From f5885f40976bc8c8cb8fa17616ccc423f6daae04 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:24 -0300 Subject: [media] au0828: no need to sleep at the IR code This sleep was doing some debouncing on the original driver. This is not needed on Linux, because the RC core and the input layer already takes care of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index fd0d3a90ce7d..39ddf3c4fdfe 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -135,8 +135,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) /* Disable IR */ au8522_rc_clear(ir, 0xe0, 1 << 4); - usleep_range(45000, 46000); - /* Enable IR */ au8522_rc_set(ir, 0xe0, 1 << 4); -- cgit v1.2.3 From ff346b0f5d86688baf7c191faf192e69cf347583 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:25 -0300 Subject: [media] au0828: add an option to disable IR via modprobe parameter The IR code increases the power consumption of the device. Allow to disable it via modprobe parameter. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 39ddf3c4fdfe..590f99d02c93 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -25,6 +25,10 @@ #include #include +static int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + #include "au0828.h" struct au0828_rc { @@ -271,7 +275,7 @@ int au0828_rc_register(struct au0828_dev *dev) int err = -ENOMEM; u16 i2c_rc_dev_addr = 0; - if (!dev->board.has_ir_i2c) + if (!dev->board.has_ir_i2c || disable_ir) return 0; i2c_rc_dev_addr = au0828_probe_i2c_ir(dev); -- cgit v1.2.3 From d84fdc774b3beea1a7c601ff6e8d22e6ac13dd01 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:26 -0300 Subject: [media] au0828: Enable IR for HVR-850 HVR-850 also has a remote. Enable it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 2c6b7da137ed..b6c9d1f466bd 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -46,6 +46,7 @@ struct au0828_board au0828_boards[] = { .name = "Hauppauge HVR850", .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, + .has_ir_i2c = 1, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, .input = { { -- cgit v1.2.3 From 2e0cc7ee75a218ad43b112164e87acb03f0fd9f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 10:46:30 -0300 Subject: [media] au0828-input: Be sure that IR is enabled at polling When the DVB code sets the frontend, it disables the IR INT, probably due to some hardware bug, as there's no code there at au8522 frontend that writes on register 0xe0. Fixing it at au8522 code is hard, as it doesn't know if the IR is enabled or disabled, and just restoring the value of register 0xe0 could cause other nasty effects. So, better to add a hack at au0828-input polling interval to enable int, if disabled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 590f99d02c93..f0c5672e5f56 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -94,14 +94,19 @@ static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val, static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value) { int rc; - char buf; + char buf, oldbuf; rc = au8522_rc_read(ir, reg, -1, &buf, 1); if (rc < 0) return rc; + oldbuf = buf; buf = (buf & ~mask) | (value & mask); + /* Nothing to do, just return */ + if (buf == oldbuf) + return 0; + return au8522_rc_write(ir, reg, buf); } @@ -126,8 +131,11 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) /* Check IR int */ rc = au8522_rc_read(ir, 0xe1, -1, buf, 1); - if (rc < 0 || !(buf[0] & (1 << 4))) + if (rc < 0 || !(buf[0] & (1 << 4))) { + /* Be sure that IR is enabled */ + au8522_rc_set(ir, 0xe0, 1 << 4); return 0; + } /* Something arrived. Get the data */ rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf)); -- cgit v1.2.3 From e9018af0b8897b02dc8e83e6cd75391afcadf894 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:07 -0300 Subject: [media] au0828: avoid race conditions at RC stop As the RC kthread can re-enable IR int, we should first cancel the kthread and then disable IR int. While here, remove a temporary debug printk. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index f0c5672e5f56..47ef07a693af 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -253,10 +253,10 @@ static void au0828_rc_stop(struct rc_dev *rc) { struct au0828_rc *ir = rc->priv; + cancel_delayed_work_sync(&ir->work); + /* Disable IR */ au8522_rc_clear(ir, 0xe0, 1 << 4); - - cancel_delayed_work_sync(&ir->work); } static int au0828_probe_i2c_ir(struct au0828_dev *dev) -- cgit v1.2.3 From 345e3bfdadf4ae12df6251d4bcb6b9fb48037690 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:08 -0300 Subject: [media] au0828: handle IR int during suspend/resume It doesn't make sense to handle an IR code given before suspending after the device resume. So, turn off IR int while suspending. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 47ef07a693af..7a5437a4d938 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -380,6 +380,9 @@ int au0828_rc_suspend(struct au0828_dev *dev) cancel_delayed_work_sync(&ir->work); + /* Disable IR */ + au8522_rc_clear(ir, 0xe0, 1 << 4); + return 0; } @@ -390,6 +393,9 @@ int au0828_rc_resume(struct au0828_dev *dev) if (!ir) return 0; + /* Enable IR */ + au8522_rc_set(ir, 0xe0, 1 << 4); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); return 0; -- cgit v1.2.3 From 917cbcde46adf3e155ec61d92f6f29a4eb3acad1 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 8 Aug 2014 21:36:18 -0300 Subject: [media] au0828: add au0828_rc_*() stubs for VIDEO_AU0828_RC disabled case Define au0828_rc_*() stubs to avoid compile errors when VIDEO_AU0828_RC is disabled and avoid the need to enclose au0828_rc_*() in ifdef CONFIG_VIDEO_AU0828_RC in .c files. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 96bec05d7dac..fd0916e20323 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -326,7 +326,14 @@ extern struct videobuf_queue_ops au0828_vbi_qops; } while (0) /* au0828-input.c */ -int au0828_rc_register(struct au0828_dev *dev); -void au0828_rc_unregister(struct au0828_dev *dev); -int au0828_rc_suspend(struct au0828_dev *dev); -int au0828_rc_resume(struct au0828_dev *dev); +#ifdef CONFIG_VIDEO_AU0828_RC +extern int au0828_rc_register(struct au0828_dev *dev); +extern void au0828_rc_unregister(struct au0828_dev *dev); +extern int au0828_rc_suspend(struct au0828_dev *dev); +extern int au0828_rc_resume(struct au0828_dev *dev); +#else +static inline int au0828_rc_register(struct au0828_dev *dev) { return 0; } +static inline void au0828_rc_unregister(struct au0828_dev *dev) { } +static inline int au0828_rc_suspend(struct au0828_dev *dev) { return 0; } +static inline int au0828_rc_resume(struct au0828_dev *dev) { return 0; } +#endif -- cgit v1.2.3 From 92143f6fb0d6655391b1b42f54ab94d3f16c00ac Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Sat, 9 Aug 2014 21:47:10 -0300 Subject: [media] au0828: remove CONFIG_VIDEO_AU0828_RC scope around au0828_rc_*() Remove CONFIG_VIDEO_AU0828_RC scope around au0828_rc_register() and au0828_rc_unregister() calls in au0828-core Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 56025e689442..b08b979bb9a7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -153,9 +153,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface) dprintk(1, "%s()\n", __func__); -#ifdef CONFIG_VIDEO_AU0828_RC au0828_rc_unregister(dev); -#endif /* Digital TV */ au0828_dvb_unregister(dev); @@ -266,10 +264,8 @@ static int au0828_usb_probe(struct usb_interface *interface, pr_err("%s() au0282_dev_register failed\n", __func__); -#ifdef CONFIG_VIDEO_AU0828_RC /* Remote controller */ au0828_rc_register(dev); -#endif /* * Store the pointer to the au0828_dev so it can be accessed in -- cgit v1.2.3 From aaeac1991b2c3dff46e0aae5e1d7c7f46ac9eddc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:11 -0300 Subject: [media] au0828: don't let the IR polling thread to run at suspend Trying to make au0828 to suspend can do very bad things, as the polling Kthread is not handled. We should disable it during suspend, only re-enabling it at resume. Still, analog and digital TV won't work, as we don't reinit the settings at resume, but at least it won't hang. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index b08b979bb9a7..3a02de142f9f 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -281,13 +281,42 @@ static int au0828_usb_probe(struct usb_interface *interface, return retval; } +static int au0828_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + if (!dev) + return 0; + + au0828_rc_suspend(dev); + + /* FIXME: should suspend also ATV/DTV */ + + return 0; +} + +static int au0828_resume(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + if (!dev) + return 0; + + au0828_rc_resume(dev); + + /* FIXME: should resume also ATV/DTV */ + + return 0; +} + static struct usb_driver au0828_usb_driver = { .name = DRIVER_NAME, .probe = au0828_usb_probe, .disconnect = au0828_usb_disconnect, .id_table = au0828_usb_id_table, - - /* FIXME: Add suspend and resume functions */ + .suspend = au0828_suspend, + .resume = au0828_resume, + .reset_resume = au0828_resume, }; static int __init au0828_init(void) -- cgit v1.2.3 From fa500461db5af83fce7b1bd45e4925efadbebd90 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:12 -0300 Subject: [media] au0828: be sure to reenable the bridge and GPIOs on resume At resume, we should restore the register contents. So, reenable the bridge and GPIO settings. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 3a02de142f9f..87340a8af7d7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -302,6 +302,12 @@ static int au0828_resume(struct usb_interface *interface) if (!dev) return 0; + /* Power Up the bridge */ + au0828_write(dev, REG_600, 1 << 4); + + /* Bring up the GPIO's and supporting devices */ + au0828_gpio_setup(dev); + au0828_rc_resume(dev); /* FIXME: should resume also ATV/DTV */ -- cgit v1.2.3 From b799de75e032c4d27788af9b4df3ab25858f87a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:13 -0300 Subject: [media] au0828: Add suspend code for DVB The scheduled work should be cancelled during suspend. At resume time, we need to set the frontend again. So, add such logic to the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 2 ++ drivers/media/usb/au0828/au0828-dvb.c | 31 ++++++++++++++++++++++++++++++- drivers/media/usb/au0828/au0828.h | 2 ++ 3 files changed, 34 insertions(+), 1 deletion(-) mode change 100644 => 100755 drivers/media/usb/au0828/au0828-dvb.c diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 87340a8af7d7..26ec50539dc4 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -290,6 +290,7 @@ static int au0828_suspend(struct usb_interface *interface, return 0; au0828_rc_suspend(dev); + au0828_dvb_suspend(dev); /* FIXME: should suspend also ATV/DTV */ @@ -309,6 +310,7 @@ static int au0828_resume(struct usb_interface *interface) au0828_gpio_setup(dev); au0828_rc_resume(dev); + au0828_dvb_resume(dev); /* FIXME: should resume also ATV/DTV */ diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c old mode 100644 new mode 100755 index d8b5d9480279..7b6e71065aa4 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -618,3 +617,33 @@ int au0828_dvb_register(struct au0828_dev *dev) return 0; } + +void au0828_dvb_suspend(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + if (dvb && dev->urb_streaming) { + cancel_work_sync(&dev->restart_streaming); + + /* Stop transport */ + mutex_lock(&dvb->lock); + stop_urb_transfer(dev); + au0828_stop_transport(dev, 1); + mutex_unlock(&dvb->lock); + } +} + +void au0828_dvb_resume(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + if (dvb && dev->urb_streaming) { + au0828_set_frontend(dvb->frontend); + + /* Start transport */ + mutex_lock(&dvb->lock); + au0828_start_transport(dev); + start_urb_transfer(dev); + mutex_unlock(&dvb->lock); + } +} diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index fd0916e20323..d32234353096 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -316,6 +316,8 @@ void au0828_analog_unregister(struct au0828_dev *dev); /* au0828-dvb.c */ extern int au0828_dvb_register(struct au0828_dev *dev); extern void au0828_dvb_unregister(struct au0828_dev *dev); +void au0828_dvb_suspend(struct au0828_dev *dev); +void au0828_dvb_resume(struct au0828_dev *dev); /* au0828-vbi.c */ extern struct videobuf_queue_ops au0828_vbi_qops; -- cgit v1.2.3 From e2147d0af0aa77c1a7b610224161993ef62e3ac1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:14 -0300 Subject: [media] au0828: properly handle stream on/off state The STREAM_ON state is used by s_format callback, but the driver never sets it. Fix it. This will also be needed in order to handle suspend/resume ops. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 98f7ea1d6d63..36ff3b496f87 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -159,6 +159,7 @@ static void au0828_irq_callback(struct urb *urb) au0828_isocdbg("urb resubmit failed (error=%i)\n", urb->status); } + dev->stream_state = STREAM_ON; } /* @@ -198,6 +199,8 @@ static void au0828_uninit_isoc(struct au0828_dev *dev) dev->isoc_ctl.urb = NULL; dev->isoc_ctl.transfer_buffer = NULL; dev->isoc_ctl.num_bufs = 0; + + dev->stream_state = STREAM_OFF; } /* -- cgit v1.2.3 From 1a1ba95e80e567176aeb2a10b2dc6d920b06a33e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:15 -0300 Subject: [media] au0828: add suspend/resume code for V4L2 No timers should be enabled during suspend. So, stop them. At resume time, we should do the proper initialization for it to keep working. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 2 ++ drivers/media/usb/au0828/au0828-video.c | 59 ++++++++++++++++++++++++++++++++- drivers/media/usb/au0828/au0828.h | 7 ++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 26ec50539dc4..5f13888d73a0 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -290,6 +290,7 @@ static int au0828_suspend(struct usb_interface *interface, return 0; au0828_rc_suspend(dev); + au0828_v4l2_suspend(dev); au0828_dvb_suspend(dev); /* FIXME: should suspend also ATV/DTV */ @@ -310,6 +311,7 @@ static int au0828_resume(struct usb_interface *interface) au0828_gpio_setup(dev); au0828_rc_resume(dev); + au0828_v4l2_resume(dev); au0828_dvb_resume(dev); /* FIXME: should resume also ATV/DTV */ diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 36ff3b496f87..574a08c7013d 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -1871,6 +1870,64 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) return rc; } +void au0828_v4l2_suspend(struct au0828_dev *dev) +{ + struct urb *urb; + int i; + + if (dev->stream_state == STREAM_ON) { + au0828_analog_stream_disable(dev); + /* stop urbs */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + } + } + } + + if (dev->vid_timeout_running) + del_timer_sync(&dev->vid_timeout); + if (dev->vbi_timeout_running) + del_timer_sync(&dev->vbi_timeout); +} + +void au0828_v4l2_resume(struct au0828_dev *dev) +{ + int i, rc; + + if (dev->stream_state == STREAM_ON) { + au0828_stream_interrupt(dev); + au0828_init_tuner(dev); + } + + if (dev->vid_timeout_running) + mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); + if (dev->vbi_timeout_running) + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + + /* If we were doing ac97 instead of i2s, it would go here...*/ + au0828_i2s_init(dev); + + au0828_analog_stream_enable(dev); + + if (!(dev->stream_state == STREAM_ON)) { + au0828_analog_stream_reset(dev); + /* submit urbs */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + au0828_isocdbg("submit of urb %i failed (error=%i)\n", + i, rc); + au0828_uninit_isoc(dev); + } + } + } +} + static struct v4l2_file_operations au0828_v4l_fops = { .owner = THIS_MODULE, .open = au0828_v4l2_open, diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index d32234353096..0d8cfe5cd264 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -311,6 +311,13 @@ int au0828_analog_register(struct au0828_dev *dev, struct usb_interface *interface); int au0828_analog_stream_disable(struct au0828_dev *d); void au0828_analog_unregister(struct au0828_dev *dev); +#ifdef CONFIG_VIDEO_AU0828_V4L2 +void au0828_v4l2_suspend(struct au0828_dev *dev); +void au0828_v4l2_resume(struct au0828_dev *dev); +#else +static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { }; +static inline void au0828_v4l2_resume(struct au0828_dev *dev) { }; +#endif /* ----------------------------------------------------------- */ /* au0828-dvb.c */ -- cgit v1.2.3 From 3d8de92e07b855d22e9807a287f80ee910331d51 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:16 -0300 Subject: [media] au0828: Remove a bad whitespace Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 7a5437a4d938..5efb83977f39 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -133,7 +133,7 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) rc = au8522_rc_read(ir, 0xe1, -1, buf, 1); if (rc < 0 || !(buf[0] & (1 << 4))) { /* Be sure that IR is enabled */ - au8522_rc_set(ir, 0xe0, 1 << 4); + au8522_rc_set(ir, 0xe0, 1 << 4); return 0; } -- cgit v1.2.3 From 83afb32aa9d8cc77049c0e4e124e3bed8b88428f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:17 -0300 Subject: [media] au0828: use pr_foo macros Instead of using printk(KERN_foo, use pr_foo() macros. No functional changes. Note: we should do the same for dprintk(), but that would require to remove the dprintk levels. So, for now, let's not touch on it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 13 ++++----- drivers/media/usb/au0828/au0828-core.c | 33 +++++++++++----------- drivers/media/usb/au0828/au0828-dvb.c | 50 +++++++++++++++------------------ drivers/media/usb/au0828/au0828-i2c.c | 15 +++++----- drivers/media/usb/au0828/au0828-input.c | 4 +-- drivers/media/usb/au0828/au0828-vbi.c | 4 +-- drivers/media/usb/au0828/au0828-video.c | 23 +++++++-------- drivers/media/usb/au0828/au0828.h | 5 ++-- 8 files changed, 72 insertions(+), 75 deletions(-) mode change 100755 => 100644 drivers/media/usb/au0828/au0828-dvb.c diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index b6c9d1f466bd..d229c6dbddb9 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -143,8 +143,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg) mdelay(10); return 0; } else { - printk(KERN_ERR - "%s(): Unknown command.\n", __func__); + pr_err("%s(): Unknown command.\n", __func__); return -EINVAL; } break; @@ -178,12 +177,12 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", __func__, tv.model); + pr_warn("%s: warning: unknown hauppauge model #%d\n", + __func__, tv.model); break; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + pr_info("%s: hauppauge eeprom: model=%d\n", __func__, tv.model); } @@ -229,7 +228,7 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "au8522", 0x8e >> 1, NULL); if (sd == NULL) - printk(KERN_ERR "analog subdev registration failed\n"); + pr_err("analog subdev registration failed\n"); } /* Setup tuners */ @@ -238,7 +237,7 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tuner", dev->board.tuner_addr, NULL); if (sd == NULL) - printk(KERN_ERR "tuner subdev registration fail\n"); + pr_err("tuner subdev registration fail\n"); tun_setup.mode_mask = mode_mask; tun_setup.type = dev->board.tuner_type; diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 5f13888d73a0..452d14249348 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -19,14 +19,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include #include #include -#include "au0828.h" - /* * 1 = General debug messages * 2 = USB handling @@ -90,7 +90,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed sending control message, error %d.\n", + pr_err("%s() Failed sending control message, error %d.\n", __func__, status); } @@ -115,7 +115,7 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", + pr_err("%s() Failed receiving control message, error %d.\n", __func__, status); } @@ -197,15 +197,14 @@ static int au0828_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(KERN_ERR "au0828: Device initialization failed.\n"); - printk(KERN_ERR "au0828: Device must be connected to a " - "high-speed USB 2.0 port.\n"); + pr_err("au0828: Device initialization failed.\n"); + pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); return -ENODEV; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); + pr_err("%s() Unable to allocate memory\n", __func__); return -ENOMEM; } @@ -273,7 +272,7 @@ static int au0828_usb_probe(struct usb_interface *interface, */ usb_set_intfdata(interface, dev); - printk(KERN_INFO "Registered device AU0828 [%s]\n", + pr_info("Registered device AU0828 [%s]\n", dev->board.name == NULL ? "Unset" : dev->board.name); mutex_unlock(&dev->lock); @@ -320,7 +319,7 @@ static int au0828_resume(struct usb_interface *interface) } static struct usb_driver au0828_usb_driver = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = au0828_usb_probe, .disconnect = au0828_usb_disconnect, .id_table = au0828_usb_id_table, @@ -334,27 +333,27 @@ static int __init au0828_init(void) int ret; if (au0828_debug & 1) - printk(KERN_INFO "%s() Debugging is enabled\n", __func__); + pr_info("%s() Debugging is enabled\n", __func__); if (au0828_debug & 2) - printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); + pr_info("%s() USB Debugging is enabled\n", __func__); if (au0828_debug & 4) - printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); + pr_info("%s() I2C Debugging is enabled\n", __func__); if (au0828_debug & 8) - printk(KERN_INFO "%s() Bridge Debugging is enabled\n", + pr_info("%s() Bridge Debugging is enabled\n", __func__); if (au0828_debug & 16) - printk(KERN_INFO "%s() IR Debugging is enabled\n", + pr_info("%s() IR Debugging is enabled\n", __func__); - printk(KERN_INFO "au0828 driver loaded\n"); + pr_info("au0828 driver loaded\n"); ret = usb_register(&au0828_usb_driver); if (ret) - printk(KERN_ERR "usb_register failed, error = %d\n", ret); + pr_err("usb_register failed, error = %d\n", ret); return ret; } diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c old mode 100755 new mode 100644 index 7b6e71065aa4..99cf83bca033 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include @@ -26,7 +28,6 @@ #include #include -#include "au0828.h" #include "au8522.h" #include "xc5000.h" #include "mxl5007t.h" @@ -126,7 +127,7 @@ static void urb_completion(struct urb *purb) } if (ptype != PIPE_BULK) { - printk(KERN_ERR "%s: Unsupported URB type %d\n", + pr_err("%s: Unsupported URB type %d\n", __func__, ptype); return; } @@ -201,8 +202,7 @@ static int start_urb_transfer(struct au0828_dev *dev) if (!purb->transfer_buffer) { usb_free_urb(purb); dev->urbs[i] = NULL; - printk(KERN_ERR - "%s: failed big buffer allocation, err = %d\n", + pr_err("%s: failed big buffer allocation, err = %d\n", __func__, ret); goto err; } @@ -223,8 +223,8 @@ static int start_urb_transfer(struct au0828_dev *dev) ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); if (ret != 0) { stop_urb_transfer(dev); - printk(KERN_ERR "%s: failed urb submission, " - "err = %d\n", __func__, ret); + pr_err("%s: failed urb submission, err = %d\n", + __func__, ret); return ret; } } @@ -392,9 +392,8 @@ static int dvb_register(struct au0828_dev *dev) if (!dev->dig_transfer_buffer[i]) { result = -ENOMEM; - printk(KERN_ERR - "%s: failed buffer allocation (errno = %d)\n", - DRIVER_NAME, result); + pr_err("failed buffer allocation (errno = %d)\n", + result); goto fail_adapter; } } @@ -403,11 +402,12 @@ static int dvb_register(struct au0828_dev *dev) INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, + result = dvb_register_adapter(&dvb->adapter, + KBUILD_MODNAME, THIS_MODULE, &dev->usbdev->dev, adapter_nr); if (result < 0) { - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d)\n", DRIVER_NAME, result); + pr_err("dvb_register_adapter failed (errno = %d)\n", + result); goto fail_adapter; } dvb->adapter.priv = dev; @@ -415,8 +415,8 @@ static int dvb_register(struct au0828_dev *dev) /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->frontend); if (result < 0) { - printk(KERN_ERR "%s: dvb_register_frontend failed " - "(errno = %d)\n", DRIVER_NAME, result); + pr_err("dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend; } @@ -435,8 +435,7 @@ static int dvb_register(struct au0828_dev *dev) dvb->demux.stop_feed = au0828_dvb_stop_feed; result = dvb_dmx_init(&dvb->demux); if (result < 0) { - printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("dvb_dmx_init failed (errno = %d)\n", result); goto fail_dmx; } @@ -445,31 +444,29 @@ static int dvb_register(struct au0828_dev *dev) dvb->dmxdev.capabilities = 0; result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { - printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); goto fail_dmxdev; } dvb->fe_hw.source = DMX_FRONTEND_0; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); + pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + result); goto fail_fe_hw; } dvb->fe_mem.source = DMX_MEMORY_FE; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); + pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + result); goto fail_fe_mem; } result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("connect_frontend failed (errno = %d)\n", result); goto fail_fe_conn; } @@ -595,12 +592,11 @@ int au0828_dvb_register(struct au0828_dev *dev) } break; default: - printk(KERN_WARNING "The frontend of your DVB/ATSC card " - "isn't supported yet\n"); + pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->frontend) { - printk(KERN_ERR "%s() Frontend initialization failed\n", + pr_err("%s() Frontend initialization failed\n", __func__); return -1; } diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c index daaeaf1b089c..ae7ac6669769 100644 --- a/drivers/media/usb/au0828/au0828-i2c.c +++ b/drivers/media/usb/au0828/au0828-i2c.c @@ -19,13 +19,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include #include #include -#include "au0828.h" #include "media/tuner.h" #include @@ -340,7 +341,7 @@ static struct i2c_algorithm au0828_i2c_algo_template = { /* ----------------------------------------------------------------------- */ static struct i2c_adapter au0828_i2c_adap_template = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .owner = THIS_MODULE, .algo = &au0828_i2c_algo_template, }; @@ -365,7 +366,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", + pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -381,7 +382,7 @@ int au0828_i2c_register(struct au0828_dev *dev) dev->i2c_adap.dev.parent = &dev->usbdev->dev; - strlcpy(dev->i2c_adap.name, DRIVER_NAME, + strlcpy(dev->i2c_adap.name, KBUILD_MODNAME, sizeof(dev->i2c_adap.name)); dev->i2c_adap.algo = &dev->i2c_algo; @@ -396,11 +397,11 @@ int au0828_i2c_register(struct au0828_dev *dev) dev->i2c_client.adapter = &dev->i2c_adap; if (0 == dev->i2c_rc) { - printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME); + pr_info("i2c bus registered\n"); if (i2c_scan) - do_i2c_scan(DRIVER_NAME, &dev->i2c_client); + do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client); } else - printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME); + pr_info("i2c bus register FAILED\n"); return dev->i2c_rc; } diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 5efb83977f39..6db1ce8e09e1 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -17,6 +17,8 @@ GNU General Public License for more details. */ +#include "au0828.h" + #include #include #include @@ -29,8 +31,6 @@ static int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -#include "au0828.h" - struct au0828_rc { struct au0828_dev *dev; struct rc_dev *rc; diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index 63f593070ee8..932d24f42b24 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -21,13 +21,13 @@ 02110-1301, USA. */ +#include "au0828.h" + #include #include #include #include -#include "au0828.h" - static unsigned int vbibufs = 5; module_param(vbibufs, int, 0644); MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 574a08c7013d..193b2e364266 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -28,6 +28,8 @@ * */ +#include "au0828.h" + #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include "au0828.h" #include "au0828-reg.h" static DEFINE_MUTEX(au0828_sysfs_lock); @@ -52,7 +53,7 @@ MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); #define au0828_isocdbg(fmt, arg...) \ do {\ if (isoc_debug) { \ - printk(KERN_INFO "au0828 %s :"fmt, \ + pr_info("au0828 %s :"fmt, \ __func__ , ##arg); \ } \ } while (0) @@ -105,12 +106,12 @@ static inline void print_err_status(struct au0828_dev *dev, static int check_dev(struct au0828_dev *dev) { if (dev->dev_state & DEV_DISCONNECTED) { - printk(KERN_INFO "v4l2 ioctl: device not present\n"); + pr_info("v4l2 ioctl: device not present\n"); return -ENODEV; } if (dev->dev_state & DEV_MISCONFIGURED) { - printk(KERN_INFO "v4l2 ioctl: device is misconfigured; " + pr_info("v4l2 ioctl: device is misconfigured; " "close and open it again\n"); return -EIO; } @@ -719,7 +720,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { rc = videobuf_iolock(vq, &buf->vb, NULL); if (rc < 0) { - printk(KERN_INFO "videobuf_iolock failed\n"); + pr_info("videobuf_iolock failed\n"); goto fail; } } @@ -732,7 +733,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, AU0828_MAX_ISO_BUFS, dev->max_pkt_size, au0828_isoc_copy); if (rc < 0) { - printk(KERN_INFO "au0828_init_isoc failed\n"); + pr_info("au0828_init_isoc failed\n"); goto fail; } } @@ -803,7 +804,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d) /* set au0828 interface0 to AS5 here again */ ret = usb_set_interface(d->usbdev, 0, 5); if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); + pr_info("Au0828 can't set alt setting to 5!\n"); return -EBUSY; } } @@ -1092,7 +1093,7 @@ static int au0828_v4l2_close(struct file *filp) USB bandwidth */ ret = usb_set_interface(dev->usbdev, 0, 0); if (ret < 0) - printk(KERN_INFO "Au0828 can't set alternate to 0!\n"); + pr_info("Au0828 can't set alternate to 0!\n"); } mutex_unlock(&dev->lock); @@ -1346,7 +1347,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return rc; if (videobuf_queue_is_busy(&fh->vb_vidq)) { - printk(KERN_INFO "%s queue busy\n", __func__); + pr_info("%s queue busy\n", __func__); rc = -EBUSY; goto out; } @@ -1999,7 +2000,7 @@ int au0828_analog_register(struct au0828_dev *dev, retval = usb_set_interface(dev->usbdev, interface->cur_altsetting->desc.bInterfaceNumber, 5); if (retval != 0) { - printk(KERN_INFO "Failure setting usb interface0 to as5\n"); + pr_info("Failure setting usb interface0 to as5\n"); return retval; } @@ -2023,7 +2024,7 @@ int au0828_analog_register(struct au0828_dev *dev, } } if (!(dev->isoc_in_endpointaddr)) { - printk(KERN_INFO "Could not locate isoc endpoint\n"); + pr_info("Could not locate isoc endpoint\n"); kfree(dev); return -ENODEV; } diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 0d8cfe5cd264..d187129b96b7 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -42,7 +44,6 @@ #include "au0828-reg.h" #include "au0828-cards.h" -#define DRIVER_NAME "au0828" #define URB_COUNT 16 #define URB_BUFSIZE (0xe522) @@ -331,7 +332,7 @@ extern struct videobuf_queue_ops au0828_vbi_qops; #define dprintk(level, fmt, arg...)\ do { if (au0828_debug & level)\ - printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ + printk(KERN_DEBUG pr_fmt(fmt), ## arg);\ } while (0) /* au0828-input.c */ -- cgit v1.2.3 From 811872404bb021b73ecb4b78de88bd2d7f26548e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:18 -0300 Subject: [media] au0828: add pr_info to track au0828 suspend/resume code Suspend/resume conditions can be very tricky. Add some info printk's to help tracking what's happening there. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 4 ++++ drivers/media/usb/au0828/au0828-dvb.c | 4 ++++ drivers/media/usb/au0828/au0828-input.c | 4 ++++ drivers/media/usb/au0828/au0828-video.c | 5 +++++ 4 files changed, 17 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 452d14249348..bc064803b6c7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -288,6 +288,8 @@ static int au0828_suspend(struct usb_interface *interface, if (!dev) return 0; + pr_info("Suspend\n"); + au0828_rc_suspend(dev); au0828_v4l2_suspend(dev); au0828_dvb_suspend(dev); @@ -303,6 +305,8 @@ static int au0828_resume(struct usb_interface *interface) if (!dev) return 0; + pr_info("Resume\n"); + /* Power Up the bridge */ au0828_write(dev, REG_600, 1 << 4); diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 99cf83bca033..ee45990c0be1 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -619,6 +619,8 @@ void au0828_dvb_suspend(struct au0828_dev *dev) struct au0828_dvb *dvb = &dev->dvb; if (dvb && dev->urb_streaming) { + pr_info("stopping DVB\n"); + cancel_work_sync(&dev->restart_streaming); /* Stop transport */ @@ -634,6 +636,8 @@ void au0828_dvb_resume(struct au0828_dev *dev) struct au0828_dvb *dvb = &dev->dvb; if (dvb && dev->urb_streaming) { + pr_info("resuming DVB\n"); + au0828_set_frontend(dvb->frontend); /* Start transport */ diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 6db1ce8e09e1..63995f97dc65 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -378,6 +378,8 @@ int au0828_rc_suspend(struct au0828_dev *dev) if (!ir) return 0; + pr_info("Stopping RC\n"); + cancel_delayed_work_sync(&ir->work); /* Disable IR */ @@ -393,6 +395,8 @@ int au0828_rc_resume(struct au0828_dev *dev) if (!ir) return 0; + pr_info("Restarting RC\n"); + /* Enable IR */ au8522_rc_set(ir, 0xe0, 1 << 4); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 193b2e364266..5f337b118bff 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1876,7 +1876,10 @@ void au0828_v4l2_suspend(struct au0828_dev *dev) struct urb *urb; int i; + pr_info("stopping V4L2\n"); + if (dev->stream_state == STREAM_ON) { + pr_info("stopping V4L2 active URBs\n"); au0828_analog_stream_disable(dev); /* stop urbs */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { @@ -1900,6 +1903,8 @@ void au0828_v4l2_resume(struct au0828_dev *dev) { int i, rc; + pr_info("restarting V4L2\n"); + if (dev->stream_state == STREAM_ON) { au0828_stream_interrupt(dev); au0828_init_tuner(dev); -- cgit v1.2.3 From 59d7889ae49f6e3e9d9cff8c0de7ad95d9ca068b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:19 -0300 Subject: [media] dvb-frontend: add core support for tuner suspend/resume While several tuners have some sort of suspend/resume implementation, this is currently mangled with an optional .sleep callback that it is also used to put the device on low power mode. Not all drivers implement it, as returning the driver from low power may require to re-load the firmware, with takes some time. Also, some drivers may delay it. So, the more coherent is to add two new optional callbacks that will let the tuners to directy implement suspend and resume callbacks if they need. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 8 ++++++-- drivers/media/dvb-core/dvb_frontend.h | 2 ++ drivers/media/v4l2-core/tuner-core.c | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index c2a6a0a85813..a5810391af61 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2550,7 +2550,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, fe->id); - if (fe->ops.tuner_ops.sleep) + if (fe->ops.tuner_ops.suspend) + ret = fe->ops.tuner_ops.suspend(fe); + else if (fe->ops.tuner_ops.sleep) ret = fe->ops.tuner_ops.sleep(fe); if (fe->ops.sleep) @@ -2572,7 +2574,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe) if (fe->ops.init) ret = fe->ops.init(fe); - if (fe->ops.tuner_ops.init) + if (fe->ops.tuner_ops.resume) + ret = fe->ops.tuner_ops.resume(fe); + else if (fe->ops.tuner_ops.init) ret = fe->ops.tuner_ops.init(fe); fe->exit = DVB_FE_NO_EXIT; diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index d398de4b6ef4..816269e5f706 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -201,6 +201,8 @@ struct dvb_tuner_ops { int (*release)(struct dvb_frontend *fe); int (*init)(struct dvb_frontend *fe); int (*sleep)(struct dvb_frontend *fe); + int (*suspend)(struct dvb_frontend *fe); + int (*resume)(struct dvb_frontend *fe); /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 06c18ba16fa0..177023200737 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1260,7 +1260,9 @@ static int tuner_suspend(struct device *dev) tuner_dbg("suspend\n"); - if (!t->standby && analog_ops->standby) + if (t->fe.ops.tuner_ops.suspend) + t->fe.ops.tuner_ops.suspend(&t->fe); + else if (!t->standby && analog_ops->standby) analog_ops->standby(&t->fe); return 0; @@ -1273,7 +1275,9 @@ static int tuner_resume(struct device *dev) tuner_dbg("resume\n"); - if (!t->standby) + if (t->fe.ops.tuner_ops.resume) + t->fe.ops.tuner_ops.resume(&t->fe); + else if (!t->standby) if (set_mode(t, t->mode) == 0) set_freq(t, 0); -- cgit v1.2.3 From 91a5307cb0b164024725d68990441553740a2149 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:20 -0300 Subject: [media] xc5000: fix xc5000 suspend After xc5000 stops working, it waits for 5 seconds, waiting for a new usage. Only after that it goes to low power mode. If a suspend event happens before that, a work queue will remain active, with causes suspend to crash. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index e135760f7d48..af137046bfe5 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1229,6 +1229,24 @@ static int xc5000_sleep(struct dvb_frontend *fe) return 0; } +static int xc5000_suspend(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + cancel_delayed_work(&priv->timer_sleep); + + ret = xc5000_tuner_reset(fe); + if (ret != 0) + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __func__); + + return 0; +} + static int xc5000_init(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1293,6 +1311,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .release = xc5000_release, .init = xc5000_init, .sleep = xc5000_sleep, + .suspend = xc5000_suspend, .set_config = xc5000_set_config, .set_params = xc5000_set_params, -- cgit v1.2.3 From 164352023104207322614deef8d03bd0d773a22a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:21 -0300 Subject: [media] au0828: move the code that sets DTV on a separate function As we'll be adding a code to resume tuner operation, we need to move the code that actually sets DTV on a separate function, to be called by the resume code. No functional changes, just code got moved. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 79 ++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index af137046bfe5..3293fd8df59b 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -59,6 +59,7 @@ struct xc5000_priv { u32 freq_hz, freq_offset; u32 bandwidth; u8 video_standard; + unsigned int mode; u8 rf_mode; u8 radio_input; @@ -712,9 +713,50 @@ static void xc_debug_dump(struct xc5000_priv *priv) } } +static int xc5000_tune_digital(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc5000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_set_tv_standard(priv, + xc5000_standard[priv->video_standard].video_mode, + xc5000_standard[priv->video_standard].audio_mode, 0); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->if_khz); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->if_khz); + return -EIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); + + if (debug) + xc_debug_dump(priv); + + priv->bandwidth = bw; + + return 0; +} + static int xc5000_set_params(struct dvb_frontend *fe) { - int ret, b; + int b; struct xc5000_priv *priv = fe->tuner_priv; u32 bw = fe->dtv_property_cache.bandwidth_hz; u32 freq = fe->dtv_property_cache.frequency; @@ -794,43 +836,12 @@ static int xc5000_set_params(struct dvb_frontend *fe) } priv->freq_hz = freq - priv->freq_offset; + priv->mode = V4L2_TUNER_DIGITAL_TV; dprintk(1, "%s() frequency=%d (compensated to %d)\n", __func__, freq, priv->freq_hz); - ret = xc_set_signal_source(priv, priv->rf_mode); - if (ret != 0) { - printk(KERN_ERR - "xc5000: xc_set_signal_source(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_set_tv_standard(priv, - xc5000_standard[priv->video_standard].video_mode, - xc5000_standard[priv->video_standard].audio_mode, 0); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->if_khz); - return -EIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); - - if (debug) - xc_debug_dump(priv); - - priv->bandwidth = bw; - - return 0; + return xc5000_tune_digital(fe); } static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) -- cgit v1.2.3 From c3d6676bbaf4666ded026b35e0f62156e59ecfc1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:22 -0300 Subject: [media] xc5000: Split config and set code for analog/radio As we need a function that reapply the last tuned radio, in order to do resume, split the code that validates and updates the internal priv struct from the ones that actually set radio and TV. A latter patch will add support for resume. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 81 ++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 3293fd8df59b..78695ed4549c 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -863,12 +863,10 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) return ret; } -static int xc5000_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static void xc5000_config_tv(struct dvb_frontend *fe, + struct analog_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; - int ret; dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", __func__, params->frequency); @@ -887,42 +885,49 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe, if (params->std & V4L2_STD_MN) { /* default to BTSC audio standard */ priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_BG) { /* default to NICAM audio standard */ priv->video_standard = BG_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_I) { /* default to NICAM audio standard */ priv->video_standard = I_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_DK) { /* default to NICAM audio standard */ priv->video_standard = DK_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_DK) { /* default to A2 DK1 audio standard */ priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_L) { priv->video_standard = L_SECAM_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_LC) { priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; + return; } +} + +static int xc5000_set_tv_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 pll_lock_status; + int ret; tune_channel: ret = xc_set_signal_source(priv, priv->rf_mode); @@ -966,12 +971,11 @@ tune_channel: return 0; } -static int xc5000_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static int xc5000_config_radio(struct dvb_frontend *fe, + struct analog_parameters *params) + { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - u8 radio_input; dprintk(1, "%s() frequency=%d (in units of khz)\n", __func__, params->frequency); @@ -981,6 +985,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } + priv->freq_hz = params->frequency * 125 / 2; + priv->rf_mode = XC_RF_MODE_AIR; + + return 0; +} + +static int xc5000_set_radio_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u8 radio_input; + if (priv->radio_input == XC5000_RADIO_FM1) radio_input = FM_RADIO_INPUT1; else if (priv->radio_input == XC5000_RADIO_FM2) @@ -993,10 +1009,6 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } - priv->freq_hz = params->frequency * 125 / 2; - - priv->rf_mode = XC_RF_MODE_AIR; - ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, xc5000_standard[radio_input].audio_mode, radio_input); @@ -1024,11 +1036,27 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return 0; } +static int xc5000_apply_params(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + switch (priv->mode) { + case V4L2_TUNER_RADIO: + return xc5000_set_radio_freq(fe); + case V4L2_TUNER_ANALOG_TV: + return xc5000_set_tv_freq(fe); + case V4L2_TUNER_DIGITAL_TV: + return xc5000_tune_digital(fe); + } + + return 0; +} + static int xc5000_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; + int ret; if (priv->i2c_props.adap == NULL) return -EINVAL; @@ -1040,18 +1068,21 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, switch (params->mode) { case V4L2_TUNER_RADIO: - ret = xc5000_set_radio_freq(fe, params); + ret = xc5000_config_radio(fe, params); + if (ret) + return ret; break; case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = xc5000_set_tv_freq(fe, params); + xc5000_config_tv(fe, params); + break; + default: break; } + priv->mode = params->mode; - return ret; + return xc5000_apply_params(fe); } - static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; -- cgit v1.2.3 From 7ab1c07614b984778a808dc22f84b682fedefea1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:23 -0300 Subject: [media] xc5000: add a resume function If a device suspends/hibertates with a station tuned, restore the tuner station at resume. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 78695ed4549c..140c537bcfcc 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1354,6 +1354,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, .suspend = xc5000_suspend, + .resume = xc5000_apply_params, .set_config = xc5000_set_config, .set_params = xc5000_set_params, -- cgit v1.2.3 From 59b94f3e74042a82fd59478d688909760b873b02 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:24 -0300 Subject: [media] xc5000: better name the functions xc5000_set_params() is a bad name for a function that handles only digital TV. Rename it to xc5000_set_digital_params(), and proper name the generic function that works for both digital and analog. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 140c537bcfcc..c1905784b08e 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -754,7 +754,7 @@ static int xc5000_tune_digital(struct dvb_frontend *fe) return 0; } -static int xc5000_set_params(struct dvb_frontend *fe) +static int xc5000_set_digital_params(struct dvb_frontend *fe) { int b; struct xc5000_priv *priv = fe->tuner_priv; @@ -1036,7 +1036,7 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe) return 0; } -static int xc5000_apply_params(struct dvb_frontend *fe) +static int xc5000_set_params(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1080,7 +1080,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, } priv->mode = params->mode; - return xc5000_apply_params(fe); + return xc5000_set_params(fe); } static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) @@ -1354,10 +1354,10 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, .suspend = xc5000_suspend, - .resume = xc5000_apply_params, + .resume = xc5000_set_params, .set_config = xc5000_set_config, - .set_params = xc5000_set_params, + .set_params = xc5000_set_digital_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, .get_if_frequency = xc5000_get_if_frequency, -- cgit v1.2.3 From bbc62a18b6d90da702d14f0d04f67de1e37ca790 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:20 -0300 Subject: [media] au0828: fix checks if dvb is initialized dev->dvb is always not null, as it is an area at the dev memory. So, checking if (dev->dvb) is always true. Instead of this stupid check, what the code wants to do is to know if the DVB was successully registered. Fix it by checking, instead, for dvb->frontend. It should also be sure that this var will be NULL if the device was not properly initialized. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index ee45990c0be1..bc4ea5397e92 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -267,7 +267,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (dvb) { + if (dvb->frontend) { mutex_lock(&dvb->lock); dvb->start_count++; dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, @@ -296,7 +296,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) dprintk(1, "%s()\n", __func__); - if (dvb) { + if (dvb->frontend) { cancel_work_sync(&dev->restart_streaming); mutex_lock(&dvb->lock); @@ -526,8 +526,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev) for (i = 0; i < URB_COUNT; i++) kfree(dev->dig_transfer_buffer[i]); } - - + dvb->frontend = NULL; } /* All the DVB attach calls go here, this function get's modified @@ -608,6 +607,7 @@ int au0828_dvb_register(struct au0828_dev *dev) if (ret < 0) { if (dvb->frontend->ops.release) dvb->frontend->ops.release(dvb->frontend); + dvb->frontend = NULL; return ret; } @@ -618,7 +618,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb && dev->urb_streaming) { + if (dvb->frontend && dev->urb_streaming) { pr_info("stopping DVB\n"); cancel_work_sync(&dev->restart_streaming); @@ -635,7 +635,7 @@ void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb && dev->urb_streaming) { + if (dvb->frontend && dev->urb_streaming) { pr_info("resuming DVB\n"); au0828_set_frontend(dvb->frontend); -- cgit v1.2.3 From 2930977ac5934540d876715fdf32b1dd6f405df5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:21 -0300 Subject: [media] au0828: Fix DVB resume when streaming When DVB is streaming and suspend is called, it will call au0828_stop_transport(), with will clean the streaming flag. Due to that, stop_urb_transfer() will be called twice, causing an oops. So, we need another flag to be used at resume, telling it to restart DVB. While here, add a logic at stop_urb_transfer() to prevent it of being called twice, and convert the usb_streaming flag into boolean. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 14 +++++++++----- drivers/media/usb/au0828/au0828.h | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index bc4ea5397e92..821f86e92cde 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -121,7 +121,7 @@ static void urb_completion(struct urb *purb) return; } - if (dev->urb_streaming == 0) { + if (!dev->urb_streaming) { dprintk(2, "%s: not streaming!\n", __func__); return; } @@ -159,7 +159,10 @@ static int stop_urb_transfer(struct au0828_dev *dev) dprintk(2, "%s()\n", __func__); - dev->urb_streaming = 0; + if (!dev->urb_streaming) + return 0; + + dev->urb_streaming = false; for (i = 0; i < URB_COUNT; i++) { if (dev->urbs[i]) { usb_kill_urb(dev->urbs[i]); @@ -229,7 +232,7 @@ static int start_urb_transfer(struct au0828_dev *dev) } } - dev->urb_streaming = 1; + dev->urb_streaming = true; ret = 0; err: @@ -323,7 +326,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) restart_streaming); struct au0828_dvb *dvb = &dev->dvb; - if (dev->urb_streaming == 0) + if (!dev->urb_streaming) return; dprintk(1, "Restarting streaming...!\n"); @@ -628,6 +631,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev) stop_urb_transfer(dev); au0828_stop_transport(dev, 1); mutex_unlock(&dvb->lock); + dev->need_urb_start = 1; } } @@ -635,7 +639,7 @@ void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb->frontend && dev->urb_streaming) { + if (dvb->frontend && dev->need_urb_start) { pr_info("resuming DVB\n"); au0828_set_frontend(dvb->frontend); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index d187129b96b7..a7cc6e397fdd 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -267,8 +267,8 @@ struct au0828_dev { char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc transfer */ - /* USB / URB Related */ - int urb_streaming; + /* DVB USB / URB Related */ + bool urb_streaming, need_urb_start; struct urb *urbs[URB_COUNT]; /* Preallocated transfer digital transfer buffers */ -- cgit v1.2.3 From 5275a3b6b01664317b1a0bdc95ad981dbbb62283 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:22 -0300 Subject: [media] xc5000: be sure that the firmware is there before set params Now that xc5000_set_params() is also called during resume, move the code that checks for the firmware to happen there. This way, the firmware will be loaded either for analog or digital TV when .resume callback is called. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index c1905784b08e..512fe508bcd2 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1040,6 +1040,11 @@ static int xc5000_set_params(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; + if (xc_load_fw_and_init_tuner(fe, 0) != 0) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + switch (priv->mode) { case V4L2_TUNER_RADIO: return xc5000_set_radio_freq(fe); @@ -1061,11 +1066,6 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, if (priv->i2c_props.adap == NULL) return -EINVAL; - if (xc_load_fw_and_init_tuner(fe, 0) != 0) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - switch (params->mode) { case V4L2_TUNER_RADIO: ret = xc5000_config_radio(fe, params); -- cgit v1.2.3 From 0fc87864879c46afe145e20ec09c9dba2328e3be Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 28 May 2014 09:38:21 -0300 Subject: [media] v4l: Add test pattern colour component controls In many cases the test pattern has selectable values for each colour component. Implement controls for raw bayer components. Additional controls should be defined for colour components that are not covered by these controls. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 34 ++++++++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 4 ++++ include/uapi/linux/v4l2-controls.h | 4 ++++ 3 files changed, 42 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9f5ffd85560b..a7eb1bde8b92 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4790,6 +4790,40 @@ interface and may change in the future. conversion. + + V4L2_CID_TEST_PATTERN_RED + integer + + + Test pattern red colour component. + + + + V4L2_CID_TEST_PATTERN_GREENR + integer + + + Test pattern green (next to red) + colour component. + + + + V4L2_CID_TEST_PATTERN_BLUE + integer + + + Test pattern blue colour component. + + + + V4L2_CID_TEST_PATTERN_GREENB + integer + + + Test pattern green (next to blue) + colour component. + + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f030d6a9e044..35d1f3d5045b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -859,6 +859,10 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_VBLANK: return "Vertical Blanking"; case V4L2_CID_HBLANK: return "Horizontal Blanking"; case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain"; + case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; + case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index e946e43fb8d5..8b930210a4b9 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -865,6 +865,10 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_VBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1) #define V4L2_CID_HBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2) #define V4L2_CID_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3) +#define V4L2_CID_TEST_PATTERN_RED (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4) +#define V4L2_CID_TEST_PATTERN_GREENR (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5) +#define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) +#define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) /* Image processing controls */ -- cgit v1.2.3 From a913d8742e275dd2d80726afac02311a0f49d161 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 26 May 2014 09:46:18 -0300 Subject: [media] smiapp: Add driver-specific test pattern menu item definitions Add numeric definitions for menu items used in the smiapp driver's test pattern menu. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/Kbuild | 1 + include/uapi/linux/smiapp.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 include/uapi/linux/smiapp.h diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 24e9033f8b3f..4ec377d103c7 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -353,6 +353,7 @@ header-y += serio.h header-y += shm.h header-y += signal.h header-y += signalfd.h +header-y += smiapp.h header-y += snmp.h header-y += sock_diag.h header-y += socket.h diff --git a/include/uapi/linux/smiapp.h b/include/uapi/linux/smiapp.h new file mode 100644 index 000000000000..53938f4412ee --- /dev/null +++ b/include/uapi/linux/smiapp.h @@ -0,0 +1,29 @@ +/* + * include/uapi/linux/smiapp.h + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2014 Intel Corporation + * Contact: Sakari Ailus + * + * 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. + * + */ + +#ifndef __UAPI_LINUX_SMIAPP_H_ +#define __UAPI_LINUX_SMIAPP_H_ + +#define V4L2_SMIAPP_TEST_PATTERN_MODE_DISABLED 0 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR 1 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS 2 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS_GREY 3 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_PN9 4 + +#endif /* __UAPI_LINUX_SMIAPP_H_ */ -- cgit v1.2.3 From 0e2a6b7f2b9303410c93fd4724f9d36ebc7be1c3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 21 May 2014 16:58:11 -0300 Subject: [media] smiapp: Implement the test pattern control Add support for the V4L2_CID_TEST_PATTERN control. When the solid colour mode is selected, additional controls become available for setting the solid four solid colour components. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 79 +++++++++++++++++++++++++++++++--- drivers/media/i2c/smiapp/smiapp.h | 4 ++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 1eaf975d3612..437ec29bdf64 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -31,8 +31,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -404,6 +405,14 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) pixel_order_str[pixel_order]); } +static const char * const smiapp_test_patterns[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) { struct smiapp_sensor *sensor = @@ -477,6 +486,35 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return smiapp_pll_update(sensor); + case V4L2_CID_TEST_PATTERN: { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_activate( + sensor->test_data[i], + ctrl->val == + V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); + + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val); + } + + case V4L2_CID_TEST_PATTERN_RED: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENR: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val); + + case V4L2_CID_TEST_PATTERN_BLUE: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENB: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + default: return -EINVAL; } @@ -489,10 +527,10 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { static int smiapp_init_controls(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int max; + unsigned int max, i; int rval; - rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7); + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); if (rval) return rval; sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; @@ -535,6 +573,20 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(smiapp_test_patterns) - 1, + 0, 0, smiapp_test_patterns); + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + sensor->test_data[i] = + v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + if (sensor->pixel_array->ctrl_handler.error) { dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", @@ -1671,17 +1723,34 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->pad == ssd->source_pad) { u32 code = fmt->format.code; int rval = __smiapp_get_format(subdev, fh, fmt); + bool range_changed = false; + unsigned int i; if (!rval && subdev == &sensor->src->sd) { const struct smiapp_csi_data_format *csi_format = smiapp_validate_csi_data_format(sensor, code); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (csi_format->width != + sensor->csi_format->width) + range_changed = true; + sensor->csi_format = csi_format; + } + fmt->format.code = csi_format->code; } mutex_unlock(&sensor->mutex); - return rval; + if (rval || !range_changed) + return rval; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_modify_range( + sensor->test_data[i], + 0, (1 << sensor->csi_format->width) - 1, 1, 0); + + return 0; } /* Sink pad. Width and height are changeable here. */ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 7cc5aae662fd..874b49ffd88f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -54,6 +54,8 @@ (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ + (clk) / 1000 - 1) / ((clk) / 1000)) +#define SMIAPP_COLOUR_COMPONENTS 4 + #include "smiapp-limits.h" struct smiapp_quirk; @@ -241,6 +243,8 @@ struct smiapp_sensor { /* src controls */ struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate_csi; + /* test pattern colour components */ + struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS]; }; #define to_smiapp_subdev(_sd) \ -- cgit v1.2.3 From 24acf8b211e25414cb288305292a1fda136c0bd8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 11:36:23 -0300 Subject: [media] v4l: subdev: Extend default link validation to cover field order The field order must match between the source and sink pads, or the sink pad field order must be NONE. This allows connecting an interlaced source to a bridge that has no hardware support for interlaced formats. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index b4d235c13fbf..543631c3557a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -501,11 +501,20 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt) { + /* The width, height and code must match. */ if (source_fmt->format.width != sink_fmt->format.width || source_fmt->format.height != sink_fmt->format.height || source_fmt->format.code != sink_fmt->format.code) return -EINVAL; + /* The field order must match, or the sink field order must be NONE + * to support interlaced hardware connected to bridges that support + * progressive formats only. + */ + if (source_fmt->format.field != sink_fmt->format.field && + sink_fmt->format.field != V4L2_FIELD_NONE) + return -EINVAL; + return 0; } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); -- cgit v1.2.3 From eb228e897c902a65f6da536331f7d058fde1ea73 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 May 2014 18:21:13 -0300 Subject: [media] omap3isp: Don't ignore subdev streamoff failures Record the value returned by subdevs from s_stream(0) and handle stop failures when an error occurs. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 2c7aa6720569..7b10c461a497 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -999,16 +999,14 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) video, s_stream, 0); } - v4l2_subdev_call(subdev, video, s_stream, 0); + ret = v4l2_subdev_call(subdev, video, s_stream, 0); if (subdev == &isp->isp_res.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer); + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer); else if (subdev == &isp->isp_prev.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview); + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_preview); else if (subdev == &isp->isp_ccdc.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); - else - ret = 0; + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); /* Handle stop failures. An entity that fails to stop can * usually just be restarted. Flag the stop failure nonetheless -- cgit v1.2.3 From 9884a955a9da8488a88672a3eff40309bbd7f74f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 18:17:55 -0300 Subject: [media] omap3isp: Remove boilerplate disclaimer and FSF address We don't want to modify all source files the day the FSF moves. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/cfa_coef_table.h | 10 ---------- drivers/media/platform/omap3isp/gamma_table.h | 10 ---------- drivers/media/platform/omap3isp/isp.c | 10 ---------- drivers/media/platform/omap3isp/isp.h | 10 ---------- drivers/media/platform/omap3isp/ispccdc.c | 10 ---------- drivers/media/platform/omap3isp/ispccdc.h | 10 ---------- drivers/media/platform/omap3isp/ispccp2.c | 10 ---------- drivers/media/platform/omap3isp/ispccp2.h | 10 ---------- drivers/media/platform/omap3isp/ispcsi2.c | 10 ---------- drivers/media/platform/omap3isp/ispcsi2.h | 10 ---------- drivers/media/platform/omap3isp/ispcsiphy.c | 10 ---------- drivers/media/platform/omap3isp/ispcsiphy.h | 10 ---------- drivers/media/platform/omap3isp/isph3a.h | 10 ---------- drivers/media/platform/omap3isp/isph3a_aewb.c | 10 ---------- drivers/media/platform/omap3isp/isph3a_af.c | 10 ---------- drivers/media/platform/omap3isp/isphist.c | 10 ---------- drivers/media/platform/omap3isp/isphist.h | 10 ---------- drivers/media/platform/omap3isp/isppreview.c | 10 ---------- drivers/media/platform/omap3isp/isppreview.h | 10 ---------- drivers/media/platform/omap3isp/ispreg.h | 10 ---------- drivers/media/platform/omap3isp/ispresizer.c | 10 ---------- drivers/media/platform/omap3isp/ispresizer.h | 10 ---------- drivers/media/platform/omap3isp/ispstat.c | 10 ---------- drivers/media/platform/omap3isp/ispstat.h | 10 ---------- drivers/media/platform/omap3isp/ispvideo.c | 10 ---------- drivers/media/platform/omap3isp/ispvideo.h | 10 ---------- drivers/media/platform/omap3isp/luma_enhance_table.h | 10 ---------- drivers/media/platform/omap3isp/noise_filter_table.h | 10 ---------- 28 files changed, 280 deletions(-) diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h index c84df0706f3e..e75b0eb2519b 100644 --- a/drivers/media/platform/omap3isp/cfa_coef_table.h +++ b/drivers/media/platform/omap3isp/cfa_coef_table.h @@ -11,16 +11,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ { 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h index 78deebf7d965..3b507078016d 100644 --- a/drivers/media/platform/omap3isp/gamma_table.h +++ b/drivers/media/platform/omap3isp/gamma_table.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 7b10c461a497..72265e58ca60 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -40,16 +40,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 2c314eea1252..cfdfc8714b6b 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_CORE_H diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 9f727d20f06d..64092923feac 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index f65061602c71..dd999be7f82e 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_CCDC_H diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index f3801db9095c..9cb49b3c04bd 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h index 76d65f4576ef..4662bffa79e3 100644 --- a/drivers/media/platform/omap3isp/ispccp2.h +++ b/drivers/media/platform/omap3isp/ispccp2.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_CCP2_H diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 5a2e47e58b84..6530b255f103 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include #include diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h index c57729b7e86e..453ed62fe394 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.h +++ b/drivers/media/platform/omap3isp/ispcsi2.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_CSI2_H diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index c09de32f986a..e033f2237a72 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index 14551fd77697..e17c88beab92 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_CSI_PHY_H diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h index fb09fd4ca755..e5b28d0f3b0f 100644 --- a/drivers/media/platform/omap3isp/isph3a.h +++ b/drivers/media/platform/omap3isp/isph3a.h @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_H3A_H diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index d6811ce263eb..b208c5417146 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 6fc960cd30f5..8a83e195f3e3 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ /* Linux specific include files */ diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index 06a5f8164eaa..ce822c34c843 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h index 0b2a38ec94c4..3b5415517dcd 100644 --- a/drivers/media/platform/omap3isp/isphist.h +++ b/drivers/media/platform/omap3isp/isphist.h @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_HIST_H diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 720809b07e75..605f57ef0a49 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h index f66923407f8c..16fdc03a3d43 100644 --- a/drivers/media/platform/omap3isp/isppreview.h +++ b/drivers/media/platform/omap3isp/isppreview.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_PREVIEW_H diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index b7d90e6fb01d..f37a8df23cf6 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_REG_H diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 6f077c2377db..93104b0957b3 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 9b01e9047c15..494f5a2fd4bb 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_RESIZER_H diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index e6cbc1eaf4ca..a94e8340508f 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index 58d6ac7cb664..b32b29677e2c 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -13,16 +13,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_STAT_H diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index e36bac26476c..04d45e70d3be 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -11,16 +11,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #include diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 7d2e82122ecd..a76124cd6431 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -11,16 +11,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef OMAP3_ISP_VIDEO_H diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h index 098b45e2280f..81c5b1566469 100644 --- a/drivers/media/platform/omap3isp/luma_enhance_table.h +++ b/drivers/media/platform/omap3isp/luma_enhance_table.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h index d50451a4a242..5073f9847937 100644 --- a/drivers/media/platform/omap3isp/noise_filter_table.h +++ b/drivers/media/platform/omap3isp/noise_filter_table.h @@ -12,16 +12,6 @@ * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -- cgit v1.2.3 From 25c5cc9194f241d9180b4ca76a1845efd0a02769 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 10:33:15 -0300 Subject: [media] omap3isp: Move non-critical code out of the mutex-protected section The isp_video_pix_to_mbus() and isp_video_mbus_to_pix() calls in isp_video_set_format() only access static fields of the isp_video structure. They don't need to be protected by a mutex. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 04d45e70d3be..2876f34b84c0 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -631,17 +631,16 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; - mutex_lock(&video->mutex); - /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. */ isp_video_pix_to_mbus(&format->fmt.pix, &fmt); isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix); + mutex_lock(&video->mutex); vfh->format = *format; - mutex_unlock(&video->mutex); + return 0; } -- cgit v1.2.3 From 48a8a0cb764c25939788a476e7f1b1695c337835 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 10:49:58 -0300 Subject: [media] omap3isp: Default to progressive field order when setting the format If the requested field order is not supported default to progressive as we can't guess how the user will configure the pipeline later on. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 2876f34b84c0..2fe1c463232d 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -631,6 +631,15 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; + /* Default to the progressive field order if the requested value is not + * supported (or set to ANY). The only supported orders are progressive + * (available on all video nodes) and alternate (available on capture + * nodes only). + */ + if (format->fmt.pix.field != V4L2_FIELD_ALTERNATE || + video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + format->fmt.pix.field = V4L2_FIELD_NONE; + /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. */ -- cgit v1.2.3 From f7abbe989f7aa5e1d65fc7f171b8c144f4382045 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 12:14:42 -0300 Subject: [media] omap3isp: video: Validate the video node field order The field order requested on the video node must match the field order at the connected subdevice source pad. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 2fe1c463232d..756c1628ef86 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -309,10 +309,11 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) vfh->format.fmt.pix.height != format.fmt.pix.height || vfh->format.fmt.pix.width != format.fmt.pix.width || vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline || - vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage) + vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage || + vfh->format.fmt.pix.field != format.fmt.pix.field) return -EINVAL; - return ret; + return 0; } /* ----------------------------------------------------------------------------- -- cgit v1.2.3 From 2e8f01725e332c8998b87a6fe09cfc3b105eb643 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 15:05:51 -0300 Subject: [media] omap3isp: ccdc: Simplify the configuration function Assign the format variable to the sink pad format earlier and use it instead of accessing the sink pad format directly from the ISP structure. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 64092923feac..8fbba95115ad 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1114,6 +1114,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + /* CCDC_PAD_SINK */ + format = &ccdc->formats[CCDC_PAD_SINK]; + /* Compute the lane shifter shift value and enable the bridge when the * input format is YUV. */ @@ -1124,8 +1127,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) depth_in = fmt_info->width; } - fmt_info = omap3isp_video_format_info - (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + fmt_info = omap3isp_video_format_info(format->code); depth_out = fmt_info->width; shift = depth_in - depth_out; @@ -1157,9 +1159,6 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) else syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; - /* CCDC_PAD_SINK */ - format = &ccdc->formats[CCDC_PAD_SINK]; - /* Mosaic filter */ switch (format->code) { case V4L2_MBUS_FMT_SRGGB10_1X10: -- cgit v1.2.3 From 0a7b1a01037e0d43e1b85134be4217c7831f57d6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 21:46:33 -0300 Subject: [media] omap3isp: ccdc: Simplify the ccdc_isr_buffer() function Instead of using goto statements to a single line return, return the correct value immediately. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 8fbba95115ad..76d4fd73f5e8 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1480,7 +1480,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; - int restart = 0; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1489,30 +1488,27 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) * would thus not be enough, we need to handle the situation explicitly. */ if (list_empty(&ccdc->video_out.dmaqueue)) - goto done; + return 0; /* We're in continuous mode, and memory writes were disabled due to a * buffer underrun. Reenable them now that we have a buffer. The buffer * address has been set in ccdc_video_queue. */ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) { - restart = 1; ccdc->underrun = 0; - goto done; + return 1; } if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; omap3isp_pipeline_cancel_stream(pipe); - goto done; + return 0; } buffer = omap3isp_video_buffer_next(&ccdc->video_out); - if (buffer != NULL) { + if (buffer != NULL) ccdc_set_outaddr(ccdc, buffer->dma); - restart = 1; - } pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; @@ -1521,8 +1517,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); -done: - return restart; + return buffer != NULL; } /* -- cgit v1.2.3 From 9a36d8ed33c481a99f69f8a2eeb22e3c7750e522 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 16:37:38 -0300 Subject: [media] omap3isp: ccdc: Add basic support for interlaced video When the CCDC input is interlaced enable the alternate field order on the CCDC output video node. The field signal polarity is specified through platform data. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 21 ++++++++++++++++++++- drivers/media/platform/omap3isp/ispvideo.c | 6 ++++++ drivers/media/platform/omap3isp/ispvideo.h | 2 ++ include/media/omap3isp.h | 3 +++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 76d4fd73f5e8..49d7256a7de3 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1001,6 +1001,9 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (pdata && pdata->vs_pol) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; + if (pdata && pdata->fld_pol) + syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; + isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The @@ -1140,6 +1143,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge); + /* Configure the sync interface. */ ccdc_config_sync_if(ccdc, pdata, depth_out); syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -1499,6 +1503,17 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } + /* When capturing fields in alternate order read the current field + * identifier and store it in the pipeline. + */ + if (ccdc->formats[CCDC_PAD_SOURCE_OF].field == V4L2_FIELD_ALTERNATE) { + u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_SYN_MODE); + + pipe->field = syn_mode & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + } + if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; @@ -1830,6 +1845,11 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, /* Clamp the input size. */ fmt->width = clamp_t(u32, width, 32, 4096); fmt->height = clamp_t(u32, height, 32, 4096); + + /* Default to progressive field order. */ + if (fmt->field == V4L2_FIELD_ANY) + fmt->field = V4L2_FIELD_NONE; + break; case CCDC_PAD_SOURCE_OF: @@ -1885,7 +1905,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * stored on 2 bytes. */ fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; } /* diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 756c1628ef86..c38f1d4cc538 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -482,6 +482,11 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) else buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number); + if (pipe->field != V4L2_FIELD_NONE) + buf->vb.v4l2_buf.sequence /= 2; + + buf->vb.v4l2_buf.field = pipe->field; + /* Report pipeline errors to userspace on the capture device side. */ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { state = VB2_BUF_STATE_ERROR; @@ -1038,6 +1043,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) video->queue = &vfh->queue; INIT_LIST_HEAD(&video->dmaqueue); atomic_set(&pipe->frame_number, -1); + pipe->field = vfh->format.fmt.pix.field; mutex_lock(&video->queue_lock); ret = vb2_streamon(&vfh->queue, type); diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index a76124cd6431..0b7efedc3da9 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -78,6 +78,7 @@ enum isp_pipeline_state { /* * struct isp_pipeline - An ISP hardware pipeline + * @field: The field being processed by the pipeline * @error: A hardware error occurred during capture * @entities: Bitmask of entities in the pipeline (indexed by entity ID) */ @@ -91,6 +92,7 @@ struct isp_pipeline { u32 entities; unsigned long l3_ick; unsigned int max_rate; + enum v4l2_field field; atomic_t frame_number; bool do_propagation; /* of frame number */ bool error; diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index c9d06d9f7e6e..398279dd1922 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -57,6 +57,8 @@ enum { * 0 - Active high, 1 - Active low * @vs_pol: Vertical synchronization polarity * 0 - Active high, 1 - Active low + * @fld_pol: Field signal polarity + * 0 - Positive, 1 - Negative * @data_pol: Data polarity * 0 - Normal, 1 - One's complement */ @@ -65,6 +67,7 @@ struct isp_parallel_platform_data { unsigned int clk_pol:1; unsigned int hs_pol:1; unsigned int vs_pol:1; + unsigned int fld_pol:1; unsigned int data_pol:1; }; -- cgit v1.2.3 From bcb4e0efd1380d93866df51ec5d8dfaa026537ad Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 19:40:04 -0300 Subject: [media] omap3isp: ccdc: Support the interlaced field orders at the CCDC output The CCDC can interleave fields into a single buffer when writing to memory. Support it. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 132 +++++++++++++++++++---------- drivers/media/platform/omap3isp/ispreg.h | 10 +-- drivers/media/platform/omap3isp/ispvideo.c | 40 +++++++-- 3 files changed, 122 insertions(+), 60 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 49d7256a7de3..8d1861d948d0 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -863,52 +863,51 @@ static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) /* * ccdc_config_outlineoffset - Configure memory saving output line offset * @ccdc: Pointer to ISP CCDC device. - * @offset: Address offset to start a new line. Must be twice the - * Output width and aligned on 32 byte boundary - * @oddeven: Specifies the odd/even line pattern to be chosen to store the - * output. - * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines. + * @bpl: Number of bytes per line when stored in memory. + * @field: Field order when storing interlaced formats in memory. * - * - Configures the output line offset when stored in memory - * - Sets the odd/even line pattern to store the output - * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4)) - * - Configures the number of even and odd line fields in case of rearranging - * the lines. + * Configure the offsets for the line output control: + * + * - The horizontal line offset is defined as the number of bytes between the + * start of two consecutive lines in memory. Set it to the given bytes per + * line value. + * + * - The field offset value is defined as the number of lines to offset the + * start of the field identified by FID = 1. Set it to one. + * + * - The line offset values are defined as the number of lines (as defined by + * the horizontal line offset) between the start of two consecutive lines for + * all combinations of odd/even lines in odd/even fields. When interleaving + * fields set them all to two lines, and to one line otherwise. */ static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc, - u32 offset, u8 oddeven, u8 numlines) + unsigned int bpl, + enum v4l2_field field) { struct isp_device *isp = to_isp_device(ccdc); + u32 sdofst = 0; - isp_reg_writel(isp, offset & 0xffff, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF); - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FINV); + isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_HSIZE_OFF); - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FOFST_4L); - - switch (oddeven) { - case EVENEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT); - break; - case ODDEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT); - break; - case EVENODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT); - break; - case ODDODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT); + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + /* When interleaving fields in memory offset field one by one + * line and set the line offset to two lines. + */ + sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST1_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST2_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST3_SHIFT); break; + default: + /* In all other cases set the line offsets to one line. */ break; } + + isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST); } /* @@ -1204,7 +1203,17 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) << ISPCCDC_VERT_LINES_NLV_SHIFT, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); - ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0); + ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, + format->field); + + /* When interleaving fields enable processing of the field input signal. + * This will cause the line output control module to apply the field + * offset to field 1. + */ + if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE && + (format->field == V4L2_FIELD_INTERLACED_TB || + format->field == V4L2_FIELD_INTERLACED_BT)) + syn_mode |= ISPCCDC_SYN_MODE_FLDMODE; /* The CCDC outputs data in UYVY order by default. Swap bytes to get * YUYV. @@ -1484,6 +1493,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; + enum v4l2_field field; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1503,17 +1513,12 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } - /* When capturing fields in alternate order read the current field - * identifier and store it in the pipeline. - */ - if (ccdc->formats[CCDC_PAD_SOURCE_OF].field == V4L2_FIELD_ALTERNATE) { - u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_SYN_MODE); - - pipe->field = syn_mode & ISPCCDC_SYN_MODE_FLDSTAT - ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; - } + /* Read the current field identifier. */ + field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) + & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + /* Wait for the CCDC to become idle. */ if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; @@ -1521,6 +1526,28 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 0; } + switch (ccdc->formats[CCDC_PAD_SOURCE_OF].field) { + case V4L2_FIELD_ALTERNATE: + /* When capturing fields in alternate order store the current + * field identifier in the pipeline. + */ + pipe->field = field; + break; + + case V4L2_FIELD_INTERLACED_TB: + /* When interleaving fields only complete the buffer after + * capturing the second field. + */ + if (field == V4L2_FIELD_TOP) + return 1; + break; + + case V4L2_FIELD_INTERLACED_BT: + if (field == V4L2_FIELD_BOTTOM) + return 1; + break; + } + buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) ccdc_set_outaddr(ccdc, buffer->dma); @@ -1829,6 +1856,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, unsigned int width = fmt->width; unsigned int height = fmt->height; struct v4l2_rect *crop; + enum v4l2_field field; unsigned int i; switch (pad) { @@ -1854,6 +1882,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, case CCDC_PAD_SOURCE_OF: pixelcode = fmt->code; + field = fmt->field; *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); /* YUV formats are converted from 2X8 to 1X16 by the bridge and @@ -1878,6 +1907,17 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, crop = __ccdc_get_crop(ccdc, fh, which); fmt->width = crop->width; fmt->height = crop->height; + + /* When input format is interlaced with alternating fields the + * CCDC can interleave the fields. + */ + if (fmt->field == V4L2_FIELD_ALTERNATE && + (field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT)) { + fmt->field = field; + fmt->height *= 2; + } + break; case CCDC_PAD_SOURCE_VP: diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index f37a8df23cf6..b5ea8da0b904 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -730,17 +730,13 @@ #define ISPCCDC_HSIZE_OFF_SHIFT 0 -#define ISPCCDC_SDOFST_FINV (1 << 14) -#define ISPCCDC_SDOFST_FOFST_1L 0 -#define ISPCCDC_SDOFST_FOFST_4L (3 << 12) +#define ISPCCDC_SDOFST_FIINV (1 << 14) +#define ISPCCDC_SDOFST_FOFST_SHIFT 12 +#define ISPCCDC_SDOFST_FOFST_MASK (3 << 12) #define ISPCCDC_SDOFST_LOFST3_SHIFT 0 #define ISPCCDC_SDOFST_LOFST2_SHIFT 3 #define ISPCCDC_SDOFST_LOFST1_SHIFT 6 #define ISPCCDC_SDOFST_LOFST0_SHIFT 9 -#define EVENEVEN 1 -#define ODDEVEN 2 -#define EVENODD 3 -#define ODDODD 4 #define ISPCCDC_CLAMP_OBGAIN_SHIFT 0 #define ISPCCDC_CLAMP_OBST_SHIFT 10 diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index c38f1d4cc538..bc38c88c7bd9 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -637,14 +637,40 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; - /* Default to the progressive field order if the requested value is not - * supported (or set to ANY). The only supported orders are progressive - * (available on all video nodes) and alternate (available on capture - * nodes only). - */ - if (format->fmt.pix.field != V4L2_FIELD_ALTERNATE || - video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + /* Replace unsupported field orders with sane defaults. */ + switch (format->fmt.pix.field) { + case V4L2_FIELD_NONE: + /* Progressive is supported everywhere. */ + break; + case V4L2_FIELD_ALTERNATE: + /* ALTERNATE is not supported on output nodes. */ + if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + format->fmt.pix.field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_INTERLACED: + /* The ISP has no concept of video standard, select the + * top-bottom order when the unqualified interlaced order is + * requested. + */ + format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB; + /* Fall-through */ + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + /* Interlaced orders are only supported at the CCDC output. */ + if (video != &video->isp->isp_ccdc.video_out) + format->fmt.pix.field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + default: + /* All other field orders are currently unsupported, default to + * progressive. + */ format->fmt.pix.field = V4L2_FIELD_NONE; + break; + } /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. -- cgit v1.2.3 From 9de7af4d5bbff7998c09e854b2999359ac1b2721 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 May 2014 14:18:53 -0300 Subject: [media] omap3isp: ccdc: Add support for BT.656 YUV format at the CCDC input Query the CCDC input media bus type from the subdev connected to the CCDC sink pad and configure the CCDC accordingly to support BT.656 synchronization. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 94 +++++++++++++++++++++++++------ drivers/media/platform/omap3isp/ispccdc.h | 2 + 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 8d1861d948d0..150bbf070bf2 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -970,10 +970,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 || format->code == V4L2_MBUS_FMT_UYVY8_2X8) { - /* The bridge is enabled for YUV8 formats. Configure the input - * mode accordingly. + /* According to the OMAP3 TRM the input mode only affects SYNC + * mode, enabling BT.656 mode should take precedence. However, + * in practice setting the input mode to YCbCr data on 8 bits + * seems to be required in BT.656 mode. In SYNC mode set it to + * YCbCr on 16 bits as the bridge is enabled in that case. */ - syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; + if (ccdc->bt656) + syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8; + else + syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; } switch (data_size) { @@ -997,7 +1003,10 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (pdata && pdata->hs_pol) syn_mode |= ISPCCDC_SYN_MODE_HDPOL; - if (pdata && pdata->vs_pol) + /* The polarity of the vertical sync signal output by the BT.656 + * decoder is not documented and seems to be active low. + */ + if ((pdata && pdata->vs_pol) || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; if (pdata && pdata->fld_pol) @@ -1015,8 +1024,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_Y8POS); - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, - ISPCCDC_REC656IF_R656ON); + /* Enable or disable BT.656 mode, including error correction for the + * synchronization codes. + */ + if (ccdc->bt656) + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, + ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, + ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH); + } /* CCDC formats descriptions */ @@ -1107,20 +1124,32 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) unsigned long flags; unsigned int bridge; unsigned int shift; + unsigned int nph; + unsigned int sph; u32 syn_mode; u32 ccdc_pattern; + ccdc->bt656 = false; + pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - if (ccdc->input == CCDC_INPUT_PARALLEL) + if (ccdc->input == CCDC_INPUT_PARALLEL) { + struct v4l2_mbus_config cfg; + int ret; + + ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg); + if (!ret) + ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; + pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + } /* CCDC_PAD_SINK */ format = &ccdc->formats[CCDC_PAD_SINK]; /* Compute the lane shifter shift value and enable the bridge when the - * input format is YUV. + * input format is a non-BT.656 YUV variant. */ fmt_src.pad = pad->index; fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -1133,7 +1162,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) depth_out = fmt_info->width; shift = depth_in - depth_out; - if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) + if (ccdc->bt656) + bridge = ISPCTRL_PAR_BRIDGE_DISABLE; + else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) bridge = ISPCTRL_PAR_BRIDGE_LENDIAN; else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8) bridge = ISPCTRL_PAR_BRIDGE_BENDIAN; @@ -1194,10 +1225,24 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; crop = &ccdc->crop; - isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) | - ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), + /* The horizontal coordinates are expressed in pixel clock cycles. We + * need two cycles per pixel in BT.656 mode, and one cycle per pixel in + * SYNC mode regardless of the format as the bridge is enabled for YUV + * formats in that case. + */ + if (ccdc->bt656) { + sph = crop->left * 2; + nph = crop->width * 2 - 1; + } else { + sph = crop->left; + nph = crop->width - 1; + } + + isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) | + (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); - isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT, + isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) | + (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); isp_reg_writel(isp, (crop->height - 1) << ISPCCDC_VERT_LINES_NLV_SHIFT, @@ -1225,8 +1270,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_BSWD); - /* Use PACK8 mode for 1byte per pixel formats. */ - if (omap3isp_video_format_info(format->code)->width <= 8) + /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode + * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad + * for simplicity. + */ + if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_PACK8; else syn_mode &= ~ISPCCDC_SYN_MODE_PACK8; @@ -1598,6 +1646,16 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; + /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus + * need to increment the frame counter here. + */ + if (ccdc->bt656) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + + atomic_inc(&pipe->frame_number); + } + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* @@ -1885,8 +1943,12 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, field = fmt->field; *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); - /* YUV formats are converted from 2X8 to 1X16 by the bridge and - * can be byte-swapped. + /* In SYNC mode the bridge converts YUV formats from 2X8 to + * 1X16. In BT.656 no such conversion occurs. As we don't know + * at this point whether the source will use SYNC or BT.656 mode + * let's pretend the conversion always occurs. The CCDC will be + * configured to pack bytes in BT.656, hiding the inaccuracy. + * In all cases bytes can be swapped. */ if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 || fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) { diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index dd999be7f82e..c325b8901159 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -113,6 +113,7 @@ struct ispccdc_lsc { * @lsc: Lens shading compensation configuration * @update: Bitmask of controls to update during the next interrupt * @shadow_update: Controls update in progress by userspace + * @bt656: Whether the input interface uses BT.656 synchronization * @underrun: A buffer underrun occurred and a new buffer has been queued * @state: Streaming state * @lock: Serializes shadow_update with interrupt handler @@ -141,6 +142,7 @@ struct isp_ccdc_device { unsigned int update; unsigned int shadow_update; + bool bt656; unsigned int underrun:1; enum isp_pipeline_stream_state state; spinlock_t lock; -- cgit v1.2.3 From aec2de0e93e34e27ef60e7a8f48bc68ec4b4fcbb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 11:51:34 -0300 Subject: [media] omap3isp: ccdc: Disable the video port when unused The video port doesn't support YUV formats. Disable it when the CCDC sink pad format is set to YUV instead of leaving it enabled and relying on downstream modules not to process data they receive from the video port. Experiments showed that this fixes some of the CCDC failures to stop, especially in BT.656 mode. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 70 +++++++++++++------------------ 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 150bbf070bf2..ecc37f2d6a90 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -808,29 +808,48 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); const struct isp_format_info *info; + struct v4l2_mbus_framefmt *format; unsigned long l3_ick = pipe->l3_ick; unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8; unsigned int div = 0; - u32 fmtcfg_vp; + u32 fmtcfg = ISPCCDC_FMTCFG_VPEN; + + format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; + + if (!format->code) { + /* Disable the video port when the input format isn't supported. + * This is indicated by a pixel code set to 0. + */ + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); + return; + } + + isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | + (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); + isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | + ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); - fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG) - & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK); + isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | + (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code); switch (info->width) { case 8: case 10: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0; break; case 11: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1; break; case 12: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2; break; case 13: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3; break; } @@ -840,24 +859,9 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc) div = l3_ick / pipe->external_rate; div = clamp(div, 2U, max_div); - fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; + fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; - isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); -} - -/* - * ccdc_enable_vp - Enable Video Port. - * @ccdc: Pointer to ISP CCDC device. - * @enable: 0 Disables VP, 1 Enables VP - * - * This is needed for outputting image to Preview, H3A and HIST ISP submodules. - */ -static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG, - ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0); + isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); } /* @@ -1282,18 +1286,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); /* CCDC_PAD_SOURCE_VP */ - format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; - - isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | - (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); - isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | - ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); - - isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | - (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); + ccdc_config_vp(ccdc); /* Lens shading correction. */ spin_lock_irqsave(&ccdc->lsc.req_lock, flags); @@ -1837,11 +1830,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) ccdc_configure(ccdc); - /* TODO: Don't configure the video port if all of its output - * links are inactive. - */ - ccdc_config_vp(ccdc); - ccdc_enable_vp(ccdc, 1); ccdc_print_status(ccdc); } -- cgit v1.2.3 From 93d7badf1b929120cbc886f3dfec3ca55549d086 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 7 Jun 2014 20:57:07 -0300 Subject: [media] omap3isp: ccdc: Only complete buffer when all fields are captured Checking that the captured field corresponds to the last required field depending on the requested field order before completing the buffer isn't enough. When the first field at stream start corresponds to the last required field, this would result in returning an interlaced buffer containing a single field. Fix this by keeping track of the fields captured in the buffer, and make sure that both fields are present for alternate field orders. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 78 ++++++++++++++++++++----------- drivers/media/platform/omap3isp/ispccdc.h | 7 +++ 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ecc37f2d6a90..56c3129c3dcd 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1134,6 +1134,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) u32 ccdc_pattern; ccdc->bt656 = false; + ccdc->fields = 0; pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); @@ -1529,12 +1530,59 @@ done: spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); } +/* + * Check whether the CCDC has captured all fields necessary to complete the + * buffer. + */ +static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct isp_device *isp = to_isp_device(ccdc); + enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field; + enum v4l2_field field; + + /* When the input is progressive fields don't matter. */ + if (of_field == V4L2_FIELD_NONE) + return true; + + /* Read the current field identifier. */ + field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) + & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + + /* When capturing fields in alternate order just store the current field + * identifier in the pipeline. + */ + if (of_field == V4L2_FIELD_ALTERNATE) { + pipe->field = field; + return true; + } + + /* The format is interlaced. Make sure we've captured both fields. */ + ccdc->fields |= field == V4L2_FIELD_BOTTOM + ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP; + + if (ccdc->fields != CCDC_FIELD_BOTH) + return false; + + /* Verify that the field just captured corresponds to the last field + * needed based on the desired field order. + */ + if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) || + (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM)) + return false; + + /* The buffer can be completed, reset the fields for the next buffer. */ + ccdc->fields = 0; + + return true; +} + static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) { struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; - enum v4l2_field field; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1554,11 +1602,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } - /* Read the current field identifier. */ - field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) - & ISPCCDC_SYN_MODE_FLDSTAT - ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; - /* Wait for the CCDC to become idle. */ if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); @@ -1567,27 +1610,8 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 0; } - switch (ccdc->formats[CCDC_PAD_SOURCE_OF].field) { - case V4L2_FIELD_ALTERNATE: - /* When capturing fields in alternate order store the current - * field identifier in the pipeline. - */ - pipe->field = field; - break; - - case V4L2_FIELD_INTERLACED_TB: - /* When interleaving fields only complete the buffer after - * capturing the second field. - */ - if (field == V4L2_FIELD_TOP) - return 1; - break; - - case V4L2_FIELD_INTERLACED_BT: - if (field == V4L2_FIELD_BOTTOM) - return 1; - break; - } + if (!ccdc_has_all_fields(ccdc)) + return 1; buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index c325b8901159..731ecc768197 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -93,6 +93,10 @@ struct ispccdc_lsc { #define CCDC_PAD_SOURCE_VP 2 #define CCDC_PADS_NUM 3 +#define CCDC_FIELD_TOP 1 +#define CCDC_FIELD_BOTTOM 2 +#define CCDC_FIELD_BOTH 3 + /* * struct isp_ccdc_device - Structure for the CCDC module to store its own * information @@ -114,6 +118,7 @@ struct ispccdc_lsc { * @update: Bitmask of controls to update during the next interrupt * @shadow_update: Controls update in progress by userspace * @bt656: Whether the input interface uses BT.656 synchronization + * @fields: The fields (CCDC_FIELD_*) stored in the current buffer * @underrun: A buffer underrun occurred and a new buffer has been queued * @state: Streaming state * @lock: Serializes shadow_update with interrupt handler @@ -143,6 +148,8 @@ struct isp_ccdc_device { unsigned int shadow_update; bool bt656; + unsigned int fields; + unsigned int underrun:1; enum isp_pipeline_stream_state state; spinlock_t lock; -- cgit v1.2.3 From 8815392a1d190201765682a82ca4c3e6ad03a674 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 7 Jun 2014 20:57:07 -0300 Subject: [media] omap3isp: ccdc: Rename __ccdc_handle_stopping to ccdc_handle_stopping There's no need for a double underscore in the function name, remove it. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 56c3129c3dcd..cd62d29d34c4 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1413,14 +1413,14 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, return -EBUSY; } -/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence +/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ -static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) +static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) { int rval = 0; @@ -1502,7 +1502,7 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) if (ccdc->lsc.state == LSC_STATE_STOPPING) ccdc->lsc.state = LSC_STATE_STOPPED; - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) goto done; if (ccdc->lsc.state != LSC_STATE_RECONFIG) @@ -1642,7 +1642,7 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) restart = ccdc_isr_buffer(ccdc); spin_lock_irqsave(&ccdc->lock, flags); - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { spin_unlock_irqrestore(&ccdc->lock, flags); return; } @@ -1702,7 +1702,7 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) break; } - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) goto done; if (ccdc->lsc.request == NULL) -- cgit v1.2.3 From 1c74817405d42572db2071b0b4a9609b487c91a7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 06:15:33 -0300 Subject: [media] omap3isp: ccdc: Simplify ccdc_lsc_is_configured() Use a local variable to avoid the duplicate spin_unlock_irqrestore() call. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index cd62d29d34c4..6a62cb76cd1f 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -481,14 +481,13 @@ done: static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc) { unsigned long flags; + int ret; spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - if (ccdc->lsc.active) { - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 1; - } + ret = ccdc->lsc.active != NULL; spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 0; + + return ret; } static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc) -- cgit v1.2.3 From fd93c10afe383d7c28b5edffa29f92b6dae55191 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 09:16:08 -0300 Subject: [media] omap3isp: ccdc: Increment the frame number at VD0 time for BT.656 We will stop using VD1 in BT.656 mode, move frame number increment to the VD0 interrupt handler. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 6a62cb76cd1f..112bced5af99 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1637,6 +1637,16 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) unsigned long flags; int restart = 0; + /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus + * need to increment the frame counter here. + */ + if (ccdc->bt656) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + + atomic_inc(&pipe->frame_number); + } + if (ccdc->output & CCDC_OUTPUT_MEMORY) restart = ccdc_isr_buffer(ccdc); @@ -1662,16 +1672,6 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; - /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus - * need to increment the frame counter here. - */ - if (ccdc->bt656) { - struct isp_pipeline *pipe = - to_isp_pipeline(&ccdc->subdev.entity); - - atomic_inc(&pipe->frame_number); - } - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* -- cgit v1.2.3 From 93456527b4488510d87a523028b3bb73dfdd7669 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 09:41:57 -0300 Subject: [media] omap3isp: ccdc: Fix freeze when a short frame is received In BT.656 mode the synchronization signals are generated by the CCDC from the embedded sync codes. The VD0 and VD1 interrupts are thus only triggered when the CCDC is enabled, unlike external sync mode where the line counter runs even when the CCDC is stopped. We can't disable the CCDC at VD1 time, as no VD0 interrupt would be generated for a short frame, which would result in the CCDC being stopped and no VD interrupt generated anymore. The CCDC is stopped from the VD0 interrupt handler instead for BT.656. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 112bced5af99..ff2ea2bf31e4 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1647,10 +1647,27 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) atomic_inc(&pipe->frame_number); } + /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in + * the VD1 interrupt handler in that mode without risking a CCDC stall + * if a short frame is received. + */ + if (ccdc->bt656) { + spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && + ccdc->output & CCDC_OUTPUT_MEMORY) { + if (ccdc->lsc.state != LSC_STATE_STOPPED) + __ccdc_lsc_enable(ccdc, 0); + __ccdc_enable(ccdc, 0); + } + ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1); + spin_unlock_irqrestore(&ccdc->lock, flags); + } + if (ccdc->output & CCDC_OUTPUT_MEMORY) restart = ccdc_isr_buffer(ccdc); spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { spin_unlock_irqrestore(&ccdc->lock, flags); return; @@ -1672,6 +1689,18 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; + /* In BT.656 mode the synchronization signals are generated by the CCDC + * from the embedded sync codes. The VD0 and VD1 interrupts are thus + * only triggered when the CCDC is enabled, unlike external sync mode + * where the line counter runs even when the CCDC is stopped. We can't + * disable the CCDC at VD1 time, as no VD0 interrupt would be generated + * for a short frame, which would result in the CCDC being stopped and + * no VD interrupt generated anymore. The CCDC is stopped from the VD0 + * interrupt handler instead for BT.656. + */ + if (ccdc->bt656) + return; + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* -- cgit v1.2.3 From 0b3fcd5727e835c60de46d33b2f5f5803c4a5de7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 10:26:28 -0300 Subject: [media] omap3isp: ccdc: Don't timeout on stream off when the CCDC is stopped When the CCDC is already stopped due to a buffer underrun, the stop state machine won't advance in BT.656 mode as no interrupt are generated by the stopped CCDC in that mode. Handle this case explicitly in the ccdc_disable() function. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 4 ++++ drivers/media/platform/omap3isp/ispccdc.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ff2ea2bf31e4..ec0a0e884c79 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1320,6 +1320,8 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0); + + ccdc->running = enable; } static int ccdc_disable(struct isp_ccdc_device *ccdc) @@ -1330,6 +1332,8 @@ static int ccdc_disable(struct isp_ccdc_device *ccdc) spin_lock_irqsave(&ccdc->lock, flags); if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS) ccdc->stopping = CCDC_STOP_REQUEST; + if (!ccdc->running) + ccdc->stopping = CCDC_STOP_FINISHED; spin_unlock_irqrestore(&ccdc->lock, flags); ret = wait_event_timeout(ccdc->wait, diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index 731ecc768197..3440a7097940 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -124,6 +124,7 @@ struct ispccdc_lsc { * @lock: Serializes shadow_update with interrupt handler * @wait: Wait queue used to stop the module * @stopping: Stopping state + * @running: Is the CCDC hardware running * @ioctl_lock: Serializes ioctl calls and LSC requests freeing */ struct isp_ccdc_device { @@ -155,6 +156,7 @@ struct isp_ccdc_device { spinlock_t lock; wait_queue_head_t wait; unsigned int stopping; + bool running; struct mutex ioctl_lock; }; -- cgit v1.2.3 From ca84ea49f8cba11aaca9c9d570431abb5288f56b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 10:28:48 -0300 Subject: [media] omap3isp: ccdc: Restart the CCDC immediately after an underrun in BT.656 As the CCDC doesn't generate interrupts when stopped in BT.656 mode, restart it immediately when the next buffer after an underrun is queued instead of relying on the interrupt handler to restart the CCDC. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ec0a0e884c79..cabf46b4b645 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1789,6 +1789,8 @@ int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events) static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) { struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc; + unsigned long flags; + bool restart = false; if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) return -ENODEV; @@ -1797,9 +1799,20 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when - * starting the stream). + * starting the stream) in external sync mode, or immediately in BT.656 + * sync mode as no CCDC interrupt is generated when the CCDC is stopped + * in that case. */ - ccdc->underrun = 1; + spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running && + ccdc->bt656) + restart = 1; + else + ccdc->underrun = 1; + spin_unlock_irqrestore(&ccdc->lock, flags); + + if (restart) + ccdc_enable(ccdc); return 0; } -- cgit v1.2.3 From 41316a27ee96b31970175bec87210075752001fb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [media] omap3isp: resizer: Remove needless variable initializations There's no need to initialize local variables to zero when they're explicitly assigned another value right after. Remove the needless initializations. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 93104b0957b3..06d4e422b5e8 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -229,7 +229,7 @@ static void resizer_set_phase(struct isp_res_device *res, u32 h_phase, u32 v_phase) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK); @@ -265,7 +265,7 @@ static void resizer_set_luma(struct isp_res_device *res, struct resizer_luma_yenh *luma) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT) & ISPRSZ_YENH_ALGO_MASK; @@ -312,7 +312,7 @@ static void resizer_set_ratio(struct isp_res_device *res, { struct isp_device *isp = to_isp_device(res); const u16 *h_filter, *v_filter; - u32 rgval = 0; + u32 rgval; rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); @@ -355,7 +355,7 @@ static void resizer_set_output_size(struct isp_res_device *res, u32 width, u32 height) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) @@ -399,7 +399,7 @@ static void resizer_set_output_offset(struct isp_res_device *res, u32 offset) static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT) & ISPRSZ_IN_START_HORZ_ST_MASK; @@ -419,7 +419,7 @@ static void resizer_set_input_size(struct isp_res_device *res, u32 width, u32 height) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); -- cgit v1.2.3 From d903a0a367f3e0350a3ba1455c0a7c533977fb42 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [media] omap3isp: resizer: Remove slow debugging message from interrupt handler The resizer_set_input_size() function prints a debugging message with the input width and height values. As the function is called from interrupt context, printing that message to the serial console could slow down the interrupt handler and cause it to miss the start of the next frame, causing image corruption. Fix this by reorganizing the resizer debug messages. The driver now prints the input size, the crop rectangle and the output size in the set selection handler instead of scattering debug messages in various places. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 06d4e422b5e8..ebc812e48fe8 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -357,7 +357,6 @@ static void resizer_set_output_size(struct isp_res_device *res, struct isp_device *isp = to_isp_device(res); u32 rgval; - dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) & ISPRSZ_OUT_SIZE_HORZ_MASK; rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT) @@ -421,8 +420,6 @@ static void resizer_set_input_size(struct isp_res_device *res, struct isp_device *isp = to_isp_device(res); u32 rgval; - dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); - rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT) & ISPRSZ_IN_SIZE_HORZ_MASK; rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT) @@ -1292,12 +1289,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which); - dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__, - sel->r.left, sel->r.top, sel->r.width, sel->r.height, - sel->which); - - dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__, + dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", + __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, + sel->r.left, sel->r.top, sel->r.width, sel->r.height, format_source->width, format_source->height); /* Clamp the crop rectangle to the bounds, and then mangle it further to @@ -1312,6 +1307,12 @@ static int resizer_set_selection(struct v4l2_subdev *sd, *__resizer_get_crop(res, fh, sel->which) = sel->r; resizer_calc_ratios(res, &sel->r, format_source, &ratio); + dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", + __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", + format_sink->width, format_sink->height, + sel->r.left, sel->r.top, sel->r.width, sel->r.height, + format_source->width, format_source->height); + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) return 0; -- cgit v1.2.3 From cd73bb6c4e493cbe227f7861d96dd864a71fe5bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [media] omap3isp: resizer: Protect against races when updating crop When updating the crop rectangle during streaming, the IRQ handler will reprogram the resizer after the current frame. A race condition currently exists between the set selection operation and the IRQ handler: if the set selection operation is called twice in a row and the IRQ handler runs only during the second call, it could reprogram the hardware with partially updated values. Use a spinlock to protect against that. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 43 ++++++++++++++++++++-------- drivers/media/platform/omap3isp/ispresizer.h | 3 ++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index ebc812e48fe8..05d1ace57451 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1062,10 +1062,13 @@ static void resizer_isr_buffer(struct isp_res_device *res) void omap3isp_resizer_isr(struct isp_res_device *res) { struct v4l2_mbus_framefmt *informat, *outformat; + unsigned long flags; if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping)) return; + spin_lock_irqsave(&res->lock, flags); + if (res->applycrop) { outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE, V4L2_SUBDEV_FORMAT_ACTIVE); @@ -1075,6 +1078,8 @@ void omap3isp_resizer_isr(struct isp_res_device *res) res->applycrop = 0; } + spin_unlock_irqrestore(&res->lock, flags); + resizer_isr_buffer(res); } @@ -1277,8 +1282,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd, { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct isp_device *isp = to_isp_device(res); - struct v4l2_mbus_framefmt *format_sink, *format_source; + const struct v4l2_mbus_framefmt *format_sink; + struct v4l2_mbus_framefmt format_source; struct resizer_ratio ratio; + unsigned long flags; if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != RESZ_PAD_SINK) @@ -1286,14 +1293,14 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, sel->which); - format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, - sel->which); + format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, + sel->which); dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, sel->r.left, sel->r.top, sel->r.width, sel->r.height, - format_source->width, format_source->height); + format_source.width, format_source.height); /* Clamp the crop rectangle to the bounds, and then mangle it further to * fulfill the TRM equations. Store the clamped but otherwise unmangled @@ -1303,29 +1310,39 @@ static int resizer_set_selection(struct v4l2_subdev *sd, * smaller input crop rectangle every time the output size is set if we * stored the mangled rectangle. */ - resizer_try_crop(format_sink, format_source, &sel->r); + resizer_try_crop(format_sink, &format_source, &sel->r); *__resizer_get_crop(res, fh, sel->which) = sel->r; - resizer_calc_ratios(res, &sel->r, format_source, &ratio); + resizer_calc_ratios(res, &sel->r, &format_source, &ratio); dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, sel->r.left, sel->r.top, sel->r.width, sel->r.height, - format_source->width, format_source->height); + format_source.width, format_source.height); - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + format_source; return 0; + } + + /* Update the source format, resizing ratios and crop rectangle. If + * streaming is on the IRQ handler will reprogram the resizer after the + * current frame. We thus we need to protect against race conditions. + */ + spin_lock_irqsave(&res->lock, flags); + + *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + format_source; res->ratio = ratio; res->crop.active = sel->r; - /* - * set_selection can be called while streaming is on. In this case the - * crop values will be set in the next IRQ. - */ if (res->state != ISP_PIPELINE_STREAM_STOPPED) res->applycrop = 1; + spin_unlock_irqrestore(&res->lock, flags); + return 0; } @@ -1772,6 +1789,8 @@ int omap3isp_resizer_init(struct isp_device *isp) init_waitqueue_head(&res->wait); atomic_set(&res->stopping, 0); + spin_lock_init(&res->lock); + return resizer_init_entities(res); } diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 494f5a2fd4bb..5414542912e2 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -17,6 +17,7 @@ #ifndef OMAP3_ISP_RESIZER_H #define OMAP3_ISP_RESIZER_H +#include #include /* @@ -86,6 +87,7 @@ enum resizer_input_entity { /* * struct isp_res_device - OMAP3 ISP resizer module + * @lock: Protects formats and crop rectangles between set_selection and IRQ * @crop.request: Crop rectangle requested by the user * @crop.active: Active crop rectangle (based on hardware requirements) */ @@ -106,6 +108,7 @@ struct isp_res_device { enum isp_pipeline_stream_state state; wait_queue_head_t wait; atomic_t stopping; + spinlock_t lock; struct { struct v4l2_rect request; -- cgit v1.2.3 From ae5abd2561b40a1f046088cd30b900ccde63fbc5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:35 -0300 Subject: [media] coda: fix CODA7541 hardware reset Do not try to read the CODA960 GDI status register on CODA7541. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 3a6d1d2b429e..ec82dec04e31 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -350,19 +350,22 @@ static int coda_hw_reset(struct coda_ctx *ctx) idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } } ret = reset_control_reset(dev->rstc); if (ret < 0) return ret; - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); ret = coda_wait_timeout(dev); -- cgit v1.2.3 From 65919e6baa4e6e193dd7e4aa4cfd94b9d69e367e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:36 -0300 Subject: [media] coda: initialize hardware on pm runtime resume only if firmware available If no firmware was found and the coda module is unloaded, coda_runtime_resume will be called without an allocated code buffer. Do not call coda_hw_init in this case. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index ec82dec04e31..75bdac0d3b07 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -3903,7 +3903,7 @@ static int coda_runtime_resume(struct device *dev) struct coda_dev *cdev = dev_get_drvdata(dev); int ret = 0; - if (dev->pm_domain) { + if (dev->pm_domain && cdev->codebuf.vaddr) { ret = coda_hw_init(cdev); if (ret) v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); -- cgit v1.2.3 From 3898e7a72d8131aea2b8daa292df7416a69f41b4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:37 -0300 Subject: [media] coda: remove CAPTURE and OUTPUT caps This is a mem2mem driver, pure capture or output modes are not supported. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 75bdac0d3b07..6befcfdac15c 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -536,13 +536,7 @@ static int coda_querycap(struct file *file, void *priv, strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product), sizeof(cap->card)); strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - /* - * 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->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; -- cgit v1.2.3 From d29a8cf24dca7106f16007e115d3128042e9267a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:38 -0300 Subject: [media] coda: remove VB2_USERPTR from queue io_modes Disallow USERPTR buffers, videobuf2-dma-contig doesn't support them. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 6befcfdac15c..c25756e7eeaf 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -2863,7 +2863,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &coda_qops; @@ -2876,7 +2876,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &coda_qops; -- cgit v1.2.3 From 390503bdb49139e83a0cbfd25a31c5fa36db5ca3 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Fri, 18 Jul 2014 07:22:39 -0300 Subject: [media] coda: use CODA_MAX_FRAME_SIZE everywhere Without this changing CODA_MAX_FRAME_SIZE to anything other than 0x100000 can break the bitstram handling Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index c25756e7eeaf..79c362bd8383 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -3104,7 +3104,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) * by up to 512 bytes */ if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512) + if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); } -- cgit v1.2.3 From eabed931dfc3f47f78b93fb49013af6da66682af Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Fri, 18 Jul 2014 07:22:40 -0300 Subject: [media] coda: delay coda_fill_bitstream() coda_fill_bitstream() calls v4l2_m2m_buf_done() which is no longer allowed before streaming was started. Delay coda_fill_bitstream() until coda_start_streaming() and explicitly set 'start_streaming_called' before calling coda_fill_bitstream() Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 79c362bd8383..898eb3dbb8da 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -1680,7 +1680,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) } mutex_lock(&ctx->bitstream_mutex); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); - coda_fill_bitstream(ctx); + if (vb2_is_streaming(vb->vb2_queue)) + coda_fill_bitstream(ctx); mutex_unlock(&ctx->bitstream_mutex); } else { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); @@ -2270,6 +2271,11 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { + /* copy the buffers that where queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + if (coda_get_bitstream_payload(ctx) < 512) return -EINVAL; } else { -- cgit v1.2.3 From 91b5841e24d1ebefd62f03ff790755ae0f379627 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:41 -0300 Subject: [media] coda: lock capture frame size to output frame size when streaming As soon as the output queue is streaming, let try_fmt on the capture side only allow the frame size that was set on the output side. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 898eb3dbb8da..f1cf44a5aa3c 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -719,6 +719,9 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.pixelformat); if (!codec) return -EINVAL; + + f->fmt.pix.width = q_data_src->width; + f->fmt.pix.height = q_data_src->height; } else { /* Otherwise determine codec by encoded format, if possible */ codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, -- cgit v1.2.3 From 121cacf44531666355d44d0f78948818c2ed9aca Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:42 -0300 Subject: [media] coda: split userspace interface into encoder and decoder device Userspace has a hard time making sense of format enumerations on V4L2 mem2mem devices if there are restrictions on which input and output formats can be used together. Alleviate the problem by splitting the video4linux device into separate encoder and decoder devices which list only raw formats on one side and only encoded formats on the other side. With this patch, the instance type (encoder or decoder) is already determined by the open file operation. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 167 ++++++++++++++++++++++++++++++------------ 1 file changed, 120 insertions(+), 47 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index f1cf44a5aa3c..546cc7bd6a71 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -129,7 +129,7 @@ struct coda_aux_buf { struct coda_dev { struct v4l2_device v4l2_dev; - struct video_device vfd; + struct video_device vfd[2]; struct platform_device *plat_dev; const struct coda_devtype *devtype; @@ -1578,14 +1578,22 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) static void set_default_params(struct coda_ctx *ctx) { + u32 src_fourcc, dst_fourcc; int max_w; int max_h; - ctx->codec = &ctx->dev->devtype->codecs[0]; + if (ctx->inst_type == CODA_INST_ENCODER) { + src_fourcc = V4L2_PIX_FMT_YUV420; + dst_fourcc = V4L2_PIX_FMT_H264; + } else { + src_fourcc = V4L2_PIX_FMT_H264; + dst_fourcc = V4L2_PIX_FMT_YUV420; + } + ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); max_w = ctx->codec->max_w; max_h = ctx->codec->max_h; - ctx->params.codec_mode = CODA_MODE_INVALID; + ctx->params.codec_mode = ctx->codec->mode; ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->params.framerate = 30; ctx->aborting = 0; @@ -1595,12 +1603,19 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; ctx->q_data[V4L2_M2M_SRC].width = max_w; ctx->q_data[V4L2_M2M_SRC].height = max_h; - ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; ctx->q_data[V4L2_M2M_DST].width = max_w; ctx->q_data[V4L2_M2M_DST].height = max_h; - ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { + ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; + ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; + ctx->q_data[V4L2_M2M_DST].bytesperline = 0; + ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + } else { + ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; + ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; + ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2; + } ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; ctx->q_data[V4L2_M2M_DST].rect.width = max_w; @@ -2287,11 +2302,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) } ctx->streamon_out = 1; - - if (coda_format_is_yuv(q_data_src->fourcc)) - ctx->inst_type = CODA_INST_ENCODER; - else - ctx->inst_type = CODA_INST_DECODER; } else { if (count < 1) return -EINVAL; @@ -2713,7 +2723,7 @@ static void coda_stop_streaming(struct vb2_queue *q) } } -static struct vb2_ops coda_qops = { +static const struct vb2_ops coda_qops = { .queue_setup = coda_queue_setup, .buf_prepare = coda_buf_prepare, .buf_queue = coda_buf_queue, @@ -2865,35 +2875,55 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) return v4l2_ctrl_handler_setup(&ctx->ctrls); } -static int coda_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) +{ + vq->drv_priv = ctx; + vq->ops = &coda_qops; + vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + vq->lock = &ctx->dev->dev_mutex; + + return vb2_queue_init(vq); +} + +static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { - struct coda_ctx *ctx = priv; int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->drv_priv = ctx; - 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_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->dev_mutex; - ret = vb2_queue_init(src_vq); + ret = coda_queue_init(priv, src_vq); if (ret) return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->drv_priv = ctx; - 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_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->dev_mutex; - return vb2_queue_init(dst_vq); + return coda_queue_init(priv, dst_vq); +} + +static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); } static int coda_next_free_instance(struct coda_dev *dev) @@ -2907,8 +2937,10 @@ static int coda_next_free_instance(struct coda_dev *dev) return idx; } -static int coda_open(struct file *file) +static int coda_open(struct file *file, enum coda_inst_type inst_type) { + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); struct coda_dev *dev = video_drvdata(file); struct coda_ctx *ctx = NULL; char *name; @@ -2930,6 +2962,7 @@ static int coda_open(struct file *file) ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); kfree(name); + ctx->inst_type = inst_type; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); @@ -2963,8 +2996,11 @@ static int coda_open(struct file *file) goto err_clk_ahb; set_default_params(ctx); - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, - &coda_queue_init); + if (inst_type == CODA_INST_ENCODER) + queue_init = coda_encoder_queue_init; + else + queue_init = coda_decoder_queue_init; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); @@ -3035,6 +3071,16 @@ err_coda_max: return ret; } +static int coda_encoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_ENCODER); +} + +static int coda_decoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_DECODER); +} + static int coda_release(struct file *file) { struct coda_dev *dev = video_drvdata(file); @@ -3079,9 +3125,18 @@ static int coda_release(struct file *file) return 0; } -static const struct v4l2_file_operations coda_fops = { +static const struct v4l2_file_operations coda_encoder_fops = { .owner = THIS_MODULE, - .open = coda_open, + .open = coda_encoder_open, + .release = coda_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct v4l2_file_operations coda_decoder_fops = { + .owner = THIS_MODULE, + .open = coda_decoder_open, .release = coda_release, .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, @@ -3564,6 +3619,17 @@ err_clk_per: return ret; } +static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) +{ + vfd->release = video_device_release_empty, + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + video_set_drvdata(vfd, dev); + + return video_register_device(vfd, VFL_TYPE_GRABBER, 0); +} + static void coda_fw_callback(const struct firmware *fw, void *context) { struct coda_dev *dev = context; @@ -3620,15 +3686,6 @@ static void coda_fw_callback(const struct firmware *fw, void *context) return; } - dev->vfd.fops = &coda_fops, - dev->vfd.ioctl_ops = &coda_ioctl_ops; - dev->vfd.release = video_device_release_empty, - dev->vfd.lock = &dev->dev_mutex; - dev->vfd.v4l2_dev = &dev->v4l2_dev; - dev->vfd.vfl_dir = VFL_DIR_M2M; - snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME); - video_set_drvdata(&dev->vfd, dev); - dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); if (IS_ERR(dev->alloc_ctx)) { v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); @@ -3641,13 +3698,28 @@ static void coda_fw_callback(const struct firmware *fw, void *context) goto rel_ctx; } - ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0); + dev->vfd[0].fops = &coda_encoder_fops, + dev->vfd[0].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); + ret = coda_register_device(dev, &dev->vfd[0]); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + v4l2_err(&dev->v4l2_dev, + "Failed to register encoder video device\n"); goto rel_m2m; } - v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n", - dev->vfd.num); + + dev->vfd[1].fops = &coda_decoder_fops, + dev->vfd[1].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); + ret = coda_register_device(dev, &dev->vfd[1]); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register decoder video device\n"); + goto rel_m2m; + } + + v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", + dev->vfd[0].num, dev->vfd[1].num); return; @@ -3882,7 +3954,8 @@ static int coda_remove(struct platform_device *pdev) { struct coda_dev *dev = platform_get_drvdata(pdev); - video_unregister_device(&dev->vfd); + video_unregister_device(&dev->vfd[0]); + video_unregister_device(&dev->vfd[1]); if (dev->m2m_dev) v4l2_m2m_release(dev->m2m_dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 22e244b813ddd9a290a446ddca24ceca1f78dad2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:43 -0300 Subject: [media] coda: split format enumeration for encoder end decoder device Let the decoder capture side and encoder output side only list uncompressed formats, and the decoder output and encoder capture side only list compressed formats. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 57 +++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 546cc7bd6a71..9493cfdb0ae6 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -542,8 +542,8 @@ static int coda_querycap(struct file *file, void *priv, return 0; } -static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, - enum v4l2_buf_type type, int src_fourcc) +static int coda_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct coda_ctx *ctx = fh_to_ctx(priv); struct coda_codec *codecs = ctx->dev->devtype->codecs; @@ -552,11 +552,19 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, int num_codecs = ctx->dev->devtype->num_codecs; int num_formats = ARRAY_SIZE(coda_formats); int i, k, num = 0; + bool yuv; + + if (ctx->inst_type == CODA_INST_ENCODER) + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); + else + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); for (i = 0; i < num_formats; i++) { - /* Both uncompressed formats are always supported */ - if (coda_format_is_yuv(formats[i].fourcc) && - !coda_format_is_yuv(src_fourcc)) { + /* Skip either raw or compressed formats */ + if (yuv != coda_format_is_yuv(formats[i].fourcc)) + continue; + /* All uncompressed formats are always supported */ + if (yuv) { if (num == f->index) break; ++num; @@ -564,12 +572,10 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, } /* Compressed formats may be supported, check the codec list */ for (k = 0; k < num_codecs; k++) { - /* if src_fourcc is set, only consider matching codecs */ - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[i].fourcc == codecs[k].dst_fourcc && - (!src_fourcc || src_fourcc == codecs[k].src_fourcc)) + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + formats[i].fourcc == codecs[k].dst_fourcc) break; - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && formats[i].fourcc == codecs[k].src_fourcc) break; } @@ -584,7 +590,7 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, fmt = &formats[i]; strlcpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - if (!coda_format_is_yuv(fmt->fourcc)) + if (!yuv) f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -593,31 +599,6 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, return -EINVAL; } -static int coda_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - struct vb2_queue *src_vq; - struct coda_q_data *q_data_src; - - /* If the source format is already fixed, only list matching formats */ - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (vb2_is_streaming(src_vq)) { - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, - q_data_src->fourcc); - } - - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); -} - -static int coda_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); -} - static int coda_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { @@ -970,12 +951,12 @@ static int coda_subscribe_event(struct v4l2_fh *fh, static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_querycap = coda_querycap, - .vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = coda_enum_fmt, .vidioc_g_fmt_vid_cap = coda_g_fmt, .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_out = coda_enum_fmt, .vidioc_g_fmt_vid_out = coda_g_fmt, .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, -- cgit v1.2.3 From 4f31ff010261b9fd232980088bbdbcfcfc4b9318 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:44 -0300 Subject: [media] coda: default to h.264 decoder on invalid formats If the user provides an invalid format, let the decoder device default to h.264. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 9493cfdb0ae6..b18814ebcd20 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -683,7 +683,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec; + struct coda_codec *codec = NULL; struct vb2_queue *src_vq; int ret; @@ -736,6 +736,12 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, /* Determine codec by encoded format, returns NULL if raw or invalid */ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, V4L2_PIX_FMT_YUV420); + if (!codec && ctx->inst_type == CODA_INST_DECODER) { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_YUV420); + if (!codec) + return -EINVAL; + } if (!f->fmt.pix.colorspace) f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; -- cgit v1.2.3 From 814c376255f2fed2c3120f04486f68fe0c286002 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:45 -0300 Subject: [media] coda: mark constant structures as such The format and codec lists and the ops structures are read-only. Mark them as const. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index b18814ebcd20..594b0c7c4151 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -102,7 +102,7 @@ struct coda_codec { struct coda_devtype { char *firmware; enum coda_product product; - struct coda_codec *codecs; + const struct coda_codec *codecs; unsigned int num_codecs; size_t workbuf_size; size_t tempbuf_size; @@ -225,7 +225,7 @@ struct coda_ctx { u32 sequence_offset; struct coda_q_data q_data[2]; enum coda_inst_type inst_type; - struct coda_codec *codec; + const struct coda_codec *codec; enum v4l2_colorspace colorspace; struct coda_params params; struct v4l2_ctrl_handler ctrls; @@ -390,7 +390,7 @@ static struct coda_q_data *get_q_data(struct coda_ctx *ctx, /* * Array of all formats supported by any version of Coda: */ -static struct coda_fmt coda_formats[] = { +static const struct coda_fmt coda_formats[] = { { .name = "YUV 4:2:0 Planar, YCbCr", .fourcc = V4L2_PIX_FMT_YUV420, @@ -419,19 +419,19 @@ static struct coda_fmt coda_formats[] = { * i.MX6 -> coda960 * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants */ -static struct coda_codec codadx6_codecs[] = { +static const struct coda_codec codadx6_codecs[] = { CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), }; -static struct coda_codec coda7_codecs[] = { +static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), }; -static struct coda_codec coda9_codecs[] = { +static const struct coda_codec coda9_codecs[] = { CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), @@ -458,10 +458,10 @@ static u32 coda_format_normalize_yuv(u32 fourcc) return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; } -static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, - int dst_fourcc) +static const struct coda_codec *coda_find_codec(struct coda_dev *dev, + int src_fourcc, int dst_fourcc) { - struct coda_codec *codecs = dev->devtype->codecs; + const struct coda_codec *codecs = dev->devtype->codecs; int num_codecs = dev->devtype->num_codecs; int k; @@ -483,10 +483,10 @@ static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, } static void coda_get_max_dimensions(struct coda_dev *dev, - struct coda_codec *codec, + const struct coda_codec *codec, int *max_w, int *max_h) { - struct coda_codec *codecs = dev->devtype->codecs; + const struct coda_codec *codecs = dev->devtype->codecs; int num_codecs = dev->devtype->num_codecs; unsigned int w, h; int k; @@ -546,9 +546,9 @@ static int coda_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codecs = ctx->dev->devtype->codecs; - struct coda_fmt *formats = coda_formats; - struct coda_fmt *fmt; + const struct coda_codec *codecs = ctx->dev->devtype->codecs; + const struct coda_fmt *formats = coda_formats; + const struct coda_fmt *fmt; int num_codecs = ctx->dev->devtype->num_codecs; int num_formats = ARRAY_SIZE(coda_formats); int i, k, num = 0; @@ -621,7 +621,7 @@ static int coda_g_fmt(struct file *file, void *priv, return 0; } -static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec, +static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, struct v4l2_format *f) { struct coda_dev *dev = ctx->dev; @@ -683,7 +683,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec = NULL; + const struct coda_codec *codec = NULL; struct vb2_queue *src_vq; int ret; @@ -731,7 +731,7 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec; + const struct coda_codec *codec; /* Determine codec by encoded format, returns NULL if raw or invalid */ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, @@ -1529,7 +1529,7 @@ static void coda_unlock(void *m2m_priv) mutex_unlock(&pcdev->dev_mutex); } -static struct v4l2_m2m_ops coda_m2m_ops = { +static const struct v4l2_m2m_ops coda_m2m_ops = { .device_run = coda_device_run, .job_ready = coda_job_ready, .job_abort = coda_job_abort, @@ -2799,7 +2799,7 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops coda_ctrl_ops = { +static const struct v4l2_ctrl_ops coda_ctrl_ops = { .s_ctrl = coda_s_ctrl, }; -- cgit v1.2.3 From e19a763950fa3598edd488c9bf28c86e79262211 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:38 -0300 Subject: [media] coda: move coda driver into its own directory The coda driver has grown significantly and will continue to grow. Move the coda driver into its own directory so it can be split. Rename coda.h to coda_regs.h as it contains the register defines. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 2 +- drivers/media/platform/coda.c | 3999 ----------------------------- drivers/media/platform/coda.h | 447 ---- drivers/media/platform/coda/Makefile | 3 + drivers/media/platform/coda/coda-common.c | 3999 +++++++++++++++++++++++++++++ drivers/media/platform/coda/coda_regs.h | 447 ++++ 6 files changed, 4450 insertions(+), 4447 deletions(-) delete mode 100644 drivers/media/platform/coda.c delete mode 100644 drivers/media/platform/coda.h create mode 100644 drivers/media/platform/coda/Makefile create mode 100644 drivers/media/platform/coda/coda-common.c create mode 100644 drivers/media/platform/coda/coda_regs.h diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index e5269da91906..4ac4c91b4415 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o -obj-$(CONFIG_VIDEO_CODA) += coda.o +obj-$(CONFIG_VIDEO_CODA) += coda/ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c deleted file mode 100644 index 594b0c7c4151..000000000000 --- a/drivers/media/platform/coda.c +++ /dev/null @@ -1,3999 +0,0 @@ -/* - * Coda multi-standard codec IP - * - * Copyright (C) 2012 Vista Silicon S.L. - * Javier Martin, - * Xavier Duret - * - * 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 -#include -#include -#include -#include -#include - -#include "coda.h" - -#define CODA_NAME "coda" - -#define CODADX6_MAX_INSTANCES 4 - -#define CODA_PARA_BUF_SIZE (10 * 1024) -#define CODA_ISRAM_SIZE (2048 * 2) - -#define CODA7_PS_BUF_SIZE 0x28000 -#define CODA9_PS_SAVE_SIZE (512 * 1024) - -#define CODA_MAX_FRAMEBUFFERS 8 - -#define CODA_MAX_FRAME_SIZE 0x100000 -#define FMO_SLICE_SAVE_BUF_SIZE (32) -#define CODA_DEFAULT_GAMMA 4096 -#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ - -#define MIN_W 176 -#define MIN_H 144 - -#define S_ALIGN 1 /* multiple of 2 */ -#define W_ALIGN 1 /* multiple of 2 */ -#define H_ALIGN 1 /* multiple of 2 */ - -#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) - -static int coda_debug; -module_param(coda_debug, int, 0644); -MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -enum coda_inst_type { - CODA_INST_ENCODER, - CODA_INST_DECODER, -}; - -enum coda_product { - CODA_DX6 = 0xf001, - CODA_7541 = 0xf012, - CODA_960 = 0xf020, -}; - -struct coda_fmt { - char *name; - u32 fourcc; -}; - -struct coda_codec { - u32 mode; - u32 src_fourcc; - u32 dst_fourcc; - u32 max_w; - u32 max_h; -}; - -struct coda_devtype { - char *firmware; - enum coda_product product; - const struct coda_codec *codecs; - unsigned int num_codecs; - size_t workbuf_size; - size_t tempbuf_size; - size_t iram_size; -}; - -/* Per-queue, driver-specific private data */ -struct coda_q_data { - unsigned int width; - unsigned int height; - unsigned int bytesperline; - unsigned int sizeimage; - unsigned int fourcc; - struct v4l2_rect rect; -}; - -struct coda_aux_buf { - void *vaddr; - dma_addr_t paddr; - u32 size; - struct debugfs_blob_wrapper blob; - struct dentry *dentry; -}; - -struct coda_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd[2]; - struct platform_device *plat_dev; - const struct coda_devtype *devtype; - - void __iomem *regs_base; - struct clk *clk_per; - struct clk *clk_ahb; - struct reset_control *rstc; - - struct coda_aux_buf codebuf; - struct coda_aux_buf tempbuf; - struct coda_aux_buf workbuf; - struct gen_pool *iram_pool; - struct coda_aux_buf iram; - - spinlock_t irqlock; - struct mutex dev_mutex; - struct mutex coda_mutex; - struct workqueue_struct *workqueue; - struct v4l2_m2m_dev *m2m_dev; - struct vb2_alloc_ctx *alloc_ctx; - struct list_head instances; - unsigned long instance_mask; - struct dentry *debugfs_root; -}; - -struct coda_params { - u8 rot_mode; - u8 h264_intra_qp; - u8 h264_inter_qp; - u8 h264_min_qp; - u8 h264_max_qp; - u8 h264_deblk_enabled; - u8 h264_deblk_alpha; - u8 h264_deblk_beta; - u8 mpeg4_intra_qp; - u8 mpeg4_inter_qp; - u8 gop_size; - int intra_refresh; - int codec_mode; - int codec_mode_aux; - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - u32 framerate; - u16 bitrate; - u32 slice_max_bits; - u32 slice_max_mb; -}; - -struct coda_iram_info { - u32 axi_sram_use; - phys_addr_t buf_bit_use; - phys_addr_t buf_ip_ac_dc_use; - phys_addr_t buf_dbk_y_use; - phys_addr_t buf_dbk_c_use; - phys_addr_t buf_ovl_use; - phys_addr_t buf_btp_use; - phys_addr_t search_ram_paddr; - int search_ram_size; - int remaining; - phys_addr_t next_paddr; -}; - -struct gdi_tiled_map { - int xy2ca_map[16]; - int xy2ba_map[16]; - int xy2ra_map[16]; - int rbc2axi_map[32]; - int xy2rbc_config; - int map_type; -#define GDI_LINEAR_FRAME_MAP 0 -}; - -struct coda_timestamp { - struct list_head list; - u32 sequence; - struct v4l2_timecode timecode; - struct timeval timestamp; -}; - -struct coda_ctx { - struct coda_dev *dev; - struct mutex buffer_mutex; - struct list_head list; - struct work_struct pic_run_work; - struct work_struct seq_end_work; - struct completion completion; - int aborting; - int initialized; - int streamon_out; - int streamon_cap; - u32 isequence; - u32 qsequence; - u32 osequence; - u32 sequence_offset; - struct coda_q_data q_data[2]; - enum coda_inst_type inst_type; - const struct coda_codec *codec; - enum v4l2_colorspace colorspace; - struct coda_params params; - struct v4l2_ctrl_handler ctrls; - struct v4l2_fh fh; - int gopcounter; - int runcounter; - char vpu_header[3][64]; - int vpu_header_size[3]; - struct kfifo bitstream_fifo; - struct mutex bitstream_mutex; - struct coda_aux_buf bitstream; - bool hold; - struct coda_aux_buf parabuf; - struct coda_aux_buf psbuf; - struct coda_aux_buf slicebuf; - struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; - u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; - u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; - struct list_head timestamp_list; - struct coda_aux_buf workbuf; - int num_internal_frames; - int idx; - int reg_idx; - struct coda_iram_info iram_info; - struct gdi_tiled_map tiled_map; - u32 bit_stream_param; - u32 frm_dis_flg; - u32 frame_mem_ctrl; - int display_idx; - struct dentry *debugfs_entry; -}; - -static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; - -static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg) -{ - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); - writel(data, dev->regs_base + reg); -} - -static inline unsigned int coda_read(struct coda_dev *dev, u32 reg) -{ - u32 data; - data = readl(dev->regs_base + reg); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); - return data; -} - -static inline unsigned long coda_isbusy(struct coda_dev *dev) -{ - return coda_read(dev, CODA_REG_BIT_BUSY); -} - -static inline int coda_is_initialized(struct coda_dev *dev) -{ - return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); -} - -static int coda_wait_timeout(struct coda_dev *dev) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - while (coda_isbusy(dev)) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - } - return 0; -} - -static void coda_command_async(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { - /* Restore context related registers to CODA */ - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - coda_write(dev, ctx->frame_mem_ctrl, - CODA_REG_BIT_FRAME_MEM_CTRL); - coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - } - - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - - coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); - - coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); -} - -static int coda_command_sync(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - coda_command_async(ctx, cmd); - return coda_wait_timeout(dev); -} - -static int coda_hw_reset(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - unsigned long timeout; - unsigned int idx; - int ret; - - if (!dev->rstc) - return -ENOENT; - - idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - - if (dev->devtype->product == CODA_960) { - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - } - - ret = reset_control_reset(dev->rstc); - if (ret < 0) - return ret; - - if (dev->devtype->product == CODA_960) - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - ret = coda_wait_timeout(dev); - coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); - - return ret; -} - -static struct coda_q_data *get_q_data(struct coda_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &(ctx->q_data[V4L2_M2M_SRC]); - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &(ctx->q_data[V4L2_M2M_DST]); - default: - return NULL; - } -} - -/* - * Array of all formats supported by any version of Coda: - */ -static const struct coda_fmt coda_formats[] = { - { - .name = "YUV 4:2:0 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:0 Planar, YCrCb", - .fourcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - }, - { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - }, -}; - -#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ - { mode, src_fourcc, dst_fourcc, max_w, max_h } - -/* - * Arrays of codecs supported by each given version of Coda: - * i.MX27 -> codadx6 - * i.MX5x -> coda7 - * i.MX6 -> coda960 - * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants - */ -static const struct coda_codec codadx6_codecs[] = { - CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), - CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), -}; - -static const struct coda_codec coda7_codecs[] = { - CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), - CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), - CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), -}; - -static const struct coda_codec coda9_codecs[] = { - CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), - CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), -}; - -static bool coda_format_is_yuv(u32 fourcc) -{ - switch (fourcc) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - return true; - default: - return false; - } -} - -/* - * Normalize all supported YUV 4:2:0 formats to the value used in the codec - * tables. - */ -static u32 coda_format_normalize_yuv(u32 fourcc) -{ - return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; -} - -static const struct coda_codec *coda_find_codec(struct coda_dev *dev, - int src_fourcc, int dst_fourcc) -{ - const struct coda_codec *codecs = dev->devtype->codecs; - int num_codecs = dev->devtype->num_codecs; - int k; - - src_fourcc = coda_format_normalize_yuv(src_fourcc); - dst_fourcc = coda_format_normalize_yuv(dst_fourcc); - if (src_fourcc == dst_fourcc) - return NULL; - - for (k = 0; k < num_codecs; k++) { - if (codecs[k].src_fourcc == src_fourcc && - codecs[k].dst_fourcc == dst_fourcc) - break; - } - - if (k == num_codecs) - return NULL; - - return &codecs[k]; -} - -static void coda_get_max_dimensions(struct coda_dev *dev, - const struct coda_codec *codec, - int *max_w, int *max_h) -{ - const struct coda_codec *codecs = dev->devtype->codecs; - int num_codecs = dev->devtype->num_codecs; - unsigned int w, h; - int k; - - if (codec) { - w = codec->max_w; - h = codec->max_h; - } else { - for (k = 0, w = 0, h = 0; k < num_codecs; k++) { - w = max(w, codecs[k].max_w); - h = max(h, codecs[k].max_h); - } - } - - if (max_w) - *max_w = w; - if (max_h) - *max_h = h; -} - -static char *coda_product_name(int product) -{ - static char buf[9]; - - switch (product) { - case CODA_DX6: - return "CodaDx6"; - case CODA_7541: - return "CODA7541"; - case CODA_960: - return "CODA960"; - default: - snprintf(buf, sizeof(buf), "(0x%04x)", product); - return buf; - } -} - -/* - * V4L2 ioctl() operations. - */ -static int coda_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - - strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver)); - strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product), - sizeof(cap->card)); - strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static int coda_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codecs = ctx->dev->devtype->codecs; - const struct coda_fmt *formats = coda_formats; - const struct coda_fmt *fmt; - int num_codecs = ctx->dev->devtype->num_codecs; - int num_formats = ARRAY_SIZE(coda_formats); - int i, k, num = 0; - bool yuv; - - if (ctx->inst_type == CODA_INST_ENCODER) - yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); - else - yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); - - for (i = 0; i < num_formats; i++) { - /* Skip either raw or compressed formats */ - if (yuv != coda_format_is_yuv(formats[i].fourcc)) - continue; - /* All uncompressed formats are always supported */ - if (yuv) { - if (num == f->index) - break; - ++num; - continue; - } - /* Compressed formats may be supported, check the codec list */ - for (k = 0; k < num_codecs; k++) { - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[i].fourcc == codecs[k].dst_fourcc) - break; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - formats[i].fourcc == codecs[k].src_fourcc) - break; - } - if (k < num_codecs) { - if (num == f->index) - break; - ++num; - } - } - - if (i < num_formats) { - fmt = &formats[i]; - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; - if (!yuv) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; - return 0; - } - - /* Format not found */ - return -EINVAL; -} - -static int coda_g_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_q_data *q_data; - struct coda_ctx *ctx = fh_to_ctx(priv); - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = q_data->fourcc; - f->fmt.pix.width = q_data->width; - f->fmt.pix.height = q_data->height; - f->fmt.pix.bytesperline = q_data->bytesperline; - - f->fmt.pix.sizeimage = q_data->sizeimage; - f->fmt.pix.colorspace = ctx->colorspace; - - return 0; -} - -static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, - struct v4l2_format *f) -{ - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data; - unsigned int max_w, max_h; - enum v4l2_field field; - - field = f->fmt.pix.field; - if (field == V4L2_FIELD_ANY) - field = V4L2_FIELD_NONE; - else if (V4L2_FIELD_NONE != field) - return -EINVAL; - - /* V4L2 specification suggests the driver corrects the format struct - * if any of the dimensions is unsupported */ - f->fmt.pix.field = field; - - coda_get_max_dimensions(dev, codec, &max_w, &max_h); - v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN, - &f->fmt.pix.height, MIN_H, max_h, H_ALIGN, - S_ALIGN); - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_H264: - case V4L2_PIX_FMT_MPEG4: - case V4L2_PIX_FMT_JPEG: - break; - default: - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - f->fmt.pix.pixelformat = q_data->fourcc; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - /* Frame stride must be multiple of 8, but 16 for h.264 */ - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 3 / 2; - break; - case V4L2_PIX_FMT_H264: - case V4L2_PIX_FMT_MPEG4: - case V4L2_PIX_FMT_JPEG: - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE; - break; - default: - BUG(); - } - - return 0; -} - -static int coda_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec = NULL; - struct vb2_queue *src_vq; - int ret; - - /* - * If the source format is already fixed, try to find a codec that - * converts to the given destination format - */ - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (vb2_is_streaming(src_vq)) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - f->fmt.pix.pixelformat); - if (!codec) - return -EINVAL; - - f->fmt.pix.width = q_data_src->width; - f->fmt.pix.height = q_data_src->height; - } else { - /* Otherwise determine codec by encoded format, if possible */ - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, - f->fmt.pix.pixelformat); - } - - f->fmt.pix.colorspace = ctx->colorspace; - - ret = coda_try_fmt(ctx, codec, f); - if (ret < 0) - return ret; - - /* The h.264 decoder only returns complete 16x16 macroblocks */ - if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) { - f->fmt.pix.width = f->fmt.pix.width; - f->fmt.pix.height = round_up(f->fmt.pix.height, 16); - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height * 3 / 2; - } - - return 0; -} - -static int coda_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec; - - /* Determine codec by encoded format, returns NULL if raw or invalid */ - codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, - V4L2_PIX_FMT_YUV420); - if (!codec && ctx->inst_type == CODA_INST_DECODER) { - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, - V4L2_PIX_FMT_YUV420); - if (!codec) - return -EINVAL; - } - - if (!f->fmt.pix.colorspace) - f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; - - return coda_try_fmt(ctx, codec, f); -} - -static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) -{ - struct coda_q_data *q_data; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - if (vb2_is_busy(vq)) { - v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); - return -EBUSY; - } - - q_data->fourcc = f->fmt.pix.pixelformat; - q_data->width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; - q_data->bytesperline = f->fmt.pix.bytesperline; - q_data->sizeimage = f->fmt.pix.sizeimage; - q_data->rect.left = 0; - q_data->rect.top = 0; - q_data->rect.width = f->fmt.pix.width; - q_data->rect.height = f->fmt.pix.height; - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Setting format for type %d, wxh: %dx%d, fmt: %d\n", - f->type, q_data->width, q_data->height, q_data->fourcc); - - return 0; -} - -static int coda_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; - - ret = coda_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - return coda_s_fmt(ctx, f); -} - -static int coda_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; - - ret = coda_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - - ret = coda_s_fmt(ctx, f); - if (ret) - ctx->colorspace = f->fmt.pix.colorspace; - - return ret; -} - -static int coda_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - - return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); -} - -static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, - struct v4l2_buffer *buf) -{ - struct vb2_queue *src_vq; - - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && - (buf->sequence == (ctx->qsequence - 1))); -} - -static int coda_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - int ret; - - ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); - - /* If this is the last capture buffer, emit an end-of-stream event */ - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - coda_buf_is_end_of_stream(ctx, buf)) { - const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; - - v4l2_event_queue_fh(&ctx->fh, &eos_event); - } - - return ret; -} - -static int coda_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_q_data *q_data; - struct v4l2_rect r, *rsel; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - r.left = 0; - r.top = 0; - r.width = q_data->width; - r.height = q_data->height; - rsel = &q_data->rect; - - switch (s->target) { - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - rsel = &r; - /* fallthrough */ - case V4L2_SEL_TGT_CROP: - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - break; - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_PADDED: - rsel = &r; - /* fallthrough */ - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - break; - default: - return -EINVAL; - } - - s->r = *rsel; - - return 0; -} - -static int coda_try_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - if (dc->cmd != V4L2_DEC_CMD_STOP) - return -EINVAL; - - if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - - if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) - return -EINVAL; - - return 0; -} - -static int coda_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_dev *dev = ctx->dev; - int ret; - - ret = coda_try_decoder_cmd(file, fh, dc); - if (ret < 0) - return ret; - - /* Ignore decoder stop command silently in encoder context */ - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - - /* Set the strem-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - ctx->hold = false; - v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); - - return 0; -} - -static int coda_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, 0, NULL); - default: - return v4l2_ctrl_subscribe_event(fh, sub); - } -} - -static const struct v4l2_ioctl_ops coda_ioctl_ops = { - .vidioc_querycap = coda_querycap, - - .vidioc_enum_fmt_vid_cap = coda_enum_fmt, - .vidioc_g_fmt_vid_cap = coda_g_fmt, - .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = coda_enum_fmt, - .vidioc_g_fmt_vid_out = coda_g_fmt, - .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - - .vidioc_qbuf = coda_qbuf, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = coda_dqbuf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_g_selection = coda_g_selection, - - .vidioc_try_decoder_cmd = coda_try_decoder_cmd, - .vidioc_decoder_cmd = coda_decoder_cmd, - - .vidioc_subscribe_event = coda_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int coda_start_decoding(struct coda_ctx *ctx); - -static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) -{ - return kfifo_len(&ctx->bitstream_fifo); -} - -static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr; - - rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - kfifo->out = (kfifo->in & ~kfifo->mask) | - (rd_ptr - ctx->bitstream.paddr); - if (kfifo->out > kfifo->in) - kfifo->out -= kfifo->mask + 1; -} - -static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr, wr_ptr; - - rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); - coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr; - - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) -{ - u32 src_size = vb2_get_plane_payload(src_buf, 0); - u32 n; - - n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); - if (n < src_size) - return -ENOSPC; - - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, - ctx->bitstream.size, DMA_TO_DEVICE); - - src_buf->v4l2_buf.sequence = ctx->qsequence++; - - return 0; -} - -static bool coda_bitstream_try_queue(struct coda_ctx *ctx, - struct vb2_buffer *src_buf) -{ - int ret; - - if (coda_get_bitstream_payload(ctx) + - vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) - return false; - - if (vb2_plane_vaddr(src_buf, 0) == NULL) { - v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); - return true; - } - - ret = coda_bitstream_queue(ctx, src_buf); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); - return false; - } - /* Sync read pointer to device */ - if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) - coda_kfifo_sync_to_device_write(ctx); - - ctx->hold = false; - - return true; -} - -static void coda_fill_bitstream(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf; - struct coda_timestamp *ts; - - while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - - if (coda_bitstream_try_queue(ctx, src_buf)) { - /* - * Source buffer is queued in the bitstream ringbuffer; - * queue the timestamp and mark source buffer as done - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - - ts = kmalloc(sizeof(*ts), GFP_KERNEL); - if (ts) { - ts->sequence = src_buf->v4l2_buf.sequence; - ts->timecode = src_buf->v4l2_buf.timecode; - ts->timestamp = src_buf->v4l2_buf.timestamp; - list_add_tail(&ts->list, &ctx->timestamp_list); - } - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } else { - break; - } - } -} - -static void coda_set_gdi_regs(struct coda_ctx *ctx) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - struct coda_dev *dev = ctx->dev; - int i; - - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ca_map[i], - CODA9_GDI_XY2_CAS_0 + 4 * i); - for (i = 0; i < 4; i++) - coda_write(dev, tiled_map->xy2ba_map[i], - CODA9_GDI_XY2_BA_0 + 4 * i); - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ra_map[i], - CODA9_GDI_XY2_RAS_0 + 4 * i); - coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); - for (i = 0; i < 32; i++) - coda_write(dev, tiled_map->rbc2axi_map[i], - CODA9_GDI_RBC2_AXI_0 + 4 * i); -} - -/* - * Mem-to-mem operations. - */ -static int coda_prepare_decode(struct coda_ctx *ctx) -{ - struct vb2_buffer *dst_buf; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_dst; - u32 stridey, height; - u32 picture_y, picture_cb, picture_cr; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - if (ctx->params.rot_mode & CODA_ROT_90) { - stridey = q_data_dst->height; - height = q_data_dst->width; - } else { - stridey = q_data_dst->width; - height = q_data_dst->height; - } - - /* Try to copy source buffer contents into the bitstream ringbuffer */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); - - if (coda_get_bitstream_payload(ctx) < 512 && - (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "bitstream payload: %d, skipping\n", - coda_get_bitstream_payload(ctx)); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } - - /* Run coda_start_decoding (again) if not yet initialized */ - if (!ctx->initialized) { - int ret = coda_start_decoding(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } else { - ctx->initialized = 1; - } - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* Set rotator output */ - picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { - /* Switch Cr and Cb for YVU420 format */ - picture_cr = picture_y + stridey * height; - picture_cb = picture_cr + stridey / 2 * height / 2; - } else { - picture_cb = picture_y + stridey * height; - picture_cr = picture_cb + stridey / 2 * height / 2; - } - - if (dev->devtype->product == CODA_960) { - /* - * The CODA960 seems to have an internal list of buffers with - * 64 entries that includes the registered frame buffers as - * well as the rotator buffer output. - * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. - */ - coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, - CODA9_CMD_DEC_PIC_ROT_INDEX); - coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); - } else { - coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); - } - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, - CODA_CMD_DEC_PIC_ROT_MODE); - - switch (dev->devtype->product) { - case CODA_DX6: - /* TBD */ - case CODA_7541: - coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); - break; - case CODA_960: - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ - break; - } - - coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); - - coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); - coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); - - return 0; -} - -static void coda_prepare_encode(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - int force_ipicture; - int quant_param = 0; - u32 picture_y, picture_cb, picture_cr; - u32 pic_stream_buffer_addr, pic_stream_buffer_size; - u32 dst_fourcc; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - src_buf->v4l2_buf.sequence = ctx->osequence; - dst_buf->v4l2_buf.sequence = ctx->osequence; - ctx->osequence++; - - /* - * Workaround coda firmware BUG that only marks the first - * frame as IDR. This is a problem for some decoders that can't - * recover when a frame is lost. - */ - if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } else { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* - * Copy headers at the beginning of the first frame for H.264 only. - * In MPEG4 they are already copied by the coda. - */ - if (src_buf->v4l2_buf.sequence == 0) { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0) + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]; - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - - ctx->vpu_header_size[0] - - ctx->vpu_header_size[1] - - ctx->vpu_header_size[2]; - memcpy(vb2_plane_vaddr(dst_buf, 0), - &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], - &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + - ctx->vpu_header_size[1], &ctx->vpu_header[2][0], - ctx->vpu_header_size[2]); - } else { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; - } - - if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { - force_ipicture = 1; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_intra_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_intra_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set intra qp, fmt not supported\n"); - break; - } - } else { - force_ipicture = 0; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_inter_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_inter_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set inter qp, fmt not supported\n"); - break; - } - } - - /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); - coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); - - - picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); - switch (q_data_src->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - picture_cr = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cb = picture_cr + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - case V4L2_PIX_FMT_YUV420: - default: - picture_cb = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cr = picture_cb + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); - coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); - coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); - - coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); - } else { - coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); - } - coda_write(dev, force_ipicture << 1 & 0x2, - CODA_CMD_ENC_PIC_OPTION); - - coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); - coda_write(dev, pic_stream_buffer_size / 1024, - CODA_CMD_ENC_PIC_BB_SIZE); - - if (!ctx->streamon_out) { - /* After streamoff on the output side, set the stream end flag */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } -} - -static void coda_device_run(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - struct coda_dev *dev = ctx->dev; - - queue_work(dev->workqueue, &ctx->pic_run_work); -} - -static void coda_free_framebuffers(struct coda_ctx *ctx); -static void coda_free_context_buffers(struct coda_ctx *ctx); - -static void coda_seq_end_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); - struct coda_dev *dev = ctx->dev; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_END failed\n"); - } - - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); - - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); -} - -static void coda_finish_decode(struct coda_ctx *ctx); -static void coda_finish_encode(struct coda_ctx *ctx); - -static void coda_pic_run_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); - struct coda_dev *dev = ctx->dev; - int ret; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - if (ctx->inst_type == CODA_INST_DECODER) { - ret = coda_prepare_decode(ctx); - if (ret < 0) { - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - /* job_finish scheduled by prepare_decode */ - return; - } - } else { - coda_prepare_encode(ctx); - } - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - if (ctx->inst_type == CODA_INST_DECODER) - coda_kfifo_sync_to_device_full(ctx); - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { - dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); - - ctx->hold = true; - - coda_hw_reset(ctx); - } else if (!ctx->aborting) { - if (ctx->inst_type == CODA_INST_DECODER) - coda_finish_decode(ctx); - else - coda_finish_encode(ctx); - } - - if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) - queue_work(dev->workqueue, &ctx->seq_end_work); - - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); -} - -static int coda_job_ready(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - - /* - * For both 'P' and 'key' frame cases 1 picture - * and 1 frame are needed. In the decoder case, - * the compressed frame can be in the bitstream. - */ - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - ctx->inst_type != CODA_INST_DECODER) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: not enough video buffers.\n"); - return 0; - } - - if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: not enough video capture buffers.\n"); - return 0; - } - - if (ctx->hold || - ((ctx->inst_type == CODA_INST_DECODER) && - (coda_get_bitstream_payload(ctx) < 512) && - !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: not enough bitstream data.\n", - ctx->idx); - return 0; - } - - if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: aborting\n"); - return 0; - } - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "job ready\n"); - return 1; -} - -static void coda_job_abort(void *priv) -{ - struct coda_ctx *ctx = priv; - - ctx->aborting = 1; - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Aborting task\n"); -} - -static void coda_lock(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - struct coda_dev *pcdev = ctx->dev; - mutex_lock(&pcdev->dev_mutex); -} - -static void coda_unlock(void *m2m_priv) -{ - struct coda_ctx *ctx = m2m_priv; - struct coda_dev *pcdev = ctx->dev; - mutex_unlock(&pcdev->dev_mutex); -} - -static const struct v4l2_m2m_ops coda_m2m_ops = { - .device_run = coda_device_run, - .job_ready = coda_job_ready, - .job_abort = coda_job_abort, - .lock = coda_lock, - .unlock = coda_unlock, -}; - -static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - int luma_map, chro_map, i; - - memset(tiled_map, 0, sizeof(*tiled_map)); - - luma_map = 64; - chro_map = 64; - tiled_map->map_type = tiled_map_type; - for (i = 0; i < 16; i++) - tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 4; i++) - tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 16; i++) - tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map; - - if (tiled_map_type == GDI_LINEAR_FRAME_MAP) { - tiled_map->xy2rbc_config = 0; - } else { - dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n", - tiled_map_type); - return; - } -} - -static void set_default_params(struct coda_ctx *ctx) -{ - u32 src_fourcc, dst_fourcc; - int max_w; - int max_h; - - if (ctx->inst_type == CODA_INST_ENCODER) { - src_fourcc = V4L2_PIX_FMT_YUV420; - dst_fourcc = V4L2_PIX_FMT_H264; - } else { - src_fourcc = V4L2_PIX_FMT_H264; - dst_fourcc = V4L2_PIX_FMT_YUV420; - } - ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); - max_w = ctx->codec->max_w; - max_h = ctx->codec->max_h; - - ctx->params.codec_mode = ctx->codec->mode; - ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->params.framerate = 30; - ctx->aborting = 0; - - /* Default formats for output and input queues */ - ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; - ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; - ctx->q_data[V4L2_M2M_SRC].width = max_w; - ctx->q_data[V4L2_M2M_SRC].height = max_h; - ctx->q_data[V4L2_M2M_DST].width = max_w; - ctx->q_data[V4L2_M2M_DST].height = max_h; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { - ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; - ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; - } else { - ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; - ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE; - ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; - ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2; - } - ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; - ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; - ctx->q_data[V4L2_M2M_DST].rect.width = max_w; - ctx->q_data[V4L2_M2M_DST].rect.height = max_h; - - if (ctx->dev->devtype->product == CODA_960) - coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); -} - -/* - * Queue operations - */ -static int coda_queue_setup(struct vb2_queue *vq, - const struct v4l2_format *fmt, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(vq); - struct coda_q_data *q_data; - unsigned int size; - - q_data = get_q_data(ctx, vq->type); - size = q_data->sizeimage; - - *nplanes = 1; - sizes[0] = size; - - alloc_ctxs[0] = ctx->dev->alloc_ctx; - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "get %d buffer(s) of size %d each.\n", *nbuffers, size); - - return 0; -} - -static int coda_buf_prepare(struct vb2_buffer *vb) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct coda_q_data *q_data; - - q_data = get_q_data(ctx, vb->vb2_queue->type); - - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - v4l2_warn(&ctx->dev->v4l2_dev, - "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), - (long)q_data->sizeimage); - return -EINVAL; - } - - return 0; -} - -static void coda_buf_queue(struct vb2_buffer *vb) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data; - - q_data = get_q_data(ctx, vb->vb2_queue->type); - - /* - * In the decoder case, immediately try to copy the buffer into the - * bitstream ringbuffer and mark it as ready to be dequeued. - */ - if (q_data->fourcc == V4L2_PIX_FMT_H264 && - vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* - * For backwards compatibility, queuing an empty buffer marks - * the stream end - */ - if (vb2_get_plane_payload(vb, 0) == 0) { - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* if this decoder instance is running, set the stream end flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - } - mutex_lock(&ctx->bitstream_mutex); - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); - if (vb2_is_streaming(vb->vb2_queue)) - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); - } else { - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); - } -} - -static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) -{ - struct coda_dev *dev = ctx->dev; - u32 *p = ctx->parabuf.vaddr; - - if (dev->devtype->product == CODA_DX6) - p[index] = value; - else - p[index ^ 1] = value; -} - -static int coda_alloc_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf, size_t size, - const char *name, struct dentry *parent) -{ - buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, - GFP_KERNEL); - if (!buf->vaddr) - return -ENOMEM; - - buf->size = size; - - if (name && parent) { - buf->blob.data = buf->vaddr; - buf->blob.size = size; - buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); - if (!buf->dentry) - dev_warn(&dev->plat_dev->dev, - "failed to create debugfs entry %s\n", name); - } - - return 0; -} - -static inline int coda_alloc_context_buf(struct coda_ctx *ctx, - struct coda_aux_buf *buf, size_t size, - const char *name) -{ - return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); -} - -static void coda_free_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf) -{ - if (buf->vaddr) { - dma_free_coherent(&dev->plat_dev->dev, buf->size, - buf->vaddr, buf->paddr); - buf->vaddr = NULL; - buf->size = 0; - } - debugfs_remove(buf->dentry); -} - -static void coda_free_framebuffers(struct coda_ctx *ctx) -{ - int i; - - for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); -} - -static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc) -{ - struct coda_dev *dev = ctx->dev; - int width, height; - dma_addr_t paddr; - int ysize; - int ret; - int i; - - if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { - width = round_up(q_data->width, 16); - height = round_up(q_data->height, 16); - } else { - width = round_up(q_data->width, 8); - height = q_data->height; - } - ysize = width * height; - - /* Allocate frame buffers */ - for (i = 0; i < ctx->num_internal_frames; i++) { - size_t size; - char *name; - - size = ysize + ysize / 2; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - size += ysize / 4; - name = kasprintf(GFP_KERNEL, "fb%d", i); - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], - size, name); - kfree(name); - if (ret < 0) { - coda_free_framebuffers(ctx); - return ret; - } - } - - /* Register frame buffers in the parameter buffer */ - for (i = 0; i < ctx->num_internal_frames; i++) { - paddr = ctx->internal_frames[i].paddr; - coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ - - /* mvcol buffer for h.264 */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - coda_parabuf_write(ctx, 96 + i, - ctx->internal_frames[i].paddr + - ysize + ysize/4 + ysize/4); - } - - /* mvcol buffer for mpeg4 */ - if ((dev->devtype->product != CODA_DX6) && - (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) - coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + - ysize + ysize/4 + ysize/4); - - return 0; -} - -static int coda_h264_padding(int size, char *p) -{ - int nal_size; - int diff; - - diff = size - (size & ~0x7); - if (diff == 0) - return 0; - - nal_size = coda_filler_size[diff]; - memcpy(p, coda_filler_nal, nal_size); - - /* Add rbsp stop bit and trailing at the end */ - *(p + nal_size - 1) = 0x80; - - return nal_size; -} - -static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) -{ - phys_addr_t ret; - - size = round_up(size, 1024); - if (size > iram->remaining) - return 0; - iram->remaining -= size; - - ret = iram->next_paddr; - iram->next_paddr += size; - - return ret; -} - -static void coda_setup_iram(struct coda_ctx *ctx) -{ - struct coda_iram_info *iram_info = &ctx->iram_info; - struct coda_dev *dev = ctx->dev; - int mb_width; - int dbk_bits; - int bit_bits; - int ip_bits; - - memset(iram_info, 0, sizeof(*iram_info)); - iram_info->next_paddr = dev->iram.paddr; - iram_info->remaining = dev->iram.size; - - switch (dev->devtype->product) { - case CODA_7541: - dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; - bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - case CODA_960: - dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; - bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - default: /* CODA_DX6 */ - return; - } - - if (ctx->inst_type == CODA_INST_ENCODER) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - mb_width = DIV_ROUND_UP(q_data_src->width, 16); - - /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { - iram_info->search_ram_size = round_up(mb_width * 16 * - 36 + 2048, 1024); - iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); - if (!iram_info->search_ram_paddr) { - pr_err("IRAM is smaller than the search ram size\n"); - goto out; - } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; - } - - /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP disabled for encoder */ - } else if (ctx->inst_type == CODA_INST_DECODER) { - struct coda_q_data *q_data_dst; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - mb_width = DIV_ROUND_UP(q_data_dst->width, 16); - - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP unused as there is no VC1 support yet */ - } - -out: - if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "IRAM smaller than needed\n"); - - if (dev->devtype->product == CODA_7541) { - /* TODO - Enabling these causes picture errors on CODA7541 */ - if (ctx->inst_type == CODA_INST_DECODER) { - /* fw 1.4.50 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_IP_ENABLE); - } else { - /* fw 13.4.29 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_HOST_DBK_ENABLE | - CODA7_USE_IP_ENABLE | - CODA7_USE_DBK_ENABLE); - } - } -} - -static void coda_free_context_buffers(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - coda_free_aux_buf(dev, &ctx->slicebuf); - coda_free_aux_buf(dev, &ctx->psbuf); - if (dev->devtype->product != CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); -} - -static int coda_alloc_context_buffers(struct coda_ctx *ctx, - struct coda_q_data *q_data) -{ - struct coda_dev *dev = ctx->dev; - size_t size; - int ret; - - if (dev->devtype->product == CODA_DX6) - return 0; - - if (ctx->psbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); - return -EBUSY; - } - if (ctx->slicebuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); - return -EBUSY; - } - if (ctx->workbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); - ret = -EBUSY; - return -ENOMEM; - } - - if (q_data->fourcc == V4L2_PIX_FMT_H264) { - /* worst case slice size */ - size = (DIV_ROUND_UP(q_data->width, 16) * - DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", - ctx->slicebuf.size); - return ret; - } - } - - if (dev->devtype->product == CODA_7541) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); - goto err; - } - } - - size = dev->devtype->workbuf_size; - if (dev->devtype->product == CODA_960 && - q_data->fourcc == V4L2_PIX_FMT_H264) - size += CODA9_PS_SAVE_SIZE; - ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", - ctx->workbuf.size); - goto err; - } - - return 0; - -err: - coda_free_context_buffers(ctx); - return ret; -} - -static int coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct coda_dev *dev = ctx->dev; - int width, height; - u32 src_fourcc; - u32 val; - int ret; - - /* Start decoding */ - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - bitstream_buf = ctx->bitstream.paddr; - bitstream_size = ctx->bitstream.size; - src_fourcc = q_data_src->fourcc; - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - - /* Update coda bitstream read and write pointers from kfifo */ - coda_kfifo_sync_to_device_full(ctx); - - ctx->display_idx = -1; - ctx->frm_dis_flg = 0; - coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, - CODA_REG_BIT_BIT_STREAM_PARAM); - - coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); - val = 0; - if ((dev->devtype->product == CODA_7541) || - (dev->devtype->product == CODA_960)) - val |= CODA_REORDER_ENABLE; - coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); - - ctx->params.codec_mode = ctx->codec->mode; - if (dev->devtype->product == CODA_960 && - src_fourcc == V4L2_PIX_FMT_MPEG4) - ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; - else - ctx->params.codec_mode_aux = 0; - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { - coda_write(dev, ctx->psbuf.paddr, - CODA_CMD_DEC_SEQ_PS_BB_START); - coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), - CODA_CMD_DEC_SEQ_PS_BB_SIZE); - } - if (dev->devtype->product == CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); - coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); - } - } - if (dev->devtype->product != CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - return -ETIMEDOUT; - } - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - - if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", - coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); - return -EAGAIN; - } - - val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); - if (dev->devtype->product == CODA_DX6) { - width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; - height = val & CODADX6_PICHEIGHT_MASK; - } else { - width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; - height = val & CODA7_PICHEIGHT_MASK; - } - - if (width > q_data_dst->width || height > q_data_dst->height) { - v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->width, q_data_dst->height); - return -EINVAL; - } - - width = round_up(width, 16); - height = round_up(height, 16); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", - __func__, ctx->idx, width, height); - - ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); - if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { - v4l2_err(&dev->v4l2_dev, - "not enough framebuffers to decode (%d < %d)\n", - CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); - return -EINVAL; - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); - - q_data_dst->rect.left = (left_right >> 10) & 0x3ff; - q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; - q_data_dst->rect.width = width - q_data_dst->rect.left - - (left_right & 0x3ff); - q_data_dst->rect.height = height - q_data_dst->rect.top - - (top_bottom & 0x3ff); - } - - ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) - return ret; - - /* Tell the decoder how many frame buffers we allocated. */ - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); - - if (dev->devtype->product != CODA_DX6) { - /* Set secondary AXI IRAM */ - coda_setup_iram(ctx); - - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - - coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); - coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | - 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, - CODA9_CMD_SET_FRAME_CACHE_CONFIG); - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - coda_write(dev, ctx->slicebuf.paddr, - CODA_CMD_SET_FRAME_SLICE_BB_START); - coda_write(dev, ctx->slicebuf.size / 1024, - CODA_CMD_SET_FRAME_SLICE_BB_SIZE); - } - - if (dev->devtype->product == CODA_7541) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); - } else if (dev->devtype->product == CODA_960) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { - v4l2_err(&ctx->dev->v4l2_dev, - "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, - int header_code, u8 *header, int *size) -{ - struct coda_dev *dev = ctx->dev; - size_t bufsize; - int ret; - int i; - - if (dev->devtype->product == CODA_960) - memset(vb2_plane_vaddr(buf, 0), 0, 64); - - coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), - CODA_CMD_ENC_HEADER_BB_START); - bufsize = vb2_plane_size(buf, 0); - if (dev->devtype->product == CODA_960) - bufsize /= 1024; - coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); - coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); - ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); - return ret; - } - - if (dev->devtype->product == CODA_960) { - for (i = 63; i > 0; i--) - if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) - break; - *size = i + 1; - } else { - *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - - coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); - } - memcpy(header, vb2_plane_vaddr(buf, 0), *size); - - return 0; -} - -static int coda_start_encoding(struct coda_ctx *ctx); - -static int coda_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 dst_fourcc; - int ret = 0; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { - /* copy the buffers that where queued before streamon */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); - - if (coda_get_bitstream_payload(ctx) < 512) - return -EINVAL; - } else { - if (count < 1) - return -EINVAL; - } - - ctx->streamon_out = 1; - } else { - if (count < 1) - return -EINVAL; - - ctx->streamon_cap = 1; - } - - /* Don't start the coda unless both queues are on */ - if (!(ctx->streamon_out & ctx->streamon_cap)) - return 0; - - /* Allow decoder device_run with no new buffers queued */ - if (ctx->inst_type == CODA_INST_DECODER) - v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); - - ctx->gopcounter = ctx->params.gop_size - 1; - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - q_data_dst->fourcc); - if (!ctx->codec) { - v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); - return -EINVAL; - } - - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - - if (ctx->inst_type == CODA_INST_DECODER) { - mutex_lock(&dev->coda_mutex); - ret = coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); - if (ret == -EAGAIN) - return 0; - else if (ret < 0) - return ret; - } else { - ret = coda_start_encoding(ctx); - } - - ctx->initialized = 1; - return ret; -} - -static int coda_start_encoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct vb2_buffer *buf; - int gamma, ret, value; - u32 dst_fourcc; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); - bitstream_size = q_data_dst->sizeimage; - - if (!coda_is_initialized(dev)) { - v4l2_err(v4l2_dev, "coda is not initialized.\n"); - return -EFAULT; - } - - mutex_lock(&dev->coda_mutex); - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | - CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - case CODA_960: - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - /* fallthrough */ - case CODA_7541: - coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | - CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - } - - value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); - value &= ~(1 << 2 | 0x7 << 9); - ctx->frame_mem_ctrl = value; - coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product == CODA_DX6) { - /* Configure the coda */ - coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); - } - - /* Could set rotation here if needed */ - switch (dev->devtype->product) { - case CODA_DX6: - value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - case CODA_7541: - if (dst_fourcc == V4L2_PIX_FMT_H264) { - value = (round_up(q_data_src->width, 16) & - CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (round_up(q_data_src->height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - } - /* fallthrough */ - case CODA_960: - value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); - coda_write(dev, ctx->params.framerate, - CODA_CMD_ENC_SEQ_SRC_F_RATE); - - ctx->params.codec_mode = ctx->codec->mode; - switch (dst_fourcc) { - case V4L2_PIX_FMT_MPEG4: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); - break; - case V4L2_PIX_FMT_H264: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - if (ctx->params.h264_deblk_enabled) { - value = ((ctx->params.h264_deblk_alpha & - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | - ((ctx->params.h264_deblk_beta & - CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); - } else { - value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); - break; - default: - v4l2_err(v4l2_dev, - "dst format (0x%08x) invalid.\n", dst_fourcc); - ret = -EINVAL; - goto out; - } - - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; - coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); - - if (ctx->params.bitrate) { - /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; - value |= 1 & CODA_RATECONTROL_ENABLE_MASK; - if (dev->devtype->product == CODA_960) - value |= BIT(31); /* disable autoskip */ - } else { - value = 0; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); - - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); - coda_write(dev, ctx->params.intra_refresh, - CODA_CMD_ENC_SEQ_INTRA_REFRESH); - - coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); - - - value = 0; - if (dev->devtype->product == CODA_960) - gamma = CODA9_DEFAULT_GAMMA; - else - gamma = CODA_DEFAULT_GAMMA; - if (gamma > 0) { - coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, - CODA_CMD_ENC_SEQ_RC_GAMMA); - } - - if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { - coda_write(dev, - ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | - ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, - CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); - } - if (dev->devtype->product == CODA_960) { - if (ctx->params.h264_max_qp) - value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; - if (CODA_DEFAULT_GAMMA > 0) - value |= 1 << CODA9_OPTION_GAMMA_OFFSET; - } else { - if (CODA_DEFAULT_GAMMA > 0) { - if (dev->devtype->product == CODA_DX6) - value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; - else - value |= 1 << CODA7_OPTION_GAMMA_OFFSET; - } - if (ctx->params.h264_min_qp) - value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; - if (ctx->params.h264_max_qp) - value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); - - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); - - coda_setup_iram(ctx); - - if (dst_fourcc == V4L2_PIX_FMT_H264) { - switch (dev->devtype->product) { - case CODA_DX6: - value = FMO_SLICE_SAVE_BUF_SIZE << 7; - coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); - break; - case CODA_7541: - coda_write(dev, ctx->iram_info.search_ram_paddr, - CODA7_CMD_ENC_SEQ_SEARCH_BASE); - coda_write(dev, ctx->iram_info.search_ram_size, - CODA7_CMD_ENC_SEQ_SEARCH_SIZE); - break; - case CODA_960: - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - goto out; - } - - if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); - ret = -EFAULT; - goto out; - } - - if (dev->devtype->product == CODA_960) - ctx->num_internal_frames = 4; - else - ctx->num_internal_frames = 2; - ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); - if (ret < 0) { - v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); - goto out; - } - - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, q_data_src->bytesperline, - CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { - coda_write(dev, q_data_src->bytesperline, - CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); - } - if (dev->devtype->product != CODA_DX6) { - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) { - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - - /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - goto out; - } - - /* Save stream headers */ - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - /* - * Get SPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - /* - * Get PPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - /* - * Length of H.264 headers is variable and thus it might not be - * aligned for the coda to append the encoded frame. In that is - * the case a filler NAL must be added to header 2. - */ - ctx->vpu_header_size[2] = coda_h264_padding( - (ctx->vpu_header_size[0] + - ctx->vpu_header_size[1]), - ctx->vpu_header[2]); - break; - case V4L2_PIX_FMT_MPEG4: - /* - * Get VOS in the first frame and copy it to an - * intermediate buffer - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, - &ctx->vpu_header[2][0], - &ctx->vpu_header_size[2]); - if (ret < 0) - goto out; - break; - default: - /* No more formats need to save headers at the moment */ - break; - } - -out: - mutex_unlock(&dev->coda_mutex); - return ret; -} - -static void coda_stop_streaming(struct vb2_queue *q) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct coda_dev *dev = ctx->dev; - - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: output\n", __func__); - ctx->streamon_out = 0; - - if (ctx->inst_type == CODA_INST_DECODER && - coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) { - /* if this decoder instance is running, set the stream end flag */ - if (dev->devtype->product == CODA_960) { - u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM); - - val |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM); - ctx->bit_stream_param = val; - } - } - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - ctx->isequence = 0; - } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: capture\n", __func__); - ctx->streamon_cap = 0; - - ctx->osequence = 0; - ctx->sequence_offset = 0; - } - - if (!ctx->streamon_out && !ctx->streamon_cap) { - struct coda_timestamp *ts; - - while (!list_empty(&ctx->timestamp_list)) { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - kfree(ts); - } - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - ctx->runcounter = 0; - } -} - -static const struct vb2_ops coda_qops = { - .queue_setup = coda_queue_setup, - .buf_prepare = coda_buf_prepare, - .buf_queue = coda_buf_queue, - .start_streaming = coda_start_streaming, - .stop_streaming = coda_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int coda_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct coda_ctx *ctx = - container_of(ctrl->handler, struct coda_ctx, ctrls); - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - if (ctrl->val) - ctx->params.rot_mode |= CODA_MIR_HOR; - else - ctx->params.rot_mode &= ~CODA_MIR_HOR; - break; - case V4L2_CID_VFLIP: - if (ctrl->val) - ctx->params.rot_mode |= CODA_MIR_VER; - else - ctx->params.rot_mode &= ~CODA_MIR_VER; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctx->params.bitrate = ctrl->val / 1000; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctx->params.gop_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: - ctx->params.h264_intra_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: - ctx->params.h264_inter_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: - ctx->params.h264_min_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: - ctx->params.h264_max_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: - ctx->params.h264_deblk_alpha = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: - ctx->params.h264_deblk_beta = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - ctx->params.h264_deblk_enabled = (ctrl->val == - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: - ctx->params.mpeg4_intra_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: - ctx->params.mpeg4_inter_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: - ctx->params.slice_mode = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: - ctx->params.slice_max_mb = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: - ctx->params.slice_max_bits = ctrl->val * 8; - break; - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - break; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: - ctx->params.intra_refresh = ctrl->val; - break; - default: - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops coda_ctrl_ops = { - .s_ctrl = coda_s_ctrl, -}; - -static int coda_ctrls_setup(struct coda_ctx *ctx) -{ - v4l2_ctrl_handler_init(&ctx->ctrls, 9); - - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25); - if (ctx->dev->devtype->product != CODA_960) { - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12); - } - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0, - V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500); - v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_HEADER_MODE, - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); - - if (ctx->ctrls.error) { - v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)", - ctx->ctrls.error); - return -EINVAL; - } - - return v4l2_ctrl_handler_setup(&ctx->ctrls); -} - -static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) -{ - vq->drv_priv = ctx; - vq->ops = &coda_qops; - vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - vq->lock = &ctx->dev->dev_mutex; - - return vb2_queue_init(vq); -} - -static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->mem_ops = &vb2_dma_contig_memops; - - ret = coda_queue_init(priv, src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->mem_ops = &vb2_dma_contig_memops; - - return coda_queue_init(priv, dst_vq); -} - -static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->mem_ops = &vb2_dma_contig_memops; - - ret = coda_queue_init(priv, src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->mem_ops = &vb2_dma_contig_memops; - - return coda_queue_init(priv, dst_vq); -} - -static int coda_next_free_instance(struct coda_dev *dev) -{ - int idx = ffz(dev->instance_mask); - - if ((idx < 0) || - (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES)) - return -EBUSY; - - return idx; -} - -static int coda_open(struct file *file, enum coda_inst_type inst_type) -{ - int (*queue_init)(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); - struct coda_dev *dev = video_drvdata(file); - struct coda_ctx *ctx = NULL; - char *name; - int ret; - int idx; - - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - idx = coda_next_free_instance(dev); - if (idx < 0) { - ret = idx; - goto err_coda_max; - } - set_bit(idx, &dev->instance_mask); - - name = kasprintf(GFP_KERNEL, "context%d", idx); - ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); - kfree(name); - - ctx->inst_type = inst_type; - init_completion(&ctx->completion); - INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - ctx->dev = dev; - ctx->idx = idx; - switch (dev->devtype->product) { - case CODA_7541: - case CODA_960: - ctx->reg_idx = 0; - break; - default: - ctx->reg_idx = idx; - } - - /* Power up and upload firmware if necessary */ - ret = pm_runtime_get_sync(&dev->plat_dev->dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); - goto err_pm_get; - } - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - set_default_params(ctx); - if (inst_type == CODA_INST_ENCODER) - queue_init = coda_encoder_queue_init; - else - queue_init = coda_decoder_queue_init; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - - v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", - __func__, ret); - goto err_ctx_init; - } - - ret = coda_ctrls_setup(ctx); - if (ret) { - v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); - goto err_ctrls_setup; - } - - ctx->fh.ctrl_handler = &ctx->ctrls; - - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE, - "parabuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); - goto err_dma_alloc; - } - - ctx->bitstream.size = CODA_MAX_FRAME_SIZE; - ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev, - ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); - if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer"); - ret = -ENOMEM; - goto err_dma_writecombine; - } - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - mutex_init(&ctx->bitstream_mutex); - mutex_init(&ctx->buffer_mutex); - INIT_LIST_HEAD(&ctx->timestamp_list); - - coda_lock(ctx); - list_add(&ctx->list, &dev->instances); - coda_unlock(ctx); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n", - ctx->idx, ctx); - - return 0; - -err_dma_writecombine: - coda_free_context_buffers(ctx); - if (ctx->dev->devtype->product == CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); - coda_free_aux_buf(dev, &ctx->parabuf); -err_dma_alloc: - v4l2_ctrl_handler_free(&ctx->ctrls); -err_ctrls_setup: - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); -err_ctx_init: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - pm_runtime_put_sync(&dev->plat_dev->dev); -err_pm_get: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - clear_bit(ctx->idx, &dev->instance_mask); -err_coda_max: - kfree(ctx); - return ret; -} - -static int coda_encoder_open(struct file *file) -{ - return coda_open(file, CODA_INST_ENCODER); -} - -static int coda_decoder_open(struct file *file) -{ - return coda_open(file, CODA_INST_DECODER); -} - -static int coda_release(struct file *file) -{ - struct coda_dev *dev = video_drvdata(file); - struct coda_ctx *ctx = fh_to_ctx(file->private_data); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", - ctx); - - debugfs_remove_recursive(ctx->debugfs_entry); - - /* If this instance is running, call .job_abort and wait for it to end */ - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - - /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized) { - queue_work(dev->workqueue, &ctx->seq_end_work); - flush_work(&ctx->seq_end_work); - } - - coda_free_framebuffers(ctx); - - coda_lock(ctx); - list_del(&ctx->list); - coda_unlock(ctx); - - dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, - ctx->bitstream.vaddr, ctx->bitstream.paddr); - coda_free_context_buffers(ctx); - if (ctx->dev->devtype->product == CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); - - coda_free_aux_buf(dev, &ctx->parabuf); - v4l2_ctrl_handler_free(&ctx->ctrls); - clk_disable_unprepare(dev->clk_ahb); - clk_disable_unprepare(dev->clk_per); - pm_runtime_put_sync(&dev->plat_dev->dev); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - clear_bit(ctx->idx, &dev->instance_mask); - kfree(ctx); - - return 0; -} - -static const struct v4l2_file_operations coda_encoder_fops = { - .owner = THIS_MODULE, - .open = coda_encoder_open, - .release = coda_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct v4l2_file_operations coda_decoder_fops = { - .owner = THIS_MODULE, - .open = coda_decoder_open, - .release = coda_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static void coda_finish_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src; - struct coda_q_data *q_data_dst; - struct vb2_buffer *dst_buf; - struct coda_timestamp *ts; - int width, height; - int decoded_idx; - int display_idx; - u32 src_fourcc; - int success; - u32 err_mb; - u32 val; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - /* - * in stream-end mode, the read pointer can overshoot the write pointer - * by up to 512 bytes - */ - if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - } - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_fourcc = q_data_src->fourcc; - - val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); - if (val != 1) - pr_err("DEC_PIC_SUCCESS = %d\n", val); - - success = val & 0x1; - if (!success) - v4l2_err(&dev->v4l2_dev, "decode failed\n"); - - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (val & (1 << 3)) - v4l2_err(&dev->v4l2_dev, - "insufficient PS buffer space (%d bytes)\n", - ctx->psbuf.size); - if (val & (1 << 2)) - v4l2_err(&dev->v4l2_dev, - "insufficient slice buffer space (%d bytes)\n", - ctx->slicebuf.size); - } - - val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); - width = (val >> 16) & 0xffff; - height = val & 0xffff; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - /* frame crop information */ - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); - - if (left_right == 0xffffffff && top_bottom == 0xffffffff) { - /* Keep current crop information */ - } else { - struct v4l2_rect *rect = &q_data_dst->rect; - - rect->left = left_right >> 16 & 0xffff; - rect->top = top_bottom >> 16 & 0xffff; - rect->width = width - rect->left - - (left_right & 0xffff); - rect->height = height - rect->top - - (top_bottom & 0xffff); - } - } else { - /* no cropping */ - } - - err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); - if (err_mb > 0) - v4l2_err(&dev->v4l2_dev, - "errors in %d macroblocks\n", err_mb); - - if (dev->devtype->product == CODA_7541) { - val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); - if (val == 0) { - /* not enough bitstream data */ - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "prescan failed: %d\n", val); - ctx->hold = true; - return; - } - } - - ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - /* - * The previous display frame was copied out by the rotator, - * now it can be overwritten again - */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - ctx->frm_dis_flg &= ~(1 << ctx->display_idx); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - } - - /* - * The index of the last decoded frame, not necessarily in - * display order, and the index of the next display frame. - * The latter could have been decoded in a previous run. - */ - decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); - display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); - - if (decoded_idx == -1) { - /* no frame was decoded, but we might have a display frame */ - if (display_idx >= 0 && display_idx < ctx->num_internal_frames) - ctx->sequence_offset++; - else if (ctx->display_idx < 0) - ctx->hold = true; - } else if (decoded_idx == -2) { - /* no frame was decoded, we still return the remaining buffers */ - } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "decoded frame index out of range: %d\n", decoded_idx); - } else { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; - val -= ctx->sequence_offset; - if (val != (ts->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, ts->sequence); - } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); - - val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - if (val == 0) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; - else if (val == 1) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; - else - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; - - ctx->frame_errors[decoded_idx] = err_mb; - } - - if (display_idx == -1) { - /* - * no more frames to be decoded, but there could still - * be rotator output to dequeue - */ - ctx->hold = true; - } else if (display_idx == -3) { - /* possibly prescan failure */ - } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "presentation frame index out of range: %d\n", - display_idx); - } - - /* If a frame was copied out, return it */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->v4l2_buf.sequence = ctx->osequence++; - - dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME); - dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; - ts = &ctx->frame_timestamps[ctx->display_idx]; - dst_buf->v4l2_buf.timecode = ts->timecode; - dst_buf->v4l2_buf.timestamp = ts->timestamp; - - vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); - - v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: decoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); - } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: no frame decoded\n"); - } - - /* The rotator will copy the current display frame next time */ - ctx->display_idx = display_idx; -} - -static void coda_finish_encode(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr, start_ptr; - - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Get results from the coda */ - start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); - wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - - /* Calculate bytesused field */ - if (dst_buf->v4l2_buf.sequence == 0) { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]); - } else { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); - } - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", - wr_ptr - start_ptr); - - coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); - coda_read(dev, CODA_RET_ENC_PIC_FLAG); - - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } else { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } - - dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.flags |= - src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); - - ctx->gopcounter--; - if (ctx->gopcounter < 0) - ctx->gopcounter = ctx->params.gop_size - 1; - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: encoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); -} - -static irqreturn_t coda_irq_handler(int irq, void *data) -{ - struct coda_dev *dev = data; - struct coda_ctx *ctx; - - /* read status register to attend the IRQ */ - coda_read(dev, CODA_REG_BIT_INT_STATUS); - coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, - CODA_REG_BIT_INT_CLEAR); - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); - return IRQ_HANDLED; - } - - if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "task has been aborted\n"); - } - - if (coda_isbusy(ctx->dev)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "coda is still busy!!!!\n"); - return IRQ_NONE; - } - - complete(&ctx->completion); - - return IRQ_HANDLED; -} - -static u32 coda_supported_firmwares[] = { - CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), - CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), -}; - -static bool coda_firmware_supported(u32 vernum) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) - if (vernum == coda_supported_firmwares[i]) - return true; - return false; -} - -static int coda_hw_init(struct coda_dev *dev) -{ - u32 data; - u16 *p; - int i, ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - if (dev->rstc) - reset_control_reset(dev->rstc); - - /* - * Copy the first CODA_ISRAM_SIZE in the internal SRAM. - * The 16-bit chars in the code buffer are in memory access - * order, re-sort them to CODA order for register download. - * Data in this SRAM survives a reboot. - */ - p = (u16 *)dev->codebuf.vaddr; - if (dev->devtype->product == CODA_DX6) { - for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { - data = CODA_DOWN_ADDRESS_SET(i) | - CODA_DOWN_DATA_SET(p[i ^ 1]); - coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); - } - } else { - for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { - data = CODA_DOWN_ADDRESS_SET(i) | - CODA_DOWN_DATA_SET(p[round_down(i, 4) + - 3 - (i % 4)]); - coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); - } - } - - /* Clear registers */ - for (i = 0; i < 64; i++) - coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4); - - /* Tell the BIT where to find everything it needs */ - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { - coda_write(dev, dev->tempbuf.paddr, - CODA_REG_BIT_TEMP_BUF_ADDR); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - } else { - coda_write(dev, dev->workbuf.paddr, - CODA_REG_BIT_WORK_BUF_ADDR); - } - coda_write(dev, dev->codebuf.paddr, - CODA_REG_BIT_CODE_BUF_ADDR); - coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); - - /* Set default values */ - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); - break; - default: - coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); - } - if (dev->devtype->product == CODA_960) - coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL); - else - coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE); - - coda_write(dev, CODA_INT_INTERRUPT_ENABLE, - CODA_REG_BIT_INT_ENABLE); - - /* Reset VPU and start processor */ - data = coda_read(dev, CODA_REG_BIT_CODE_RESET); - data |= CODA_REG_RESET_ENABLE; - coda_write(dev, data, CODA_REG_BIT_CODE_RESET); - udelay(10); - data &= ~CODA_REG_RESET_ENABLE; - coda_write(dev, data, CODA_REG_BIT_CODE_RESET); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - - clk_disable_unprepare(dev->clk_ahb); - clk_disable_unprepare(dev->clk_per); - - return 0; - -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - -static int coda_check_firmware(struct coda_dev *dev) -{ - u16 product, major, minor, release; - u32 data; - int ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); - if (coda_wait_timeout(dev)) { - v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); - ret = -EIO; - goto err_run_cmd; - } - - if (dev->devtype->product == CODA_960) { - data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); - v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", - data); - } - - /* Check we are compatible with the loaded firmware */ - data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); - product = CODA_FIRMWARE_PRODUCT(data); - major = CODA_FIRMWARE_MAJOR(data); - minor = CODA_FIRMWARE_MINOR(data); - release = CODA_FIRMWARE_RELEASE(data); - - clk_disable_unprepare(dev->clk_per); - clk_disable_unprepare(dev->clk_ahb); - - if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," - " Version: %u.%u.%u\n", - coda_product_name(dev->devtype->product), - coda_product_name(product), major, minor, release); - return -EINVAL; - } - - v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", - coda_product_name(product)); - - if (coda_firmware_supported(data)) { - v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", - major, minor, release); - } else { - v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " - "%u.%u.%u\n", major, minor, release); - } - - return 0; - -err_run_cmd: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - -static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) -{ - vfd->release = video_device_release_empty, - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - video_set_drvdata(vfd, dev); - - return video_register_device(vfd, VFL_TYPE_GRABBER, 0); -} - -static void coda_fw_callback(const struct firmware *fw, void *context) -{ - struct coda_dev *dev = context; - struct platform_device *pdev = dev->plat_dev; - int ret; - - if (!fw) { - v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); - return; - } - - /* allocate auxiliary per-device code buffer for the BIT processor */ - ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", - dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate code buffer\n"); - return; - } - - /* Copy the whole firmware image to the code buffer */ - memcpy(dev->codebuf.vaddr, fw->data, fw->size); - release_firmware(fw); - - if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) { - /* - * Enabling power temporarily will cause coda_hw_init to be - * called via coda_runtime_resume by the pm domain. - */ - ret = pm_runtime_get_sync(&dev->plat_dev->dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n", - ret); - return; - } - - ret = coda_check_firmware(dev); - if (ret < 0) - return; - - pm_runtime_put_sync(&dev->plat_dev->dev); - } else { - /* - * If runtime pm is disabled or pm_domain is not set, - * initialize once manually. - */ - ret = coda_hw_init(dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); - return; - } - - ret = coda_check_firmware(dev); - if (ret < 0) - return; - } - - dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(dev->alloc_ctx)) { - v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); - return; - } - - dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); - if (IS_ERR(dev->m2m_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); - goto rel_ctx; - } - - dev->vfd[0].fops = &coda_encoder_fops, - dev->vfd[0].ioctl_ops = &coda_ioctl_ops; - snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); - ret = coda_register_device(dev, &dev->vfd[0]); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to register encoder video device\n"); - goto rel_m2m; - } - - dev->vfd[1].fops = &coda_decoder_fops, - dev->vfd[1].ioctl_ops = &coda_ioctl_ops; - snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); - ret = coda_register_device(dev, &dev->vfd[1]); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to register decoder video device\n"); - goto rel_m2m; - } - - v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", - dev->vfd[0].num, dev->vfd[1].num); - - return; - -rel_m2m: - v4l2_m2m_release(dev->m2m_dev); -rel_ctx: - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); -} - -static int coda_firmware_request(struct coda_dev *dev) -{ - char *fw = dev->devtype->firmware; - - dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, - coda_product_name(dev->devtype->product)); - - return request_firmware_nowait(THIS_MODULE, true, - fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback); -} - -enum coda_platform { - CODA_IMX27, - CODA_IMX53, - CODA_IMX6Q, - CODA_IMX6DL, -}; - -static const struct coda_devtype coda_devdata[] = { - [CODA_IMX27] = { - .firmware = "v4l-codadx6-imx27.bin", - .product = CODA_DX6, - .codecs = codadx6_codecs, - .num_codecs = ARRAY_SIZE(codadx6_codecs), - .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, - .iram_size = 0xb000, - }, - [CODA_IMX53] = { - .firmware = "v4l-coda7541-imx53.bin", - .product = CODA_7541, - .codecs = coda7_codecs, - .num_codecs = ARRAY_SIZE(coda7_codecs), - .workbuf_size = 128 * 1024, - .tempbuf_size = 304 * 1024, - .iram_size = 0x14000, - }, - [CODA_IMX6Q] = { - .firmware = "v4l-coda960-imx6q.bin", - .product = CODA_960, - .codecs = coda9_codecs, - .num_codecs = ARRAY_SIZE(coda9_codecs), - .workbuf_size = 80 * 1024, - .tempbuf_size = 204 * 1024, - .iram_size = 0x21000, - }, - [CODA_IMX6DL] = { - .firmware = "v4l-coda960-imx6dl.bin", - .product = CODA_960, - .codecs = coda9_codecs, - .num_codecs = ARRAY_SIZE(coda9_codecs), - .workbuf_size = 80 * 1024, - .tempbuf_size = 204 * 1024, - .iram_size = 0x20000, - }, -}; - -static struct platform_device_id coda_platform_ids[] = { - { .name = "coda-imx27", .driver_data = CODA_IMX27 }, - { .name = "coda-imx53", .driver_data = CODA_IMX53 }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, coda_platform_ids); - -#ifdef CONFIG_OF -static const struct of_device_id coda_dt_ids[] = { - { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, - { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, - { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, - { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, coda_dt_ids); -#endif - -static int coda_probe(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev); - const struct platform_device_id *pdev_id; - struct coda_platform_data *pdata = pdev->dev.platform_data; - struct device_node *np = pdev->dev.of_node; - struct gen_pool *pool; - struct coda_dev *dev; - struct resource *res; - int ret, irq; - - dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Not enough memory for %s\n", - CODA_NAME); - return -ENOMEM; - } - - spin_lock_init(&dev->irqlock); - INIT_LIST_HEAD(&dev->instances); - - dev->plat_dev = pdev; - dev->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(dev->clk_per)) { - dev_err(&pdev->dev, "Could not get per clock\n"); - return PTR_ERR(dev->clk_per); - } - - dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(dev->clk_ahb)) { - dev_err(&pdev->dev, "Could not get ahb clock\n"); - return PTR_ERR(dev->clk_ahb); - } - - /* Get memory for physical registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->regs_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->regs_base)) - return PTR_ERR(dev->regs_base); - - /* IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq resource\n"); - return irq; - } - - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler, - IRQF_ONESHOT, dev_name(&pdev->dev), dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq: %d\n", ret); - return ret; - } - - dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); - if (IS_ERR(dev->rstc)) { - ret = PTR_ERR(dev->rstc); - if (ret == -ENOENT || ret == -ENOSYS) { - dev->rstc = NULL; - } else { - dev_err(&pdev->dev, "failed get reset control: %d\n", ret); - return ret; - } - } - - /* Get IRAM pool from device tree or platform data */ - pool = of_get_named_gen_pool(np, "iram", 0); - if (!pool && pdata) - pool = dev_get_gen_pool(pdata->iram_dev); - if (!pool) { - dev_err(&pdev->dev, "iram pool not available\n"); - return -ENOMEM; - } - dev->iram_pool = pool; - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - return ret; - - mutex_init(&dev->dev_mutex); - mutex_init(&dev->coda_mutex); - - pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); - - if (of_id) { - dev->devtype = of_id->data; - } else if (pdev_id) { - dev->devtype = &coda_devdata[pdev_id->driver_data]; - } else { - v4l2_device_unregister(&dev->v4l2_dev); - return -EINVAL; - } - - dev->debugfs_root = debugfs_create_dir("coda", NULL); - if (!dev->debugfs_root) - dev_warn(&pdev->dev, "failed to create debugfs root\n"); - - /* allocate auxiliary per-device buffers for the BIT processor */ - if (dev->devtype->product == CODA_DX6) { - ret = coda_alloc_aux_buf(dev, &dev->workbuf, - dev->devtype->workbuf_size, "workbuf", - dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate work buffer\n"); - v4l2_device_unregister(&dev->v4l2_dev); - return ret; - } - } - - if (dev->devtype->tempbuf_size) { - ret = coda_alloc_aux_buf(dev, &dev->tempbuf, - dev->devtype->tempbuf_size, "tempbuf", - dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate temp buffer\n"); - v4l2_device_unregister(&dev->v4l2_dev); - return ret; - } - } - - dev->iram.size = dev->devtype->iram_size; - dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, - &dev->iram.paddr); - if (!dev->iram.vaddr) { - dev_err(&pdev->dev, "unable to alloc iram\n"); - return -ENOMEM; - } - - dev->iram.blob.data = dev->iram.vaddr; - dev->iram.blob.size = dev->iram.size; - dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root, - &dev->iram.blob); - - dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); - if (!dev->workqueue) { - dev_err(&pdev->dev, "unable to alloc workqueue\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, dev); - - pm_runtime_enable(&pdev->dev); - - return coda_firmware_request(dev); -} - -static int coda_remove(struct platform_device *pdev) -{ - struct coda_dev *dev = platform_get_drvdata(pdev); - - video_unregister_device(&dev->vfd[0]); - video_unregister_device(&dev->vfd[1]); - if (dev->m2m_dev) - v4l2_m2m_release(dev->m2m_dev); - pm_runtime_disable(&pdev->dev); - if (dev->alloc_ctx) - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); - v4l2_device_unregister(&dev->v4l2_dev); - destroy_workqueue(dev->workqueue); - if (dev->iram.vaddr) - gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr, - dev->iram.size); - coda_free_aux_buf(dev, &dev->codebuf); - coda_free_aux_buf(dev, &dev->tempbuf); - coda_free_aux_buf(dev, &dev->workbuf); - debugfs_remove_recursive(dev->debugfs_root); - return 0; -} - -#ifdef CONFIG_PM_RUNTIME -static int coda_runtime_resume(struct device *dev) -{ - struct coda_dev *cdev = dev_get_drvdata(dev); - int ret = 0; - - if (dev->pm_domain && cdev->codebuf.vaddr) { - ret = coda_hw_init(cdev); - if (ret) - v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); - } - - return ret; -} -#endif - -static const struct dev_pm_ops coda_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL) -}; - -static struct platform_driver coda_driver = { - .probe = coda_probe, - .remove = coda_remove, - .driver = { - .name = CODA_NAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(coda_dt_ids), - .pm = &coda_pm_ops, - }, - .id_table = coda_platform_ids, -}; - -module_platform_driver(coda_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Javier Martin "); -MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h deleted file mode 100644 index c791275e307b..000000000000 --- a/drivers/media/platform/coda.h +++ /dev/null @@ -1,447 +0,0 @@ -/* - * linux/drivers/media/platform/coda/coda_regs.h - * - * Copyright (C) 2012 Vista Silicon SL - * Javier Martin - * Xavier Duret - * - * 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. - */ - -#ifndef _REGS_CODA_H_ -#define _REGS_CODA_H_ - -/* HW registers */ -#define CODA_REG_BIT_CODE_RUN 0x000 -#define CODA_REG_RUN_ENABLE (1 << 0) -#define CODA_REG_BIT_CODE_DOWN 0x004 -#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16) -#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff) -#define CODA_REG_BIT_HOST_IN_REQ 0x008 -#define CODA_REG_BIT_INT_CLEAR 0x00c -#define CODA_REG_BIT_INT_CLEAR_SET 0x1 -#define CODA_REG_BIT_INT_STATUS 0x010 -#define CODA_REG_BIT_CODE_RESET 0x014 -#define CODA_REG_RESET_ENABLE (1 << 0) -#define CODA_REG_BIT_CUR_PC 0x018 -#define CODA9_REG_BIT_SW_RESET 0x024 -#define CODA9_SW_RESET_BPU_CORE 0x008 -#define CODA9_SW_RESET_BPU_BUS 0x010 -#define CODA9_SW_RESET_VCE_CORE 0x020 -#define CODA9_SW_RESET_VCE_BUS 0x040 -#define CODA9_SW_RESET_GDI_CORE 0x080 -#define CODA9_SW_RESET_GDI_BUS 0x100 -#define CODA9_REG_BIT_SW_RESET_STATUS 0x034 - -/* Static SW registers */ -#define CODA_REG_BIT_CODE_BUF_ADDR 0x100 -#define CODA_REG_BIT_WORK_BUF_ADDR 0x104 -#define CODA_REG_BIT_PARA_BUF_ADDR 0x108 -#define CODA_REG_BIT_STREAM_CTRL 0x10c -#define CODA7_STREAM_BUF_PIC_RESET (1 << 4) -#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3) -#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3) -#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2) -#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5) -#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4) -#define CODADX6_STREAM_CHKDIS_OFFSET (1 << 1) -#define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) -#define CODA_STREAM_ENDIAN_SELECT (1 << 0) -#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 -#define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) -#define CODA_IMAGE_ENDIAN_SELECT (1 << 0) -#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 -#define CODA_BIT_STREAM_END_FLAG (1 << 2) -#define CODA_BIT_DEC_SEQ_INIT_ESCAPE (1 << 0) -#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118 -#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x)) -#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x)) -#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x)) -#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140 -#define CODA7_REG_BIT_AXI_SRAM_USE 0x140 -#define CODA9_USE_HOST_BTP_ENABLE (1 << 13) -#define CODA9_USE_HOST_OVL_ENABLE (1 << 12) -#define CODA7_USE_HOST_ME_ENABLE (1 << 11) -#define CODA9_USE_HOST_DBK_ENABLE (3 << 10) -#define CODA7_USE_HOST_OVL_ENABLE (1 << 10) -#define CODA7_USE_HOST_DBK_ENABLE (1 << 9) -#define CODA9_USE_HOST_IP_ENABLE (1 << 9) -#define CODA7_USE_HOST_IP_ENABLE (1 << 8) -#define CODA9_USE_HOST_BIT_ENABLE (1 << 8) -#define CODA7_USE_HOST_BIT_ENABLE (1 << 7) -#define CODA9_USE_BTP_ENABLE (1 << 5) -#define CODA7_USE_ME_ENABLE (1 << 4) -#define CODA9_USE_OVL_ENABLE (1 << 4) -#define CODA7_USE_OVL_ENABLE (1 << 3) -#define CODA9_USE_DBK_ENABLE (3 << 2) -#define CODA7_USE_DBK_ENABLE (1 << 2) -#define CODA7_USE_IP_ENABLE (1 << 1) -#define CODA7_USE_BIT_ENABLE (1 << 0) - -#define CODA_REG_BIT_BUSY 0x160 -#define CODA_REG_BIT_BUSY_FLAG 1 -#define CODA_REG_BIT_RUN_COMMAND 0x164 -#define CODA_COMMAND_SEQ_INIT 1 -#define CODA_COMMAND_SEQ_END 2 -#define CODA_COMMAND_PIC_RUN 3 -#define CODA_COMMAND_SET_FRAME_BUF 4 -#define CODA_COMMAND_ENCODE_HEADER 5 -#define CODA_COMMAND_ENC_PARA_SET 6 -#define CODA_COMMAND_DEC_PARA_SET 7 -#define CODA_COMMAND_DEC_BUF_FLUSH 8 -#define CODA_COMMAND_RC_CHANGE_PARAMETER 9 -#define CODA_COMMAND_FIRMWARE_GET 0xf -#define CODA_REG_BIT_RUN_INDEX 0x168 -#define CODA_INDEX_SET(x) ((x) & 0x3) -#define CODA_REG_BIT_RUN_COD_STD 0x16c -#define CODADX6_MODE_DECODE_MP4 0 -#define CODADX6_MODE_ENCODE_MP4 1 -#define CODADX6_MODE_DECODE_H264 2 -#define CODADX6_MODE_ENCODE_H264 3 -#define CODA7_MODE_DECODE_H264 0 -#define CODA7_MODE_DECODE_VC1 1 -#define CODA7_MODE_DECODE_MP2 2 -#define CODA7_MODE_DECODE_MP4 3 -#define CODA7_MODE_DECODE_DV3 3 -#define CODA7_MODE_DECODE_RV 4 -#define CODA7_MODE_DECODE_MJPG 5 -#define CODA7_MODE_ENCODE_H264 8 -#define CODA7_MODE_ENCODE_MP4 11 -#define CODA7_MODE_ENCODE_MJPG 13 -#define CODA9_MODE_DECODE_H264 0 -#define CODA9_MODE_DECODE_VC1 1 -#define CODA9_MODE_DECODE_MP2 2 -#define CODA9_MODE_DECODE_MP4 3 -#define CODA9_MODE_DECODE_DV3 3 -#define CODA9_MODE_DECODE_RV 4 -#define CODA9_MODE_DECODE_AVS 5 -#define CODA9_MODE_DECODE_MJPG 6 -#define CODA9_MODE_DECODE_VPX 7 -#define CODA9_MODE_ENCODE_H264 8 -#define CODA9_MODE_ENCODE_MP4 11 -#define CODA9_MODE_ENCODE_MJPG 13 -#define CODA_MODE_INVALID 0xffff -#define CODA_REG_BIT_INT_ENABLE 0x170 -#define CODA_INT_INTERRUPT_ENABLE (1 << 3) -#define CODA_REG_BIT_INT_REASON 0x174 -#define CODA7_REG_BIT_RUN_AUX_STD 0x178 -#define CODA_MP4_AUX_MPEG4 0 -#define CODA_MP4_AUX_DIVX3 1 -#define CODA_VPX_AUX_THO 0 -#define CODA_VPX_AUX_VP6 1 -#define CODA_VPX_AUX_VP8 2 -#define CODA_H264_AUX_AVC 0 -#define CODA_H264_AUX_MVC 1 - -/* - * Commands' mailbox: - * registers with offsets in the range 0x180-0x1d0 - * have different meaning depending on the command being - * issued. - */ - -/* Decoder Sequence Initialization */ -#define CODA_CMD_DEC_SEQ_BB_START 0x180 -#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184 -#define CODA_CMD_DEC_SEQ_OPTION 0x188 -#define CODA_REORDER_ENABLE (1 << 1) -#define CODADX6_QP_REPORT (1 << 0) -#define CODA7_MP4_DEBLK_ENABLE (1 << 0) -#define CODA_CMD_DEC_SEQ_SRC_SIZE 0x18c -#define CODA_CMD_DEC_SEQ_START_BYTE 0x190 -#define CODA_CMD_DEC_SEQ_PS_BB_START 0x194 -#define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198 -#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c -#define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c -#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0 - -#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0 -#define CODA9_RET_DEC_SEQ_BITRATE 0x1b4 -#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0 -#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */ -#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4 -#define CODA_RET_DEC_SEQ_SRC_F_RATE 0x1c8 -#define CODA9_RET_DEC_SEQ_ASPECT 0x1c8 -#define CODA_RET_DEC_SEQ_FRAME_NEED 0x1cc -#define CODA_RET_DEC_SEQ_FRAME_DELAY 0x1d0 -#define CODA_RET_DEC_SEQ_INFO 0x1d4 -#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT 0x1d8 -#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM 0x1dc -#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM 0x1e0 -#define CODA_RET_DEC_SEQ_ERR_REASON 0x1e0 -#define CODA_RET_DEC_SEQ_FRATE_NR 0x1e4 -#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 -#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 -#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 -#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec - -/* Decoder Picture Run */ -#define CODA_CMD_DEC_PIC_ROT_MODE 0x180 -#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184 -#define CODA9_CMD_DEC_PIC_ROT_INDEX 0x184 -#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188 -#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y 0x188 -#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c -#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB 0x18c -#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190 -#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR 0x190 -#define CODA9_CMD_DEC_PIC_ROT_STRIDE 0x1b8 - -#define CODA_CMD_DEC_PIC_OPTION 0x194 -#define CODA_PRE_SCAN_EN (1 << 0) -#define CODA_PRE_SCAN_MODE_DECODE (0 << 1) -#define CODA_PRE_SCAN_MODE_RETURN (1 << 1) -#define CODA_IFRAME_SEARCH_EN (1 << 2) -#define CODA_SKIP_FRAME_MODE (0x3 << 3) -#define CODA_CMD_DEC_PIC_SKIP_NUM 0x198 -#define CODA_CMD_DEC_PIC_CHUNK_SIZE 0x19c -#define CODA_CMD_DEC_PIC_BB_START 0x1a0 -#define CODA_CMD_DEC_PIC_START_BYTE 0x1a4 -#define CODA_RET_DEC_PIC_SIZE 0x1bc -#define CODA_RET_DEC_PIC_FRAME_NUM 0x1c0 -#define CODA_RET_DEC_PIC_FRAME_IDX 0x1c4 -#define CODA_RET_DEC_PIC_ERR_MB 0x1c8 -#define CODA_RET_DEC_PIC_TYPE 0x1cc -#define CODA_PIC_TYPE_MASK 0x7 -#define CODA_PIC_TYPE_MASK_VC1 0x3f -#define CODA9_PIC_TYPE_FIRST_MASK (0x7 << 3) -#define CODA9_PIC_TYPE_IDR_MASK (0x3 << 6) -#define CODA7_PIC_TYPE_H264_NPF_MASK (0x3 << 16) -#define CODA7_PIC_TYPE_INTERLACED (1 << 18) -#define CODA_RET_DEC_PIC_POST 0x1d0 -#define CODA_RET_DEC_PIC_MVC_REPORT 0x1d0 -#define CODA_RET_DEC_PIC_OPTION 0x1d4 -#define CODA_RET_DEC_PIC_SUCCESS 0x1d8 -#define CODA_RET_DEC_PIC_CUR_IDX 0x1dc -#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT 0x1e0 -#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4 -#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec - -#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT 0x1e8 -#define CODA9_RET_DEC_PIC_ASPECT 0x1f0 -#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO 0x1f0 -#define CODA9_RET_DEC_PIC_FRATE_NR 0x1f4 -#define CODA9_RET_DEC_PIC_FRATE_DR 0x1f8 - -/* Encoder Sequence Initialization */ -#define CODA_CMD_ENC_SEQ_BB_START 0x180 -#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184 -#define CODA_CMD_ENC_SEQ_OPTION 0x188 -#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9 -#define CODA9_OPTION_MVC_PREFIX_NAL_OFFSET 9 -#define CODA7_OPTION_GAMMA_OFFSET 8 -#define CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET 8 -#define CODA7_OPTION_RCQPMAX_OFFSET 7 -#define CODA9_OPTION_GAMMA_OFFSET 7 -#define CODADX6_OPTION_GAMMA_OFFSET 7 -#define CODA7_OPTION_RCQPMIN_OFFSET 6 -#define CODA9_OPTION_RCQPMAX_OFFSET 6 -#define CODA_OPTION_LIMITQP_OFFSET 6 -#define CODA_OPTION_RCINTRAQP_OFFSET 5 -#define CODA_OPTION_FMO_OFFSET 4 -#define CODA9_OPTION_MVC_INTERVIEW_OFFSET 4 -#define CODA_OPTION_AVC_AUD_OFFSET 2 -#define CODA_OPTION_SLICEREPORT_OFFSET 1 -#define CODA_CMD_ENC_SEQ_COD_STD 0x18c -#define CODA_STD_MPEG4 0 -#define CODA9_STD_H264 0 -#define CODA_STD_H263 1 -#define CODA_STD_H264 2 -#define CODA_STD_MJPG 3 -#define CODA9_STD_MPEG4 3 - -#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190 -#define CODA7_PICWIDTH_OFFSET 16 -#define CODA7_PICWIDTH_MASK 0xffff -#define CODADX6_PICWIDTH_OFFSET 10 -#define CODADX6_PICWIDTH_MASK 0x3ff -#define CODA_PICHEIGHT_OFFSET 0 -#define CODADX6_PICHEIGHT_MASK 0x3ff -#define CODA7_PICHEIGHT_MASK 0xffff -#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 -#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 -#define CODA_MP4PARAM_VERID_OFFSET 6 -#define CODA_MP4PARAM_VERID_MASK 0x01 -#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2 -#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07 -#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1 -#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01 -#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0 -#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_263_PARA 0x19c -#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2 -#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01 -#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1 -#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01 -#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0 -#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0 -#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12 -#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f -#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 -#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f -#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 -#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01 -#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 -#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 -#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 -#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f -#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4 -#define CODA_SLICING_SIZE_OFFSET 2 -#define CODA_SLICING_SIZE_MASK 0x3fffffff -#define CODA_SLICING_UNIT_OFFSET 1 -#define CODA_SLICING_UNIT_MASK 0x01 -#define CODA_SLICING_MODE_OFFSET 0 -#define CODA_SLICING_MODE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8 -#define CODA_GOP_SIZE_OFFSET 0 -#define CODA_GOP_SIZE_MASK 0x3f -#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac -#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 -#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 -#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 -#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f -#define CODA_RATECONTROL_BITRATE_OFFSET 1 -#define CODA_RATECONTROL_BITRATE_MASK 0x7f -#define CODA_RATECONTROL_ENABLE_OFFSET 0 -#define CODA_RATECONTROL_ENABLE_MASK 0x01 -#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 -#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4 -#define CODADX6_CMD_ENC_SEQ_FMO 0x1b8 -#define CODA_FMOPARAM_TYPE_OFFSET 4 -#define CODA_FMOPARAM_TYPE_MASK 1 -#define CODA_FMOPARAM_SLICENUM_OFFSET 0 -#define CODA_FMOPARAM_SLICENUM_MASK 0x0f -#define CODADX6_CMD_ENC_SEQ_INTRA_QP 0x1bc -#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8 -#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc -#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4 -#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX 0x1c8 -#define CODA_QPMIN_OFFSET 8 -#define CODA_QPMIN_MASK 0x3f -#define CODA_QPMAX_OFFSET 0 -#define CODA_QPMAX_MASK 0x3f -#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc -#define CODA_GAMMA_OFFSET 0 -#define CODA_GAMMA_MASK 0xffff -#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE 0x1d0 -#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT 0x1d4 -#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8 -#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 - -/* Encoder Picture Run */ -#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 -#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 -#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC 0x1a4 -#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y 0x1a8 -#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB 0x1ac -#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR 0x1b0 -#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180 -#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184 -#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188 -#define CODA_CMD_ENC_PIC_QS 0x18c -#define CODA_CMD_ENC_PIC_ROT_MODE 0x190 -#define CODA_ROT_MIR_ENABLE (1 << 4) -#define CODA_ROT_0 (0x0 << 0) -#define CODA_ROT_90 (0x1 << 0) -#define CODA_ROT_180 (0x2 << 0) -#define CODA_ROT_270 (0x3 << 0) -#define CODA_MIR_NONE (0x0 << 2) -#define CODA_MIR_VER (0x1 << 2) -#define CODA_MIR_HOR (0x2 << 2) -#define CODA_MIR_VER_HOR (0x3 << 2) -#define CODA_CMD_ENC_PIC_OPTION 0x194 -#define CODA_FORCE_IPICTURE BIT(1) -#define CODA_REPORT_MB_INFO BIT(3) -#define CODA_REPORT_MV_INFO BIT(4) -#define CODA_REPORT_SLICE_INFO BIT(5) -#define CODA_CMD_ENC_PIC_BB_START 0x198 -#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c -#define CODA_RET_ENC_FRAME_NUM 0x1c0 -#define CODA_RET_ENC_PIC_TYPE 0x1c4 -#define CODA_RET_ENC_PIC_FRAME_IDX 0x1c8 -#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc -#define CODA_RET_ENC_PIC_FLAG 0x1d0 -#define CODA_RET_ENC_PIC_SUCCESS 0x1d8 - -/* Set Frame Buffer */ -#define CODA_CMD_SET_FRAME_BUF_NUM 0x180 -#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184 -#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188 -#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c -#define CODA9_CMD_SET_FRAME_SUBSAMP_A 0x188 -#define CODA9_CMD_SET_FRAME_SUBSAMP_B 0x18c -#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190 -#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194 -#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198 -#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c -#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0 -#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4 -#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR 0x1a4 -#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8 -#define CODA9_CMD_SET_FRAME_CACHE_SIZE 0x1a8 -#define CODA9_CMD_SET_FRAME_CACHE_CONFIG 0x1ac -#define CODA9_CACHE_BYPASS_OFFSET 28 -#define CODA9_CACHE_DUALCONF_OFFSET 26 -#define CODA9_CACHE_PAGEMERGE_OFFSET 24 -#define CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET 16 -#define CODA9_CACHE_CB_BUFFER_SIZE_OFFSET 8 -#define CODA9_CACHE_CR_BUFFER_SIZE_OFFSET 0 -#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC 0x1b0 -#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC 0x1b4 -#define CODA9_CMD_SET_FRAME_DP_BUF_BASE 0x1b0 -#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE 0x1b4 -#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE 0x1b8 -#define CODA9_CMD_SET_FRAME_DELAY 0x1bc - -/* Encoder Header */ -#define CODA_CMD_ENC_HEADER_CODE 0x180 -#define CODA_GAMMA_OFFSET 0 -#define CODA_HEADER_H264_SPS 0 -#define CODA_HEADER_H264_PPS 1 -#define CODA_HEADER_MP4V_VOL 0 -#define CODA_HEADER_MP4V_VOS 1 -#define CODA_HEADER_MP4V_VIS 2 -#define CODA9_HEADER_FRAME_CROP (1 << 3) -#define CODA_CMD_ENC_HEADER_BB_START 0x184 -#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188 -#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H 0x18c -#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V 0x190 - -/* Get Version */ -#define CODA_CMD_FIRMWARE_VERNUM 0x1c0 -#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff) -#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f) -#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f) -#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff) -#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \ - ((product) << 16 | ((major) << 12) | \ - ((minor) << 8) | (release)) -#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4 - -#define CODA9_GDMA_BASE 0x1000 -#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0) -#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac) - -#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0) -#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4) - -#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800) -#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c) - -#define CODA9_GDI_XY2_BA_0 (CODA9_GDMA_BASE + 0x840) -#define CODA9_GDI_XY2_BA_1 (CODA9_GDMA_BASE + 0x844) -#define CODA9_GDI_XY2_BA_2 (CODA9_GDMA_BASE + 0x848) -#define CODA9_GDI_XY2_BA_3 (CODA9_GDMA_BASE + 0x84c) - -#define CODA9_GDI_XY2_RAS_0 (CODA9_GDMA_BASE + 0x850) -#define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) - -#define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) -#define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) -#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) - -#endif diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile new file mode 100644 index 000000000000..13d9ad6df51f --- /dev/null +++ b/drivers/media/platform/coda/Makefile @@ -0,0 +1,3 @@ +coda-objs := coda-common.o + +obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c new file mode 100644 index 000000000000..98784ee9d38a --- /dev/null +++ b/drivers/media/platform/coda/coda-common.c @@ -0,0 +1,3999 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * + * 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 +#include +#include +#include +#include +#include + +#include "coda_regs.h" + +#define CODA_NAME "coda" + +#define CODADX6_MAX_INSTANCES 4 + +#define CODA_PARA_BUF_SIZE (10 * 1024) +#define CODA_ISRAM_SIZE (2048 * 2) + +#define CODA7_PS_BUF_SIZE 0x28000 +#define CODA9_PS_SAVE_SIZE (512 * 1024) + +#define CODA_MAX_FRAMEBUFFERS 8 + +#define CODA_MAX_FRAME_SIZE 0x100000 +#define FMO_SLICE_SAVE_BUF_SIZE (32) +#define CODA_DEFAULT_GAMMA 4096 +#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ + +#define MIN_W 176 +#define MIN_H 144 + +#define S_ALIGN 1 /* multiple of 2 */ +#define W_ALIGN 1 /* multiple of 2 */ +#define H_ALIGN 1 /* multiple of 2 */ + +#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) + +static int coda_debug; +module_param(coda_debug, int, 0644); +MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum coda_inst_type { + CODA_INST_ENCODER, + CODA_INST_DECODER, +}; + +enum coda_product { + CODA_DX6 = 0xf001, + CODA_7541 = 0xf012, + CODA_960 = 0xf020, +}; + +struct coda_fmt { + char *name; + u32 fourcc; +}; + +struct coda_codec { + u32 mode; + u32 src_fourcc; + u32 dst_fourcc; + u32 max_w; + u32 max_h; +}; + +struct coda_devtype { + char *firmware; + enum coda_product product; + const struct coda_codec *codecs; + unsigned int num_codecs; + size_t workbuf_size; + size_t tempbuf_size; + size_t iram_size; +}; + +/* Per-queue, driver-specific private data */ +struct coda_q_data { + unsigned int width; + unsigned int height; + unsigned int bytesperline; + unsigned int sizeimage; + unsigned int fourcc; + struct v4l2_rect rect; +}; + +struct coda_aux_buf { + void *vaddr; + dma_addr_t paddr; + u32 size; + struct debugfs_blob_wrapper blob; + struct dentry *dentry; +}; + +struct coda_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd[2]; + struct platform_device *plat_dev; + const struct coda_devtype *devtype; + + void __iomem *regs_base; + struct clk *clk_per; + struct clk *clk_ahb; + struct reset_control *rstc; + + struct coda_aux_buf codebuf; + struct coda_aux_buf tempbuf; + struct coda_aux_buf workbuf; + struct gen_pool *iram_pool; + struct coda_aux_buf iram; + + spinlock_t irqlock; + struct mutex dev_mutex; + struct mutex coda_mutex; + struct workqueue_struct *workqueue; + struct v4l2_m2m_dev *m2m_dev; + struct vb2_alloc_ctx *alloc_ctx; + struct list_head instances; + unsigned long instance_mask; + struct dentry *debugfs_root; +}; + +struct coda_params { + u8 rot_mode; + u8 h264_intra_qp; + u8 h264_inter_qp; + u8 h264_min_qp; + u8 h264_max_qp; + u8 h264_deblk_enabled; + u8 h264_deblk_alpha; + u8 h264_deblk_beta; + u8 mpeg4_intra_qp; + u8 mpeg4_inter_qp; + u8 gop_size; + int intra_refresh; + int codec_mode; + int codec_mode_aux; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u32 framerate; + u16 bitrate; + u32 slice_max_bits; + u32 slice_max_mb; +}; + +struct coda_iram_info { + u32 axi_sram_use; + phys_addr_t buf_bit_use; + phys_addr_t buf_ip_ac_dc_use; + phys_addr_t buf_dbk_y_use; + phys_addr_t buf_dbk_c_use; + phys_addr_t buf_ovl_use; + phys_addr_t buf_btp_use; + phys_addr_t search_ram_paddr; + int search_ram_size; + int remaining; + phys_addr_t next_paddr; +}; + +struct gdi_tiled_map { + int xy2ca_map[16]; + int xy2ba_map[16]; + int xy2ra_map[16]; + int rbc2axi_map[32]; + int xy2rbc_config; + int map_type; +#define GDI_LINEAR_FRAME_MAP 0 +}; + +struct coda_timestamp { + struct list_head list; + u32 sequence; + struct v4l2_timecode timecode; + struct timeval timestamp; +}; + +struct coda_ctx { + struct coda_dev *dev; + struct mutex buffer_mutex; + struct list_head list; + struct work_struct pic_run_work; + struct work_struct seq_end_work; + struct completion completion; + int aborting; + int initialized; + int streamon_out; + int streamon_cap; + u32 isequence; + u32 qsequence; + u32 osequence; + u32 sequence_offset; + struct coda_q_data q_data[2]; + enum coda_inst_type inst_type; + const struct coda_codec *codec; + enum v4l2_colorspace colorspace; + struct coda_params params; + struct v4l2_ctrl_handler ctrls; + struct v4l2_fh fh; + int gopcounter; + int runcounter; + char vpu_header[3][64]; + int vpu_header_size[3]; + struct kfifo bitstream_fifo; + struct mutex bitstream_mutex; + struct coda_aux_buf bitstream; + bool hold; + struct coda_aux_buf parabuf; + struct coda_aux_buf psbuf; + struct coda_aux_buf slicebuf; + struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; + u32 frame_types[CODA_MAX_FRAMEBUFFERS]; + struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; + u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; + struct list_head timestamp_list; + struct coda_aux_buf workbuf; + int num_internal_frames; + int idx; + int reg_idx; + struct coda_iram_info iram_info; + struct gdi_tiled_map tiled_map; + u32 bit_stream_param; + u32 frm_dis_flg; + u32 frame_mem_ctrl; + int display_idx; + struct dentry *debugfs_entry; +}; + +static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; +static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; + +static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg) +{ + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + writel(data, dev->regs_base + reg); +} + +static inline unsigned int coda_read(struct coda_dev *dev, u32 reg) +{ + u32 data; + data = readl(dev->regs_base + reg); + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + return data; +} + +static inline unsigned long coda_isbusy(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_BUSY); +} + +static inline int coda_is_initialized(struct coda_dev *dev) +{ + return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); +} + +static int coda_wait_timeout(struct coda_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (coda_isbusy(dev)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + } + return 0; +} + +static void coda_command_async(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + if (dev->devtype->product == CODA_960 || + dev->devtype->product == CODA_7541) { + /* Restore context related registers to CODA */ + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + coda_write(dev, ctx->frame_mem_ctrl, + CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + } + + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + + coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); + + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); +} + +static int coda_command_sync(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + coda_command_async(ctx, cmd); + return coda_wait_timeout(dev); +} + +static int coda_hw_reset(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + unsigned long timeout; + unsigned int idx; + int ret; + + if (!dev->rstc) + return -ENOENT; + + idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); + + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } + } + + ret = reset_control_reset(dev->rstc); + if (ret < 0) + return ret; + + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + ret = coda_wait_timeout(dev); + coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); + + return ret; +} + +static struct coda_q_data *get_q_data(struct coda_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &(ctx->q_data[V4L2_M2M_SRC]); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &(ctx->q_data[V4L2_M2M_DST]); + default: + return NULL; + } +} + +/* + * Array of all formats supported by any version of Coda: + */ +static const struct coda_fmt coda_formats[] = { + { + .name = "YUV 4:2:0 Planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + }, + { + .name = "YUV 4:2:0 Planar, YCrCb", + .fourcc = V4L2_PIX_FMT_YVU420, + }, + { + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + }, + { + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + }, +}; + +#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ + { mode, src_fourcc, dst_fourcc, max_w, max_h } + +/* + * Arrays of codecs supported by each given version of Coda: + * i.MX27 -> codadx6 + * i.MX5x -> coda7 + * i.MX6 -> coda960 + * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants + */ +static const struct coda_codec codadx6_codecs[] = { + CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), +}; + +static const struct coda_codec coda7_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), + CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), +}; + +static const struct coda_codec coda9_codecs[] = { + CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), + CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), + CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), +}; + +static bool coda_format_is_yuv(u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + return true; + default: + return false; + } +} + +/* + * Normalize all supported YUV 4:2:0 formats to the value used in the codec + * tables. + */ +static u32 coda_format_normalize_yuv(u32 fourcc) +{ + return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; +} + +static const struct coda_codec *coda_find_codec(struct coda_dev *dev, + int src_fourcc, int dst_fourcc) +{ + const struct coda_codec *codecs = dev->devtype->codecs; + int num_codecs = dev->devtype->num_codecs; + int k; + + src_fourcc = coda_format_normalize_yuv(src_fourcc); + dst_fourcc = coda_format_normalize_yuv(dst_fourcc); + if (src_fourcc == dst_fourcc) + return NULL; + + for (k = 0; k < num_codecs; k++) { + if (codecs[k].src_fourcc == src_fourcc && + codecs[k].dst_fourcc == dst_fourcc) + break; + } + + if (k == num_codecs) + return NULL; + + return &codecs[k]; +} + +static void coda_get_max_dimensions(struct coda_dev *dev, + const struct coda_codec *codec, + int *max_w, int *max_h) +{ + const struct coda_codec *codecs = dev->devtype->codecs; + int num_codecs = dev->devtype->num_codecs; + unsigned int w, h; + int k; + + if (codec) { + w = codec->max_w; + h = codec->max_h; + } else { + for (k = 0, w = 0, h = 0; k < num_codecs; k++) { + w = max(w, codecs[k].max_w); + h = max(h, codecs[k].max_h); + } + } + + if (max_w) + *max_w = w; + if (max_h) + *max_h = h; +} + +static char *coda_product_name(int product) +{ + static char buf[9]; + + switch (product) { + case CODA_DX6: + return "CodaDx6"; + case CODA_7541: + return "CODA7541"; + case CODA_960: + return "CODA960"; + default: + snprintf(buf, sizeof(buf), "(0x%04x)", product); + return buf; + } +} + +/* + * V4L2 ioctl() operations. + */ +static int coda_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver)); + strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product), + sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int coda_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codecs = ctx->dev->devtype->codecs; + const struct coda_fmt *formats = coda_formats; + const struct coda_fmt *fmt; + int num_codecs = ctx->dev->devtype->num_codecs; + int num_formats = ARRAY_SIZE(coda_formats); + int i, k, num = 0; + bool yuv; + + if (ctx->inst_type == CODA_INST_ENCODER) + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); + else + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); + + for (i = 0; i < num_formats; i++) { + /* Skip either raw or compressed formats */ + if (yuv != coda_format_is_yuv(formats[i].fourcc)) + continue; + /* All uncompressed formats are always supported */ + if (yuv) { + if (num == f->index) + break; + ++num; + continue; + } + /* Compressed formats may be supported, check the codec list */ + for (k = 0; k < num_codecs; k++) { + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + formats[i].fourcc == codecs[k].dst_fourcc) + break; + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + formats[i].fourcc == codecs[k].src_fourcc) + break; + } + if (k < num_codecs) { + if (num == f->index) + break; + ++num; + } + } + + if (i < num_formats) { + fmt = &formats[i]; + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + if (!yuv) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + return 0; + } + + /* Format not found */ + return -EINVAL; +} + +static int coda_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_q_data *q_data; + struct coda_ctx *ctx = fh_to_ctx(priv); + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fourcc; + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.bytesperline = q_data->bytesperline; + + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + + return 0; +} + +static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, + struct v4l2_format *f) +{ + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data; + unsigned int max_w, max_h; + enum v4l2_field field; + + field = f->fmt.pix.field; + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (V4L2_FIELD_NONE != field) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + f->fmt.pix.field = field; + + coda_get_max_dimensions(dev, codec, &max_w, &max_h); + v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN, + &f->fmt.pix.height, MIN_H, max_h, H_ALIGN, + S_ALIGN); + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_MPEG4: + case V4L2_PIX_FMT_JPEG: + break; + default: + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + f->fmt.pix.pixelformat = q_data->fourcc; + } + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + /* Frame stride must be multiple of 8, but 16 for h.264 */ + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 3 / 2; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_MPEG4: + case V4L2_PIX_FMT_JPEG: + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE; + break; + default: + BUG(); + } + + return 0; +} + +static int coda_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codec = NULL; + struct vb2_queue *src_vq; + int ret; + + /* + * If the source format is already fixed, try to find a codec that + * converts to the given destination format + */ + src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (vb2_is_streaming(src_vq)) { + struct coda_q_data *q_data_src; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) + return -EINVAL; + + f->fmt.pix.width = q_data_src->width; + f->fmt.pix.height = q_data_src->height; + } else { + /* Otherwise determine codec by encoded format, if possible */ + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + f->fmt.pix.pixelformat); + } + + f->fmt.pix.colorspace = ctx->colorspace; + + ret = coda_try_fmt(ctx, codec, f); + if (ret < 0) + return ret; + + /* The h.264 decoder only returns complete 16x16 macroblocks */ + if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) { + f->fmt.pix.width = f->fmt.pix.width; + f->fmt.pix.height = round_up(f->fmt.pix.height, 16); + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 3 / 2; + } + + return 0; +} + +static int coda_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codec; + + /* Determine codec by encoded format, returns NULL if raw or invalid */ + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, + V4L2_PIX_FMT_YUV420); + if (!codec && ctx->inst_type == CODA_INST_DECODER) { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_YUV420); + if (!codec) + return -EINVAL; + } + + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + + return coda_try_fmt(ctx, codec, f); +} + +static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) +{ + struct coda_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fourcc = f->fmt.pix.pixelformat; + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->bytesperline = f->fmt.pix.bytesperline; + q_data->sizeimage = f->fmt.pix.sizeimage; + q_data->rect.left = 0; + q_data->rect.top = 0; + q_data->rect.width = f->fmt.pix.width; + q_data->rect.height = f->fmt.pix.height; + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Setting format for type %d, wxh: %dx%d, fmt: %d\n", + f->type, q_data->width, q_data->height, q_data->fourcc); + + return 0; +} + +static int coda_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = coda_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return coda_s_fmt(ctx, f); +} + +static int coda_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = coda_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = coda_s_fmt(ctx, f); + if (ret) + ctx->colorspace = f->fmt.pix.colorspace; + + return ret; +} + +static int coda_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); +} + +static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, + struct v4l2_buffer *buf) +{ + struct vb2_queue *src_vq; + + src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && + (buf->sequence == (ctx->qsequence - 1))); +} + +static int coda_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); + + /* If this is the last capture buffer, emit an end-of-stream event */ + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + coda_buf_is_end_of_stream(ctx, buf)) { + const struct v4l2_event eos_event = { + .type = V4L2_EVENT_EOS + }; + + v4l2_event_queue_fh(&ctx->fh, &eos_event); + } + + return ret; +} + +static int coda_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data; + struct v4l2_rect r, *rsel; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + r.left = 0; + r.top = 0; + r.width = q_data->width; + r.height = q_data->height; + rsel = &q_data->rect; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + rsel = &r; + /* fallthrough */ + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + rsel = &r; + /* fallthrough */ + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + default: + return -EINVAL; + } + + s->r = *rsel; + + return 0; +} + +static int coda_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + if (dc->cmd != V4L2_DEC_CMD_STOP) + return -EINVAL; + + if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) + return -EINVAL; + + if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) + return -EINVAL; + + return 0; +} + +static int coda_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_dev *dev = ctx->dev; + int ret; + + ret = coda_try_decoder_cmd(file, fh, dc); + if (ret < 0) + return ret; + + /* Ignore decoder stop command silently in encoder context */ + if (ctx->inst_type != CODA_INST_DECODER) + return 0; + + /* Set the strem-end flag on this context */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* If this context is currently running, update the hardware flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } + ctx->hold = false; + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + + return 0; +} + +static int coda_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, 0, NULL); + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static const struct v4l2_ioctl_ops coda_ioctl_ops = { + .vidioc_querycap = coda_querycap, + + .vidioc_enum_fmt_vid_cap = coda_enum_fmt, + .vidioc_g_fmt_vid_cap = coda_g_fmt, + .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = coda_enum_fmt, + .vidioc_g_fmt_vid_out = coda_g_fmt, + .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + + .vidioc_qbuf = coda_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = coda_dqbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = coda_g_selection, + + .vidioc_try_decoder_cmd = coda_try_decoder_cmd, + .vidioc_decoder_cmd = coda_decoder_cmd, + + .vidioc_subscribe_event = coda_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int coda_start_decoding(struct coda_ctx *ctx); + +static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) +{ + return kfifo_len(&ctx->bitstream_fifo); +} + +static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr; + + rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + kfifo->out = (kfifo->in & ~kfifo->mask) | + (rd_ptr - ctx->bitstream.paddr); + if (kfifo->out > kfifo->in) + kfifo->out -= kfifo->mask + 1; +} + +static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr, wr_ptr; + + rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); + coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr; + + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) +{ + u32 src_size = vb2_get_plane_payload(src_buf, 0); + u32 n; + + n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); + if (n < src_size) + return -ENOSPC; + + dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, + ctx->bitstream.size, DMA_TO_DEVICE); + + src_buf->v4l2_buf.sequence = ctx->qsequence++; + + return 0; +} + +static bool coda_bitstream_try_queue(struct coda_ctx *ctx, + struct vb2_buffer *src_buf) +{ + int ret; + + if (coda_get_bitstream_payload(ctx) + + vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) + return false; + + if (vb2_plane_vaddr(src_buf, 0) == NULL) { + v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); + return true; + } + + ret = coda_bitstream_queue(ctx, src_buf); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); + return false; + } + /* Sync read pointer to device */ + if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) + coda_kfifo_sync_to_device_write(ctx); + + ctx->hold = false; + + return true; +} + +static void coda_fill_bitstream(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf; + struct coda_timestamp *ts; + + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + + if (coda_bitstream_try_queue(ctx, src_buf)) { + /* + * Source buffer is queued in the bitstream ringbuffer; + * queue the timestamp and mark source buffer as done + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + + ts = kmalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + ts->sequence = src_buf->v4l2_buf.sequence; + ts->timecode = src_buf->v4l2_buf.timecode; + ts->timestamp = src_buf->v4l2_buf.timestamp; + list_add_tail(&ts->list, &ctx->timestamp_list); + } + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + break; + } + } +} + +static void coda_set_gdi_regs(struct coda_ctx *ctx) +{ + struct gdi_tiled_map *tiled_map = &ctx->tiled_map; + struct coda_dev *dev = ctx->dev; + int i; + + for (i = 0; i < 16; i++) + coda_write(dev, tiled_map->xy2ca_map[i], + CODA9_GDI_XY2_CAS_0 + 4 * i); + for (i = 0; i < 4; i++) + coda_write(dev, tiled_map->xy2ba_map[i], + CODA9_GDI_XY2_BA_0 + 4 * i); + for (i = 0; i < 16; i++) + coda_write(dev, tiled_map->xy2ra_map[i], + CODA9_GDI_XY2_RAS_0 + 4 * i); + coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); + for (i = 0; i < 32; i++) + coda_write(dev, tiled_map->rbc2axi_map[i], + CODA9_GDI_RBC2_AXI_0 + 4 * i); +} + +/* + * Mem-to-mem operations. + */ +static int coda_prepare_decode(struct coda_ctx *ctx) +{ + struct vb2_buffer *dst_buf; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_dst; + u32 stridey, height; + u32 picture_y, picture_cb, picture_cr; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + if (ctx->params.rot_mode & CODA_ROT_90) { + stridey = q_data_dst->height; + height = q_data_dst->width; + } else { + stridey = q_data_dst->width; + height = q_data_dst->height; + } + + /* Try to copy source buffer contents into the bitstream ringbuffer */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + + if (coda_get_bitstream_payload(ctx) < 512 && + (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "bitstream payload: %d, skipping\n", + coda_get_bitstream_payload(ctx)); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } + + /* Run coda_start_decoding (again) if not yet initialized */ + if (!ctx->initialized) { + int ret = coda_start_decoding(ctx); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } else { + ctx->initialized = 1; + } + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* Set rotator output */ + picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { + /* Switch Cr and Cb for YVU420 format */ + picture_cr = picture_y + stridey * height; + picture_cb = picture_cr + stridey / 2 * height / 2; + } else { + picture_cb = picture_y + stridey * height; + picture_cr = picture_cb + stridey / 2 * height / 2; + } + + if (dev->devtype->product == CODA_960) { + /* + * The CODA960 seems to have an internal list of buffers with + * 64 entries that includes the registered frame buffers as + * well as the rotator buffer output. + * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. + */ + coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, + CODA9_CMD_DEC_PIC_ROT_INDEX); + coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); + } else { + coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); + } + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, + CODA_CMD_DEC_PIC_ROT_MODE); + + switch (dev->devtype->product) { + case CODA_DX6: + /* TBD */ + case CODA_7541: + coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); + break; + case CODA_960: + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ + break; + } + + coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); + + coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); + coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + + return 0; +} + +static void coda_prepare_encode(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + int force_ipicture; + int quant_param = 0; + u32 picture_y, picture_cb, picture_cr; + u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 dst_fourcc; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + src_buf->v4l2_buf.sequence = ctx->osequence; + dst_buf->v4l2_buf.sequence = ctx->osequence; + ctx->osequence++; + + /* + * Workaround coda firmware BUG that only marks the first + * frame as IDR. This is a problem for some decoders that can't + * recover when a frame is lost. + */ + if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } else { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* + * Copy headers at the beginning of the first frame for H.264 only. + * In MPEG4 they are already copied by the coda. + */ + if (src_buf->v4l2_buf.sequence == 0) { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - + ctx->vpu_header_size[0] - + ctx->vpu_header_size[1] - + ctx->vpu_header_size[2]; + memcpy(vb2_plane_vaddr(dst_buf, 0), + &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], + &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1], &ctx->vpu_header[2][0], + ctx->vpu_header_size[2]); + } else { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; + } + + if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + force_ipicture = 1; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_intra_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_intra_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set intra qp, fmt not supported\n"); + break; + } + } else { + force_ipicture = 0; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_inter_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_inter_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set inter qp, fmt not supported\n"); + break; + } + } + + /* submit */ + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); + + + picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); + switch (q_data_src->fourcc) { + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + picture_cr = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cb = picture_cr + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + case V4L2_PIX_FMT_YUV420: + default: + picture_cb = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cr = picture_cb + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); + coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); + coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); + + coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); + } else { + coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); + } + coda_write(dev, force_ipicture << 1 & 0x2, + CODA_CMD_ENC_PIC_OPTION); + + coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); + coda_write(dev, pic_stream_buffer_size / 1024, + CODA_CMD_ENC_PIC_BB_SIZE); + + if (!ctx->streamon_out) { + /* After streamoff on the output side, set the stream end flag */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + +static void coda_device_run(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *dev = ctx->dev; + + queue_work(dev->workqueue, &ctx->pic_run_work); +} + +static void coda_free_framebuffers(struct coda_ctx *ctx); +static void coda_free_context_buffers(struct coda_ctx *ctx); + +static void coda_seq_end_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); + struct coda_dev *dev = ctx->dev; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_END failed\n"); + } + + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); + + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static void coda_finish_decode(struct coda_ctx *ctx); +static void coda_finish_encode(struct coda_ctx *ctx); + +static void coda_pic_run_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + if (ctx->inst_type == CODA_INST_DECODER) { + ret = coda_prepare_decode(ctx); + if (ret < 0) { + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); + /* job_finish scheduled by prepare_decode */ + return; + } + } else { + coda_prepare_encode(ctx); + } + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + if (ctx->inst_type == CODA_INST_DECODER) + coda_kfifo_sync_to_device_full(ctx); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { + dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); + + ctx->hold = true; + + coda_hw_reset(ctx); + } else if (!ctx->aborting) { + if (ctx->inst_type == CODA_INST_DECODER) + coda_finish_decode(ctx); + else + coda_finish_encode(ctx); + } + + if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) + queue_work(dev->workqueue, &ctx->seq_end_work); + + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); + + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); +} + +static int coda_job_ready(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + + /* + * For both 'P' and 'key' frame cases 1 picture + * and 1 frame are needed. In the decoder case, + * the compressed frame can be in the bitstream. + */ + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && + ctx->inst_type != CODA_INST_DECODER) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: not enough video buffers.\n"); + return 0; + } + + if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: not enough video capture buffers.\n"); + return 0; + } + + if (ctx->hold || + ((ctx->inst_type == CODA_INST_DECODER) && + (coda_get_bitstream_payload(ctx) < 512) && + !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: not enough bitstream data.\n", + ctx->idx); + return 0; + } + + if (ctx->aborting) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: aborting\n"); + return 0; + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "job ready\n"); + return 1; +} + +static void coda_job_abort(void *priv) +{ + struct coda_ctx *ctx = priv; + + ctx->aborting = 1; + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Aborting task\n"); +} + +static void coda_lock(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *pcdev = ctx->dev; + mutex_lock(&pcdev->dev_mutex); +} + +static void coda_unlock(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *pcdev = ctx->dev; + mutex_unlock(&pcdev->dev_mutex); +} + +static const struct v4l2_m2m_ops coda_m2m_ops = { + .device_run = coda_device_run, + .job_ready = coda_job_ready, + .job_abort = coda_job_abort, + .lock = coda_lock, + .unlock = coda_unlock, +}; + +static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) +{ + struct gdi_tiled_map *tiled_map = &ctx->tiled_map; + int luma_map, chro_map, i; + + memset(tiled_map, 0, sizeof(*tiled_map)); + + luma_map = 64; + chro_map = 64; + tiled_map->map_type = tiled_map_type; + for (i = 0; i < 16; i++) + tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map; + for (i = 0; i < 4; i++) + tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map; + for (i = 0; i < 16; i++) + tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map; + + if (tiled_map_type == GDI_LINEAR_FRAME_MAP) { + tiled_map->xy2rbc_config = 0; + } else { + dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n", + tiled_map_type); + return; + } +} + +static void set_default_params(struct coda_ctx *ctx) +{ + u32 src_fourcc, dst_fourcc; + int max_w; + int max_h; + + if (ctx->inst_type == CODA_INST_ENCODER) { + src_fourcc = V4L2_PIX_FMT_YUV420; + dst_fourcc = V4L2_PIX_FMT_H264; + } else { + src_fourcc = V4L2_PIX_FMT_H264; + dst_fourcc = V4L2_PIX_FMT_YUV420; + } + ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); + max_w = ctx->codec->max_w; + max_h = ctx->codec->max_h; + + ctx->params.codec_mode = ctx->codec->mode; + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->params.framerate = 30; + ctx->aborting = 0; + + /* Default formats for output and input queues */ + ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; + ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; + ctx->q_data[V4L2_M2M_SRC].width = max_w; + ctx->q_data[V4L2_M2M_SRC].height = max_h; + ctx->q_data[V4L2_M2M_DST].width = max_w; + ctx->q_data[V4L2_M2M_DST].height = max_h; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { + ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; + ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; + ctx->q_data[V4L2_M2M_DST].bytesperline = 0; + ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + } else { + ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; + ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; + ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2; + } + ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; + ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; + ctx->q_data[V4L2_M2M_DST].rect.width = max_w; + ctx->q_data[V4L2_M2M_DST].rect.height = max_h; + + if (ctx->dev->devtype->product == CODA_960) + coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); +} + +/* + * Queue operations + */ +static int coda_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vq); + struct coda_q_data *q_data; + unsigned int size; + + q_data = get_q_data(ctx, vq->type); + size = q_data->sizeimage; + + *nplanes = 1; + sizes[0] = size; + + alloc_ctxs[0] = ctx->dev->alloc_ctx; + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "get %d buffer(s) of size %d each.\n", *nbuffers, size); + + return 0; +} + +static int coda_buf_prepare(struct vb2_buffer *vb) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct coda_q_data *q_data; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + v4l2_warn(&ctx->dev->v4l2_dev, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; + } + + return 0; +} + +static void coda_buf_queue(struct vb2_buffer *vb) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + + /* + * In the decoder case, immediately try to copy the buffer into the + * bitstream ringbuffer and mark it as ready to be dequeued. + */ + if (q_data->fourcc == V4L2_PIX_FMT_H264 && + vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* + * For backwards compatibility, queuing an empty buffer marks + * the stream end + */ + if (vb2_get_plane_payload(vb, 0) == 0) { + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* if this decoder instance is running, set the stream end flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } + } + mutex_lock(&ctx->bitstream_mutex); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); + if (vb2_is_streaming(vb->vb2_queue)) + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + } else { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); + } +} + +static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) +{ + struct coda_dev *dev = ctx->dev; + u32 *p = ctx->parabuf.vaddr; + + if (dev->devtype->product == CODA_DX6) + p[index] = value; + else + p[index ^ 1] = value; +} + +static int coda_alloc_aux_buf(struct coda_dev *dev, + struct coda_aux_buf *buf, size_t size, + const char *name, struct dentry *parent) +{ + buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, + GFP_KERNEL); + if (!buf->vaddr) + return -ENOMEM; + + buf->size = size; + + if (name && parent) { + buf->blob.data = buf->vaddr; + buf->blob.size = size; + buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); + if (!buf->dentry) + dev_warn(&dev->plat_dev->dev, + "failed to create debugfs entry %s\n", name); + } + + return 0; +} + +static inline int coda_alloc_context_buf(struct coda_ctx *ctx, + struct coda_aux_buf *buf, size_t size, + const char *name) +{ + return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); +} + +static void coda_free_aux_buf(struct coda_dev *dev, + struct coda_aux_buf *buf) +{ + if (buf->vaddr) { + dma_free_coherent(&dev->plat_dev->dev, buf->size, + buf->vaddr, buf->paddr); + buf->vaddr = NULL; + buf->size = 0; + } + debugfs_remove(buf->dentry); +} + +static void coda_free_framebuffers(struct coda_ctx *ctx) +{ + int i; + + for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); +} + +static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc) +{ + struct coda_dev *dev = ctx->dev; + int width, height; + dma_addr_t paddr; + int ysize; + int ret; + int i; + + if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { + width = round_up(q_data->width, 16); + height = round_up(q_data->height, 16); + } else { + width = round_up(q_data->width, 8); + height = q_data->height; + } + ysize = width * height; + + /* Allocate frame buffers */ + for (i = 0; i < ctx->num_internal_frames; i++) { + size_t size; + char *name; + + size = ysize + ysize / 2; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + size += ysize / 4; + name = kasprintf(GFP_KERNEL, "fb%d", i); + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], + size, name); + kfree(name); + if (ret < 0) { + coda_free_framebuffers(ctx); + return ret; + } + } + + /* Register frame buffers in the parameter buffer */ + for (i = 0; i < ctx->num_internal_frames; i++) { + paddr = ctx->internal_frames[i].paddr; + coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ + coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ + coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ + + /* mvcol buffer for h.264 */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + coda_parabuf_write(ctx, 96 + i, + ctx->internal_frames[i].paddr + + ysize + ysize/4 + ysize/4); + } + + /* mvcol buffer for mpeg4 */ + if ((dev->devtype->product != CODA_DX6) && + (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) + coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + + ysize + ysize/4 + ysize/4); + + return 0; +} + +static int coda_h264_padding(int size, char *p) +{ + int nal_size; + int diff; + + diff = size - (size & ~0x7); + if (diff == 0) + return 0; + + nal_size = coda_filler_size[diff]; + memcpy(p, coda_filler_nal, nal_size); + + /* Add rbsp stop bit and trailing at the end */ + *(p + nal_size - 1) = 0x80; + + return nal_size; +} + +static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) +{ + phys_addr_t ret; + + size = round_up(size, 1024); + if (size > iram->remaining) + return 0; + iram->remaining -= size; + + ret = iram->next_paddr; + iram->next_paddr += size; + + return ret; +} + +static void coda_setup_iram(struct coda_ctx *ctx) +{ + struct coda_iram_info *iram_info = &ctx->iram_info; + struct coda_dev *dev = ctx->dev; + int mb_width; + int dbk_bits; + int bit_bits; + int ip_bits; + + memset(iram_info, 0, sizeof(*iram_info)); + iram_info->next_paddr = dev->iram.paddr; + iram_info->remaining = dev->iram.size; + + switch (dev->devtype->product) { + case CODA_7541: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + case CODA_960: + dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; + bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + default: /* CODA_DX6 */ + return; + } + + if (ctx->inst_type == CODA_INST_ENCODER) { + struct coda_q_data *q_data_src; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + mb_width = DIV_ROUND_UP(q_data_src->width, 16); + + /* Prioritize in case IRAM is too small for everything */ + if (dev->devtype->product == CODA_7541) { + iram_info->search_ram_size = round_up(mb_width * 16 * + 36 + 2048, 1024); + iram_info->search_ram_paddr = coda_iram_alloc(iram_info, + iram_info->search_ram_size); + if (!iram_info->search_ram_paddr) { + pr_err("IRAM is smaller than the search ram size\n"); + goto out; + } + iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | + CODA7_USE_ME_ENABLE; + } + + /* Only H.264BP and H.263P3 are considered */ + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP disabled for encoder */ + } else if (ctx->inst_type == CODA_INST_DECODER) { + struct coda_q_data *q_data_dst; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP unused as there is no VC1 support yet */ + } + +out: + if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "IRAM smaller than needed\n"); + + if (dev->devtype->product == CODA_7541) { + /* TODO - Enabling these causes picture errors on CODA7541 */ + if (ctx->inst_type == CODA_INST_DECODER) { + /* fw 1.4.50 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_IP_ENABLE); + } else { + /* fw 13.4.29 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_HOST_DBK_ENABLE | + CODA7_USE_IP_ENABLE | + CODA7_USE_DBK_ENABLE); + } + } +} + +static void coda_free_context_buffers(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + coda_free_aux_buf(dev, &ctx->slicebuf); + coda_free_aux_buf(dev, &ctx->psbuf); + if (dev->devtype->product != CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); +} + +static int coda_alloc_context_buffers(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + struct coda_dev *dev = ctx->dev; + size_t size; + int ret; + + if (dev->devtype->product == CODA_DX6) + return 0; + + if (ctx->psbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); + return -EBUSY; + } + if (ctx->slicebuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); + return -EBUSY; + } + if (ctx->workbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); + ret = -EBUSY; + return -ENOMEM; + } + + if (q_data->fourcc == V4L2_PIX_FMT_H264) { + /* worst case slice size */ + size = (DIV_ROUND_UP(q_data->width, 16) * + DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", + ctx->slicebuf.size); + return ret; + } + } + + if (dev->devtype->product == CODA_7541) { + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); + goto err; + } + } + + size = dev->devtype->workbuf_size; + if (dev->devtype->product == CODA_960 && + q_data->fourcc == V4L2_PIX_FMT_H264) + size += CODA9_PS_SAVE_SIZE; + ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", + ctx->workbuf.size); + goto err; + } + + return 0; + +err: + coda_free_context_buffers(ctx); + return ret; +} + +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct coda_dev *dev = ctx->dev; + int width, height; + u32 src_fourcc; + u32 val; + int ret; + + /* Start decoding */ + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + bitstream_buf = ctx->bitstream.paddr; + bitstream_size = ctx->bitstream.size; + src_fourcc = q_data_src->fourcc; + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + + /* Update coda bitstream read and write pointers from kfifo */ + coda_kfifo_sync_to_device_full(ctx); + + ctx->display_idx = -1; + ctx->frm_dis_flg = 0; + coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, + CODA_REG_BIT_BIT_STREAM_PARAM); + + coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); + val = 0; + if ((dev->devtype->product == CODA_7541) || + (dev->devtype->product == CODA_960)) + val |= CODA_REORDER_ENABLE; + coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); + + ctx->params.codec_mode = ctx->codec->mode; + if (dev->devtype->product == CODA_960 && + src_fourcc == V4L2_PIX_FMT_MPEG4) + ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; + else + ctx->params.codec_mode_aux = 0; + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (dev->devtype->product == CODA_7541) { + coda_write(dev, ctx->psbuf.paddr, + CODA_CMD_DEC_SEQ_PS_BB_START); + coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), + CODA_CMD_DEC_SEQ_PS_BB_SIZE); + } + if (dev->devtype->product == CODA_960) { + coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); + coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); + } + } + if (dev->devtype->product != CODA_960) { + coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + return -ETIMEDOUT; + } + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + + if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", + coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); + return -EAGAIN; + } + + val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); + if (dev->devtype->product == CODA_DX6) { + width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; + height = val & CODADX6_PICHEIGHT_MASK; + } else { + width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; + height = val & CODA7_PICHEIGHT_MASK; + } + + if (width > q_data_dst->width || height > q_data_dst->height) { + v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", + width, height, q_data_dst->width, q_data_dst->height); + return -EINVAL; + } + + width = round_up(width, 16); + height = round_up(height, 16); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", + __func__, ctx->idx, width, height); + + ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); + if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { + v4l2_err(&dev->v4l2_dev, + "not enough framebuffers to decode (%d < %d)\n", + CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); + return -EINVAL; + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); + + q_data_dst->rect.left = (left_right >> 10) & 0x3ff; + q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; + q_data_dst->rect.width = width - q_data_dst->rect.left - + (left_right & 0x3ff); + q_data_dst->rect.height = height - q_data_dst->rect.top - + (top_bottom & 0x3ff); + } + + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); + if (ret < 0) + return ret; + + /* Tell the decoder how many frame buffers we allocated. */ + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); + + if (dev->devtype->product != CODA_DX6) { + /* Set secondary AXI IRAM */ + coda_setup_iram(ctx); + + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + + coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); + coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | + 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, + CODA9_CMD_SET_FRAME_CACHE_CONFIG); + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + coda_write(dev, ctx->slicebuf.paddr, + CODA_CMD_SET_FRAME_SLICE_BB_START); + coda_write(dev, ctx->slicebuf.size / 1024, + CODA_CMD_SET_FRAME_SLICE_BB_SIZE); + } + + if (dev->devtype->product == CODA_7541) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); + } else if (dev->devtype->product == CODA_960) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { + v4l2_err(&ctx->dev->v4l2_dev, + "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, + int header_code, u8 *header, int *size) +{ + struct coda_dev *dev = ctx->dev; + size_t bufsize; + int ret; + int i; + + if (dev->devtype->product == CODA_960) + memset(vb2_plane_vaddr(buf, 0), 0, 64); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), + CODA_CMD_ENC_HEADER_BB_START); + bufsize = vb2_plane_size(buf, 0); + if (dev->devtype->product == CODA_960) + bufsize /= 1024; + coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); + ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return ret; + } + + if (dev->devtype->product == CODA_960) { + for (i = 63; i > 0; i--) + if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) + break; + *size = i + 1; + } else { + *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + } + memcpy(header, vb2_plane_vaddr(buf, 0), *size); + + return 0; +} + +static int coda_start_encoding(struct coda_ctx *ctx); + +static int coda_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 dst_fourcc; + int ret = 0; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { + /* copy the buffers that where queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + + if (coda_get_bitstream_payload(ctx) < 512) + return -EINVAL; + } else { + if (count < 1) + return -EINVAL; + } + + ctx->streamon_out = 1; + } else { + if (count < 1) + return -EINVAL; + + ctx->streamon_cap = 1; + } + + /* Don't start the coda unless both queues are on */ + if (!(ctx->streamon_out & ctx->streamon_cap)) + return 0; + + /* Allow decoder device_run with no new buffers queued */ + if (ctx->inst_type == CODA_INST_DECODER) + v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); + + ctx->gopcounter = ctx->params.gop_size - 1; + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + q_data_dst->fourcc); + if (!ctx->codec) { + v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); + return -EINVAL; + } + + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + + if (ctx->inst_type == CODA_INST_DECODER) { + mutex_lock(&dev->coda_mutex); + ret = coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + if (ret == -EAGAIN) + return 0; + else if (ret < 0) + return ret; + } else { + ret = coda_start_encoding(ctx); + } + + ctx->initialized = 1; + return ret; +} + +static int coda_start_encoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct vb2_buffer *buf; + int gamma, ret, value; + u32 dst_fourcc; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); + bitstream_size = q_data_dst->sizeimage; + + if (!coda_is_initialized(dev)) { + v4l2_err(v4l2_dev, "coda is not initialized.\n"); + return -EFAULT; + } + + mutex_lock(&dev->coda_mutex); + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | + CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + case CODA_960: + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + /* fallthrough */ + case CODA_7541: + coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | + CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + } + + value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); + value &= ~(1 << 2 | 0x7 << 9); + ctx->frame_mem_ctrl = value; + coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product == CODA_DX6) { + /* Configure the coda */ + coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + } + + /* Could set rotation here if needed */ + switch (dev->devtype->product) { + case CODA_DX6: + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + case CODA_7541: + if (dst_fourcc == V4L2_PIX_FMT_H264) { + value = (round_up(q_data_src->width, 16) & + CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (round_up(q_data_src->height, 16) & + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + } + /* fallthrough */ + case CODA_960: + value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_SEQ_SRC_F_RATE); + + ctx->params.codec_mode = ctx->codec->mode; + switch (dst_fourcc) { + case V4L2_PIX_FMT_MPEG4: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); + break; + case V4L2_PIX_FMT_H264: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + if (ctx->params.h264_deblk_enabled) { + value = ((ctx->params.h264_deblk_alpha & + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | + ((ctx->params.h264_deblk_beta & + CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); + } else { + value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); + break; + default: + v4l2_err(v4l2_dev, + "dst format (0x%08x) invalid.\n", dst_fourcc); + ret = -EINVAL; + goto out; + } + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + value = 0; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); + + if (ctx->params.bitrate) { + /* Rate control enabled */ + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + if (dev->devtype->product == CODA_960) + value |= BIT(31); /* disable autoskip */ + } else { + value = 0; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_SEQ_INTRA_REFRESH); + + coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); + + + value = 0; + if (dev->devtype->product == CODA_960) + gamma = CODA9_DEFAULT_GAMMA; + else + gamma = CODA_DEFAULT_GAMMA; + if (gamma > 0) { + coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, + CODA_CMD_ENC_SEQ_RC_GAMMA); + } + + if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { + coda_write(dev, + ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | + ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, + CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); + } + if (dev->devtype->product == CODA_960) { + if (ctx->params.h264_max_qp) + value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; + if (CODA_DEFAULT_GAMMA > 0) + value |= 1 << CODA9_OPTION_GAMMA_OFFSET; + } else { + if (CODA_DEFAULT_GAMMA > 0) { + if (dev->devtype->product == CODA_DX6) + value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; + else + value |= 1 << CODA7_OPTION_GAMMA_OFFSET; + } + if (ctx->params.h264_min_qp) + value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; + if (ctx->params.h264_max_qp) + value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); + + coda_setup_iram(ctx); + + if (dst_fourcc == V4L2_PIX_FMT_H264) { + switch (dev->devtype->product) { + case CODA_DX6: + value = FMO_SLICE_SAVE_BUF_SIZE << 7; + coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); + break; + case CODA_7541: + coda_write(dev, ctx->iram_info.search_ram_paddr, + CODA7_CMD_ENC_SEQ_SEARCH_BASE); + coda_write(dev, ctx->iram_info.search_ram_size, + CODA7_CMD_ENC_SEQ_SEARCH_SIZE); + break; + case CODA_960: + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + goto out; + } + + if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); + ret = -EFAULT; + goto out; + } + + if (dev->devtype->product == CODA_960) + ctx->num_internal_frames = 4; + else + ctx->num_internal_frames = 2; + ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); + goto out; + } + + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, q_data_src->bytesperline, + CODA_CMD_SET_FRAME_BUF_STRIDE); + if (dev->devtype->product == CODA_7541) { + coda_write(dev, q_data_src->bytesperline, + CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); + } + if (dev->devtype->product != CODA_DX6) { + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) { + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + + /* FIXME */ + coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + goto out; + } + + /* Save stream headers */ + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + /* + * Get SPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + /* + * Get PPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + /* + * Length of H.264 headers is variable and thus it might not be + * aligned for the coda to append the encoded frame. In that is + * the case a filler NAL must be added to header 2. + */ + ctx->vpu_header_size[2] = coda_h264_padding( + (ctx->vpu_header_size[0] + + ctx->vpu_header_size[1]), + ctx->vpu_header[2]); + break; + case V4L2_PIX_FMT_MPEG4: + /* + * Get VOS in the first frame and copy it to an + * intermediate buffer + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, + &ctx->vpu_header[2][0], + &ctx->vpu_header_size[2]); + if (ret < 0) + goto out; + break; + default: + /* No more formats need to save headers at the moment */ + break; + } + +out: + mutex_unlock(&dev->coda_mutex); + return ret; +} + +static void coda_stop_streaming(struct vb2_queue *q) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct coda_dev *dev = ctx->dev; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: output\n", __func__); + ctx->streamon_out = 0; + + if (ctx->inst_type == CODA_INST_DECODER && + coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) { + /* if this decoder instance is running, set the stream end flag */ + if (dev->devtype->product == CODA_960) { + u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM); + + val |= CODA_BIT_STREAM_END_FLAG; + coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM); + ctx->bit_stream_param = val; + } + } + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + ctx->isequence = 0; + } else { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: capture\n", __func__); + ctx->streamon_cap = 0; + + ctx->osequence = 0; + ctx->sequence_offset = 0; + } + + if (!ctx->streamon_out && !ctx->streamon_cap) { + struct coda_timestamp *ts; + + while (!list_empty(&ctx->timestamp_list)) { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + kfree(ts); + } + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + ctx->runcounter = 0; + } +} + +static const struct vb2_ops coda_qops = { + .queue_setup = coda_queue_setup, + .buf_prepare = coda_buf_prepare, + .buf_queue = coda_buf_queue, + .start_streaming = coda_start_streaming, + .stop_streaming = coda_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int coda_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct coda_ctx *ctx = + container_of(ctrl->handler, struct coda_ctx, ctrls); + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + if (ctrl->val) + ctx->params.rot_mode |= CODA_MIR_HOR; + else + ctx->params.rot_mode &= ~CODA_MIR_HOR; + break; + case V4L2_CID_VFLIP: + if (ctrl->val) + ctx->params.rot_mode |= CODA_MIR_VER; + else + ctx->params.rot_mode &= ~CODA_MIR_VER; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctx->params.bitrate = ctrl->val / 1000; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctx->params.gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + ctx->params.h264_intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + ctx->params.h264_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + ctx->params.h264_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + ctx->params.h264_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + ctx->params.h264_deblk_alpha = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + ctx->params.h264_deblk_beta = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + ctx->params.h264_deblk_enabled = (ctrl->val == + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: + ctx->params.mpeg4_intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: + ctx->params.mpeg4_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + ctx->params.slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + ctx->params.slice_max_mb = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + ctx->params.slice_max_bits = ctrl->val * 8; + break; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + break; + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: + ctx->params.intra_refresh = ctrl->val; + break; + default: + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops coda_ctrl_ops = { + .s_ctrl = coda_s_ctrl, +}; + +static int coda_ctrls_setup(struct coda_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrls, 9); + + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25); + if (ctx->dev->devtype->product != CODA_960) { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12); + } + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + + if (ctx->ctrls.error) { + v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)", + ctx->ctrls.error); + return -EINVAL; + } + + return v4l2_ctrl_handler_setup(&ctx->ctrls); +} + +static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) +{ + vq->drv_priv = ctx; + vq->ops = &coda_qops; + vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + vq->lock = &ctx->dev->dev_mutex; + + return vb2_queue_init(vq); +} + +static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); +} + +static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); +} + +static int coda_next_free_instance(struct coda_dev *dev) +{ + int idx = ffz(dev->instance_mask); + + if ((idx < 0) || + (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES)) + return -EBUSY; + + return idx; +} + +static int coda_open(struct file *file, enum coda_inst_type inst_type) +{ + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + struct coda_dev *dev = video_drvdata(file); + struct coda_ctx *ctx = NULL; + char *name; + int ret; + int idx; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + idx = coda_next_free_instance(dev); + if (idx < 0) { + ret = idx; + goto err_coda_max; + } + set_bit(idx, &dev->instance_mask); + + name = kasprintf(GFP_KERNEL, "context%d", idx); + ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); + kfree(name); + + ctx->inst_type = inst_type; + init_completion(&ctx->completion); + INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); + INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->dev = dev; + ctx->idx = idx; + switch (dev->devtype->product) { + case CODA_7541: + case CODA_960: + ctx->reg_idx = 0; + break; + default: + ctx->reg_idx = idx; + } + + /* Power up and upload firmware if necessary */ + ret = pm_runtime_get_sync(&dev->plat_dev->dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); + goto err_pm_get; + } + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + set_default_params(ctx); + if (inst_type == CODA_INST_ENCODER) + queue_init = coda_encoder_queue_init; + else + queue_init = coda_decoder_queue_init; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + + v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", + __func__, ret); + goto err_ctx_init; + } + + ret = coda_ctrls_setup(ctx); + if (ret) { + v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); + goto err_ctrls_setup; + } + + ctx->fh.ctrl_handler = &ctx->ctrls; + + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE, + "parabuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); + goto err_dma_alloc; + } + + ctx->bitstream.size = CODA_MAX_FRAME_SIZE; + ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev, + ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); + if (!ctx->bitstream.vaddr) { + v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer"); + ret = -ENOMEM; + goto err_dma_writecombine; + } + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + mutex_init(&ctx->bitstream_mutex); + mutex_init(&ctx->buffer_mutex); + INIT_LIST_HEAD(&ctx->timestamp_list); + + coda_lock(ctx); + list_add(&ctx->list, &dev->instances); + coda_unlock(ctx); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n", + ctx->idx, ctx); + + return 0; + +err_dma_writecombine: + coda_free_context_buffers(ctx); + if (ctx->dev->devtype->product == CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); + coda_free_aux_buf(dev, &ctx->parabuf); +err_dma_alloc: + v4l2_ctrl_handler_free(&ctx->ctrls); +err_ctrls_setup: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); +err_ctx_init: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + pm_runtime_put_sync(&dev->plat_dev->dev); +err_pm_get: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + clear_bit(ctx->idx, &dev->instance_mask); +err_coda_max: + kfree(ctx); + return ret; +} + +static int coda_encoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_ENCODER); +} + +static int coda_decoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_DECODER); +} + +static int coda_release(struct file *file) +{ + struct coda_dev *dev = video_drvdata(file); + struct coda_ctx *ctx = fh_to_ctx(file->private_data); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", + ctx); + + debugfs_remove_recursive(ctx->debugfs_entry); + + /* If this instance is running, call .job_abort and wait for it to end */ + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + /* In case the instance was not running, we still need to call SEQ_END */ + if (ctx->initialized) { + queue_work(dev->workqueue, &ctx->seq_end_work); + flush_work(&ctx->seq_end_work); + } + + coda_free_framebuffers(ctx); + + coda_lock(ctx); + list_del(&ctx->list); + coda_unlock(ctx); + + dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, + ctx->bitstream.vaddr, ctx->bitstream.paddr); + coda_free_context_buffers(ctx); + if (ctx->dev->devtype->product == CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); + + coda_free_aux_buf(dev, &ctx->parabuf); + v4l2_ctrl_handler_free(&ctx->ctrls); + clk_disable_unprepare(dev->clk_ahb); + clk_disable_unprepare(dev->clk_per); + pm_runtime_put_sync(&dev->plat_dev->dev); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + clear_bit(ctx->idx, &dev->instance_mask); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations coda_encoder_fops = { + .owner = THIS_MODULE, + .open = coda_encoder_open, + .release = coda_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct v4l2_file_operations coda_decoder_fops = { + .owner = THIS_MODULE, + .open = coda_decoder_open, + .release = coda_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static void coda_finish_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src; + struct coda_q_data *q_data_dst; + struct vb2_buffer *dst_buf; + struct coda_timestamp *ts; + int width, height; + int decoded_idx; + int display_idx; + u32 src_fourcc; + int success; + u32 err_mb; + u32 val; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + /* + * in stream-end mode, the read pointer can overshoot the write pointer + * by up to 512 bytes + */ + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { + if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_fourcc = q_data_src->fourcc; + + val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); + if (val != 1) + pr_err("DEC_PIC_SUCCESS = %d\n", val); + + success = val & 0x1; + if (!success) + v4l2_err(&dev->v4l2_dev, "decode failed\n"); + + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (val & (1 << 3)) + v4l2_err(&dev->v4l2_dev, + "insufficient PS buffer space (%d bytes)\n", + ctx->psbuf.size); + if (val & (1 << 2)) + v4l2_err(&dev->v4l2_dev, + "insufficient slice buffer space (%d bytes)\n", + ctx->slicebuf.size); + } + + val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); + width = (val >> 16) & 0xffff; + height = val & 0xffff; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* frame crop information */ + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); + + if (left_right == 0xffffffff && top_bottom == 0xffffffff) { + /* Keep current crop information */ + } else { + struct v4l2_rect *rect = &q_data_dst->rect; + + rect->left = left_right >> 16 & 0xffff; + rect->top = top_bottom >> 16 & 0xffff; + rect->width = width - rect->left - + (left_right & 0xffff); + rect->height = height - rect->top - + (top_bottom & 0xffff); + } + } else { + /* no cropping */ + } + + err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); + if (err_mb > 0) + v4l2_err(&dev->v4l2_dev, + "errors in %d macroblocks\n", err_mb); + + if (dev->devtype->product == CODA_7541) { + val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); + if (val == 0) { + /* not enough bitstream data */ + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "prescan failed: %d\n", val); + ctx->hold = true; + return; + } + } + + ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + /* + * The previous display frame was copied out by the rotator, + * now it can be overwritten again + */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + ctx->frm_dis_flg &= ~(1 << ctx->display_idx); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + } + + /* + * The index of the last decoded frame, not necessarily in + * display order, and the index of the next display frame. + * The latter could have been decoded in a previous run. + */ + decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); + display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); + + if (decoded_idx == -1) { + /* no frame was decoded, but we might have a display frame */ + if (display_idx >= 0 && display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; + else if (ctx->display_idx < 0) + ctx->hold = true; + } else if (decoded_idx == -2) { + /* no frame was decoded, we still return the remaining buffers */ + } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "decoded frame index out of range: %d\n", decoded_idx); + } else { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + val -= ctx->sequence_offset; + if (val != (ts->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + val, ctx->sequence_offset, ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; + if (val == 0) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; + else if (val == 1) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; + else + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; + + ctx->frame_errors[decoded_idx] = err_mb; + } + + if (display_idx == -1) { + /* + * no more frames to be decoded, but there could still + * be rotator output to dequeue + */ + ctx->hold = true; + } else if (display_idx == -3) { + /* possibly prescan failure */ + } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "presentation frame index out of range: %d\n", + display_idx); + } + + /* If a frame was copied out, return it */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->v4l2_buf.sequence = ctx->osequence++; + + dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME); + dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; + ts = &ctx->frame_timestamps[ctx->display_idx]; + dst_buf->v4l2_buf.timecode = ts->timecode; + dst_buf->v4l2_buf.timestamp = ts->timestamp; + + vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); + + v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: decoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); + } else { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: no frame decoded\n"); + } + + /* The rotator will copy the current display frame next time */ + ctx->display_idx = display_idx; +} + +static void coda_finish_encode(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr, start_ptr; + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Get results from the coda */ + start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); + wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + + /* Calculate bytesused field */ + if (dst_buf->v4l2_buf.sequence == 0) { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]); + } else { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", + wr_ptr - start_ptr); + + coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); + coda_read(dev, CODA_RET_ENC_PIC_FLAG); + + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } else { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } + + dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.flags |= + src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + ctx->gopcounter--; + if (ctx->gopcounter < 0) + ctx->gopcounter = ctx->params.gop_size - 1; + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: encoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); +} + +static irqreturn_t coda_irq_handler(int irq, void *data) +{ + struct coda_dev *dev = data; + struct coda_ctx *ctx; + + /* read status register to attend the IRQ */ + coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, + CODA_REG_BIT_INT_CLEAR); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (ctx == NULL) { + v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + mutex_unlock(&dev->coda_mutex); + return IRQ_HANDLED; + } + + if (ctx->aborting) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "task has been aborted\n"); + } + + if (coda_isbusy(ctx->dev)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "coda is still busy!!!!\n"); + return IRQ_NONE; + } + + complete(&ctx->completion); + + return IRQ_HANDLED; +} + +static u32 coda_supported_firmwares[] = { + CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), +}; + +static bool coda_firmware_supported(u32 vernum) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) + if (vernum == coda_supported_firmwares[i]) + return true; + return false; +} + +static int coda_hw_init(struct coda_dev *dev) +{ + u32 data; + u16 *p; + int i, ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + if (dev->rstc) + reset_control_reset(dev->rstc); + + /* + * Copy the first CODA_ISRAM_SIZE in the internal SRAM. + * The 16-bit chars in the code buffer are in memory access + * order, re-sort them to CODA order for register download. + * Data in this SRAM survives a reboot. + */ + p = (u16 *)dev->codebuf.vaddr; + if (dev->devtype->product == CODA_DX6) { + for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { + data = CODA_DOWN_ADDRESS_SET(i) | + CODA_DOWN_DATA_SET(p[i ^ 1]); + coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); + } + } else { + for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { + data = CODA_DOWN_ADDRESS_SET(i) | + CODA_DOWN_DATA_SET(p[round_down(i, 4) + + 3 - (i % 4)]); + coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); + } + } + + /* Clear registers */ + for (i = 0; i < 64; i++) + coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4); + + /* Tell the BIT where to find everything it needs */ + if (dev->devtype->product == CODA_960 || + dev->devtype->product == CODA_7541) { + coda_write(dev, dev->tempbuf.paddr, + CODA_REG_BIT_TEMP_BUF_ADDR); + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + } else { + coda_write(dev, dev->workbuf.paddr, + CODA_REG_BIT_WORK_BUF_ADDR); + } + coda_write(dev, dev->codebuf.paddr, + CODA_REG_BIT_CODE_BUF_ADDR); + coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); + + /* Set default values */ + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + break; + default: + coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + } + if (dev->devtype->product == CODA_960) + coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL); + else + coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE); + + coda_write(dev, CODA_INT_INTERRUPT_ENABLE, + CODA_REG_BIT_INT_ENABLE); + + /* Reset VPU and start processor */ + data = coda_read(dev, CODA_REG_BIT_CODE_RESET); + data |= CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + udelay(10); + data &= ~CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + + clk_disable_unprepare(dev->clk_ahb); + clk_disable_unprepare(dev->clk_per); + + return 0; + +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +static int coda_check_firmware(struct coda_dev *dev) +{ + u16 product, major, minor, release; + u32 data; + int ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); + if (coda_wait_timeout(dev)) { + v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); + ret = -EIO; + goto err_run_cmd; + } + + if (dev->devtype->product == CODA_960) { + data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); + v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", + data); + } + + /* Check we are compatible with the loaded firmware */ + data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); + product = CODA_FIRMWARE_PRODUCT(data); + major = CODA_FIRMWARE_MAJOR(data); + minor = CODA_FIRMWARE_MINOR(data); + release = CODA_FIRMWARE_RELEASE(data); + + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + + if (product != dev->devtype->product) { + v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," + " Version: %u.%u.%u\n", + coda_product_name(dev->devtype->product), + coda_product_name(product), major, minor, release); + return -EINVAL; + } + + v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", + coda_product_name(product)); + + if (coda_firmware_supported(data)) { + v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", + major, minor, release); + } else { + v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " + "%u.%u.%u\n", major, minor, release); + } + + return 0; + +err_run_cmd: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) +{ + vfd->release = video_device_release_empty, + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + video_set_drvdata(vfd, dev); + + return video_register_device(vfd, VFL_TYPE_GRABBER, 0); +} + +static void coda_fw_callback(const struct firmware *fw, void *context) +{ + struct coda_dev *dev = context; + struct platform_device *pdev = dev->plat_dev; + int ret; + + if (!fw) { + v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); + return; + } + + /* allocate auxiliary per-device code buffer for the BIT processor */ + ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", + dev->debugfs_root); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate code buffer\n"); + return; + } + + /* Copy the whole firmware image to the code buffer */ + memcpy(dev->codebuf.vaddr, fw->data, fw->size); + release_firmware(fw); + + if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) { + /* + * Enabling power temporarily will cause coda_hw_init to be + * called via coda_runtime_resume by the pm domain. + */ + ret = pm_runtime_get_sync(&dev->plat_dev->dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n", + ret); + return; + } + + ret = coda_check_firmware(dev); + if (ret < 0) + return; + + pm_runtime_put_sync(&dev->plat_dev->dev); + } else { + /* + * If runtime pm is disabled or pm_domain is not set, + * initialize once manually. + */ + ret = coda_hw_init(dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); + return; + } + + ret = coda_check_firmware(dev); + if (ret < 0) + return; + } + + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(dev->alloc_ctx)) { + v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); + return; + } + + dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + goto rel_ctx; + } + + dev->vfd[0].fops = &coda_encoder_fops, + dev->vfd[0].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); + ret = coda_register_device(dev, &dev->vfd[0]); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register encoder video device\n"); + goto rel_m2m; + } + + dev->vfd[1].fops = &coda_decoder_fops, + dev->vfd[1].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); + ret = coda_register_device(dev, &dev->vfd[1]); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register decoder video device\n"); + goto rel_m2m; + } + + v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", + dev->vfd[0].num, dev->vfd[1].num); + + return; + +rel_m2m: + v4l2_m2m_release(dev->m2m_dev); +rel_ctx: + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); +} + +static int coda_firmware_request(struct coda_dev *dev) +{ + char *fw = dev->devtype->firmware; + + dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, + coda_product_name(dev->devtype->product)); + + return request_firmware_nowait(THIS_MODULE, true, + fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback); +} + +enum coda_platform { + CODA_IMX27, + CODA_IMX53, + CODA_IMX6Q, + CODA_IMX6DL, +}; + +static const struct coda_devtype coda_devdata[] = { + [CODA_IMX27] = { + .firmware = "v4l-codadx6-imx27.bin", + .product = CODA_DX6, + .codecs = codadx6_codecs, + .num_codecs = ARRAY_SIZE(codadx6_codecs), + .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, + .iram_size = 0xb000, + }, + [CODA_IMX53] = { + .firmware = "v4l-coda7541-imx53.bin", + .product = CODA_7541, + .codecs = coda7_codecs, + .num_codecs = ARRAY_SIZE(coda7_codecs), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, + [CODA_IMX6Q] = { + .firmware = "v4l-coda960-imx6q.bin", + .product = CODA_960, + .codecs = coda9_codecs, + .num_codecs = ARRAY_SIZE(coda9_codecs), + .workbuf_size = 80 * 1024, + .tempbuf_size = 204 * 1024, + .iram_size = 0x21000, + }, + [CODA_IMX6DL] = { + .firmware = "v4l-coda960-imx6dl.bin", + .product = CODA_960, + .codecs = coda9_codecs, + .num_codecs = ARRAY_SIZE(coda9_codecs), + .workbuf_size = 80 * 1024, + .tempbuf_size = 204 * 1024, + .iram_size = 0x20000, + }, +}; + +static struct platform_device_id coda_platform_ids[] = { + { .name = "coda-imx27", .driver_data = CODA_IMX27 }, + { .name = "coda-imx53", .driver_data = CODA_IMX53 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, coda_platform_ids); + +#ifdef CONFIG_OF +static const struct of_device_id coda_dt_ids[] = { + { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, + { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, + { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, + { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, coda_dt_ids); +#endif + +static int coda_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev); + const struct platform_device_id *pdev_id; + struct coda_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + struct gen_pool *pool; + struct coda_dev *dev; + struct resource *res; + int ret, irq; + + dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Not enough memory for %s\n", + CODA_NAME); + return -ENOMEM; + } + + spin_lock_init(&dev->irqlock); + INIT_LIST_HEAD(&dev->instances); + + dev->plat_dev = pdev; + dev->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(dev->clk_per)) { + dev_err(&pdev->dev, "Could not get per clock\n"); + return PTR_ERR(dev->clk_per); + } + + dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(dev->clk_ahb)) { + dev_err(&pdev->dev, "Could not get ahb clock\n"); + return PTR_ERR(dev->clk_ahb); + } + + /* Get memory for physical registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->regs_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dev->regs_base)) + return PTR_ERR(dev->regs_base); + + /* IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + return irq; + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler, + IRQF_ONESHOT, dev_name(&pdev->dev), dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + return ret; + } + + dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); + if (IS_ERR(dev->rstc)) { + ret = PTR_ERR(dev->rstc); + if (ret == -ENOENT || ret == -ENOSYS) { + dev->rstc = NULL; + } else { + dev_err(&pdev->dev, "failed get reset control: %d\n", ret); + return ret; + } + } + + /* Get IRAM pool from device tree or platform data */ + pool = of_get_named_gen_pool(np, "iram", 0); + if (!pool && pdata) + pool = dev_get_gen_pool(pdata->iram_dev); + if (!pool) { + dev_err(&pdev->dev, "iram pool not available\n"); + return -ENOMEM; + } + dev->iram_pool = pool; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + return ret; + + mutex_init(&dev->dev_mutex); + mutex_init(&dev->coda_mutex); + + pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); + + if (of_id) { + dev->devtype = of_id->data; + } else if (pdev_id) { + dev->devtype = &coda_devdata[pdev_id->driver_data]; + } else { + v4l2_device_unregister(&dev->v4l2_dev); + return -EINVAL; + } + + dev->debugfs_root = debugfs_create_dir("coda", NULL); + if (!dev->debugfs_root) + dev_warn(&pdev->dev, "failed to create debugfs root\n"); + + /* allocate auxiliary per-device buffers for the BIT processor */ + if (dev->devtype->product == CODA_DX6) { + ret = coda_alloc_aux_buf(dev, &dev->workbuf, + dev->devtype->workbuf_size, "workbuf", + dev->debugfs_root); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate work buffer\n"); + v4l2_device_unregister(&dev->v4l2_dev); + return ret; + } + } + + if (dev->devtype->tempbuf_size) { + ret = coda_alloc_aux_buf(dev, &dev->tempbuf, + dev->devtype->tempbuf_size, "tempbuf", + dev->debugfs_root); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate temp buffer\n"); + v4l2_device_unregister(&dev->v4l2_dev); + return ret; + } + } + + dev->iram.size = dev->devtype->iram_size; + dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, + &dev->iram.paddr); + if (!dev->iram.vaddr) { + dev_err(&pdev->dev, "unable to alloc iram\n"); + return -ENOMEM; + } + + dev->iram.blob.data = dev->iram.vaddr; + dev->iram.blob.size = dev->iram.size; + dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root, + &dev->iram.blob); + + dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); + if (!dev->workqueue) { + dev_err(&pdev->dev, "unable to alloc workqueue\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, dev); + + pm_runtime_enable(&pdev->dev); + + return coda_firmware_request(dev); +} + +static int coda_remove(struct platform_device *pdev) +{ + struct coda_dev *dev = platform_get_drvdata(pdev); + + video_unregister_device(&dev->vfd[0]); + video_unregister_device(&dev->vfd[1]); + if (dev->m2m_dev) + v4l2_m2m_release(dev->m2m_dev); + pm_runtime_disable(&pdev->dev); + if (dev->alloc_ctx) + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + v4l2_device_unregister(&dev->v4l2_dev); + destroy_workqueue(dev->workqueue); + if (dev->iram.vaddr) + gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr, + dev->iram.size); + coda_free_aux_buf(dev, &dev->codebuf); + coda_free_aux_buf(dev, &dev->tempbuf); + coda_free_aux_buf(dev, &dev->workbuf); + debugfs_remove_recursive(dev->debugfs_root); + return 0; +} + +#ifdef CONFIG_PM_RUNTIME +static int coda_runtime_resume(struct device *dev) +{ + struct coda_dev *cdev = dev_get_drvdata(dev); + int ret = 0; + + if (dev->pm_domain && cdev->codebuf.vaddr) { + ret = coda_hw_init(cdev); + if (ret) + v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); + } + + return ret; +} +#endif + +static const struct dev_pm_ops coda_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL) +}; + +static struct platform_driver coda_driver = { + .probe = coda_probe, + .remove = coda_remove, + .driver = { + .name = CODA_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(coda_dt_ids), + .pm = &coda_pm_ops, + }, + .id_table = coda_platform_ids, +}; + +module_platform_driver(coda_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Javier Martin "); +MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h new file mode 100644 index 000000000000..c791275e307b --- /dev/null +++ b/drivers/media/platform/coda/coda_regs.h @@ -0,0 +1,447 @@ +/* + * linux/drivers/media/platform/coda/coda_regs.h + * + * Copyright (C) 2012 Vista Silicon SL + * Javier Martin + * Xavier Duret + * + * 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. + */ + +#ifndef _REGS_CODA_H_ +#define _REGS_CODA_H_ + +/* HW registers */ +#define CODA_REG_BIT_CODE_RUN 0x000 +#define CODA_REG_RUN_ENABLE (1 << 0) +#define CODA_REG_BIT_CODE_DOWN 0x004 +#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16) +#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff) +#define CODA_REG_BIT_HOST_IN_REQ 0x008 +#define CODA_REG_BIT_INT_CLEAR 0x00c +#define CODA_REG_BIT_INT_CLEAR_SET 0x1 +#define CODA_REG_BIT_INT_STATUS 0x010 +#define CODA_REG_BIT_CODE_RESET 0x014 +#define CODA_REG_RESET_ENABLE (1 << 0) +#define CODA_REG_BIT_CUR_PC 0x018 +#define CODA9_REG_BIT_SW_RESET 0x024 +#define CODA9_SW_RESET_BPU_CORE 0x008 +#define CODA9_SW_RESET_BPU_BUS 0x010 +#define CODA9_SW_RESET_VCE_CORE 0x020 +#define CODA9_SW_RESET_VCE_BUS 0x040 +#define CODA9_SW_RESET_GDI_CORE 0x080 +#define CODA9_SW_RESET_GDI_BUS 0x100 +#define CODA9_REG_BIT_SW_RESET_STATUS 0x034 + +/* Static SW registers */ +#define CODA_REG_BIT_CODE_BUF_ADDR 0x100 +#define CODA_REG_BIT_WORK_BUF_ADDR 0x104 +#define CODA_REG_BIT_PARA_BUF_ADDR 0x108 +#define CODA_REG_BIT_STREAM_CTRL 0x10c +#define CODA7_STREAM_BUF_PIC_RESET (1 << 4) +#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3) +#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3) +#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2) +#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5) +#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4) +#define CODADX6_STREAM_CHKDIS_OFFSET (1 << 1) +#define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) +#define CODA_STREAM_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 +#define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) +#define CODA_IMAGE_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 +#define CODA_BIT_STREAM_END_FLAG (1 << 2) +#define CODA_BIT_DEC_SEQ_INIT_ESCAPE (1 << 0) +#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118 +#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x)) +#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x)) +#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x)) +#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140 +#define CODA7_REG_BIT_AXI_SRAM_USE 0x140 +#define CODA9_USE_HOST_BTP_ENABLE (1 << 13) +#define CODA9_USE_HOST_OVL_ENABLE (1 << 12) +#define CODA7_USE_HOST_ME_ENABLE (1 << 11) +#define CODA9_USE_HOST_DBK_ENABLE (3 << 10) +#define CODA7_USE_HOST_OVL_ENABLE (1 << 10) +#define CODA7_USE_HOST_DBK_ENABLE (1 << 9) +#define CODA9_USE_HOST_IP_ENABLE (1 << 9) +#define CODA7_USE_HOST_IP_ENABLE (1 << 8) +#define CODA9_USE_HOST_BIT_ENABLE (1 << 8) +#define CODA7_USE_HOST_BIT_ENABLE (1 << 7) +#define CODA9_USE_BTP_ENABLE (1 << 5) +#define CODA7_USE_ME_ENABLE (1 << 4) +#define CODA9_USE_OVL_ENABLE (1 << 4) +#define CODA7_USE_OVL_ENABLE (1 << 3) +#define CODA9_USE_DBK_ENABLE (3 << 2) +#define CODA7_USE_DBK_ENABLE (1 << 2) +#define CODA7_USE_IP_ENABLE (1 << 1) +#define CODA7_USE_BIT_ENABLE (1 << 0) + +#define CODA_REG_BIT_BUSY 0x160 +#define CODA_REG_BIT_BUSY_FLAG 1 +#define CODA_REG_BIT_RUN_COMMAND 0x164 +#define CODA_COMMAND_SEQ_INIT 1 +#define CODA_COMMAND_SEQ_END 2 +#define CODA_COMMAND_PIC_RUN 3 +#define CODA_COMMAND_SET_FRAME_BUF 4 +#define CODA_COMMAND_ENCODE_HEADER 5 +#define CODA_COMMAND_ENC_PARA_SET 6 +#define CODA_COMMAND_DEC_PARA_SET 7 +#define CODA_COMMAND_DEC_BUF_FLUSH 8 +#define CODA_COMMAND_RC_CHANGE_PARAMETER 9 +#define CODA_COMMAND_FIRMWARE_GET 0xf +#define CODA_REG_BIT_RUN_INDEX 0x168 +#define CODA_INDEX_SET(x) ((x) & 0x3) +#define CODA_REG_BIT_RUN_COD_STD 0x16c +#define CODADX6_MODE_DECODE_MP4 0 +#define CODADX6_MODE_ENCODE_MP4 1 +#define CODADX6_MODE_DECODE_H264 2 +#define CODADX6_MODE_ENCODE_H264 3 +#define CODA7_MODE_DECODE_H264 0 +#define CODA7_MODE_DECODE_VC1 1 +#define CODA7_MODE_DECODE_MP2 2 +#define CODA7_MODE_DECODE_MP4 3 +#define CODA7_MODE_DECODE_DV3 3 +#define CODA7_MODE_DECODE_RV 4 +#define CODA7_MODE_DECODE_MJPG 5 +#define CODA7_MODE_ENCODE_H264 8 +#define CODA7_MODE_ENCODE_MP4 11 +#define CODA7_MODE_ENCODE_MJPG 13 +#define CODA9_MODE_DECODE_H264 0 +#define CODA9_MODE_DECODE_VC1 1 +#define CODA9_MODE_DECODE_MP2 2 +#define CODA9_MODE_DECODE_MP4 3 +#define CODA9_MODE_DECODE_DV3 3 +#define CODA9_MODE_DECODE_RV 4 +#define CODA9_MODE_DECODE_AVS 5 +#define CODA9_MODE_DECODE_MJPG 6 +#define CODA9_MODE_DECODE_VPX 7 +#define CODA9_MODE_ENCODE_H264 8 +#define CODA9_MODE_ENCODE_MP4 11 +#define CODA9_MODE_ENCODE_MJPG 13 +#define CODA_MODE_INVALID 0xffff +#define CODA_REG_BIT_INT_ENABLE 0x170 +#define CODA_INT_INTERRUPT_ENABLE (1 << 3) +#define CODA_REG_BIT_INT_REASON 0x174 +#define CODA7_REG_BIT_RUN_AUX_STD 0x178 +#define CODA_MP4_AUX_MPEG4 0 +#define CODA_MP4_AUX_DIVX3 1 +#define CODA_VPX_AUX_THO 0 +#define CODA_VPX_AUX_VP6 1 +#define CODA_VPX_AUX_VP8 2 +#define CODA_H264_AUX_AVC 0 +#define CODA_H264_AUX_MVC 1 + +/* + * Commands' mailbox: + * registers with offsets in the range 0x180-0x1d0 + * have different meaning depending on the command being + * issued. + */ + +/* Decoder Sequence Initialization */ +#define CODA_CMD_DEC_SEQ_BB_START 0x180 +#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184 +#define CODA_CMD_DEC_SEQ_OPTION 0x188 +#define CODA_REORDER_ENABLE (1 << 1) +#define CODADX6_QP_REPORT (1 << 0) +#define CODA7_MP4_DEBLK_ENABLE (1 << 0) +#define CODA_CMD_DEC_SEQ_SRC_SIZE 0x18c +#define CODA_CMD_DEC_SEQ_START_BYTE 0x190 +#define CODA_CMD_DEC_SEQ_PS_BB_START 0x194 +#define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198 +#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c +#define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c +#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0 + +#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0 +#define CODA9_RET_DEC_SEQ_BITRATE 0x1b4 +#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0 +#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */ +#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4 +#define CODA_RET_DEC_SEQ_SRC_F_RATE 0x1c8 +#define CODA9_RET_DEC_SEQ_ASPECT 0x1c8 +#define CODA_RET_DEC_SEQ_FRAME_NEED 0x1cc +#define CODA_RET_DEC_SEQ_FRAME_DELAY 0x1d0 +#define CODA_RET_DEC_SEQ_INFO 0x1d4 +#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT 0x1d8 +#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM 0x1dc +#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM 0x1e0 +#define CODA_RET_DEC_SEQ_ERR_REASON 0x1e0 +#define CODA_RET_DEC_SEQ_FRATE_NR 0x1e4 +#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 +#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 +#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 +#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec + +/* Decoder Picture Run */ +#define CODA_CMD_DEC_PIC_ROT_MODE 0x180 +#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184 +#define CODA9_CMD_DEC_PIC_ROT_INDEX 0x184 +#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188 +#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y 0x188 +#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c +#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB 0x18c +#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190 +#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR 0x190 +#define CODA9_CMD_DEC_PIC_ROT_STRIDE 0x1b8 + +#define CODA_CMD_DEC_PIC_OPTION 0x194 +#define CODA_PRE_SCAN_EN (1 << 0) +#define CODA_PRE_SCAN_MODE_DECODE (0 << 1) +#define CODA_PRE_SCAN_MODE_RETURN (1 << 1) +#define CODA_IFRAME_SEARCH_EN (1 << 2) +#define CODA_SKIP_FRAME_MODE (0x3 << 3) +#define CODA_CMD_DEC_PIC_SKIP_NUM 0x198 +#define CODA_CMD_DEC_PIC_CHUNK_SIZE 0x19c +#define CODA_CMD_DEC_PIC_BB_START 0x1a0 +#define CODA_CMD_DEC_PIC_START_BYTE 0x1a4 +#define CODA_RET_DEC_PIC_SIZE 0x1bc +#define CODA_RET_DEC_PIC_FRAME_NUM 0x1c0 +#define CODA_RET_DEC_PIC_FRAME_IDX 0x1c4 +#define CODA_RET_DEC_PIC_ERR_MB 0x1c8 +#define CODA_RET_DEC_PIC_TYPE 0x1cc +#define CODA_PIC_TYPE_MASK 0x7 +#define CODA_PIC_TYPE_MASK_VC1 0x3f +#define CODA9_PIC_TYPE_FIRST_MASK (0x7 << 3) +#define CODA9_PIC_TYPE_IDR_MASK (0x3 << 6) +#define CODA7_PIC_TYPE_H264_NPF_MASK (0x3 << 16) +#define CODA7_PIC_TYPE_INTERLACED (1 << 18) +#define CODA_RET_DEC_PIC_POST 0x1d0 +#define CODA_RET_DEC_PIC_MVC_REPORT 0x1d0 +#define CODA_RET_DEC_PIC_OPTION 0x1d4 +#define CODA_RET_DEC_PIC_SUCCESS 0x1d8 +#define CODA_RET_DEC_PIC_CUR_IDX 0x1dc +#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT 0x1e0 +#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4 +#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec + +#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT 0x1e8 +#define CODA9_RET_DEC_PIC_ASPECT 0x1f0 +#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO 0x1f0 +#define CODA9_RET_DEC_PIC_FRATE_NR 0x1f4 +#define CODA9_RET_DEC_PIC_FRATE_DR 0x1f8 + +/* Encoder Sequence Initialization */ +#define CODA_CMD_ENC_SEQ_BB_START 0x180 +#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184 +#define CODA_CMD_ENC_SEQ_OPTION 0x188 +#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9 +#define CODA9_OPTION_MVC_PREFIX_NAL_OFFSET 9 +#define CODA7_OPTION_GAMMA_OFFSET 8 +#define CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET 8 +#define CODA7_OPTION_RCQPMAX_OFFSET 7 +#define CODA9_OPTION_GAMMA_OFFSET 7 +#define CODADX6_OPTION_GAMMA_OFFSET 7 +#define CODA7_OPTION_RCQPMIN_OFFSET 6 +#define CODA9_OPTION_RCQPMAX_OFFSET 6 +#define CODA_OPTION_LIMITQP_OFFSET 6 +#define CODA_OPTION_RCINTRAQP_OFFSET 5 +#define CODA_OPTION_FMO_OFFSET 4 +#define CODA9_OPTION_MVC_INTERVIEW_OFFSET 4 +#define CODA_OPTION_AVC_AUD_OFFSET 2 +#define CODA_OPTION_SLICEREPORT_OFFSET 1 +#define CODA_CMD_ENC_SEQ_COD_STD 0x18c +#define CODA_STD_MPEG4 0 +#define CODA9_STD_H264 0 +#define CODA_STD_H263 1 +#define CODA_STD_H264 2 +#define CODA_STD_MJPG 3 +#define CODA9_STD_MPEG4 3 + +#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190 +#define CODA7_PICWIDTH_OFFSET 16 +#define CODA7_PICWIDTH_MASK 0xffff +#define CODADX6_PICWIDTH_OFFSET 10 +#define CODADX6_PICWIDTH_MASK 0x3ff +#define CODA_PICHEIGHT_OFFSET 0 +#define CODADX6_PICHEIGHT_MASK 0x3ff +#define CODA7_PICHEIGHT_MASK 0xffff +#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 +#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 +#define CODA_MP4PARAM_VERID_OFFSET 6 +#define CODA_MP4PARAM_VERID_MASK 0x01 +#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2 +#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_263_PARA 0x19c +#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2 +#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1 +#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0 +#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f +#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 +#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 +#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 +#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f +#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4 +#define CODA_SLICING_SIZE_OFFSET 2 +#define CODA_SLICING_SIZE_MASK 0x3fffffff +#define CODA_SLICING_UNIT_OFFSET 1 +#define CODA_SLICING_UNIT_MASK 0x01 +#define CODA_SLICING_MODE_OFFSET 0 +#define CODA_SLICING_MODE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8 +#define CODA_GOP_SIZE_OFFSET 0 +#define CODA_GOP_SIZE_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac +#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 +#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 +#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 +#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f +#define CODA_RATECONTROL_BITRATE_OFFSET 1 +#define CODA_RATECONTROL_BITRATE_MASK 0x7f +#define CODA_RATECONTROL_ENABLE_OFFSET 0 +#define CODA_RATECONTROL_ENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 +#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4 +#define CODADX6_CMD_ENC_SEQ_FMO 0x1b8 +#define CODA_FMOPARAM_TYPE_OFFSET 4 +#define CODA_FMOPARAM_TYPE_MASK 1 +#define CODA_FMOPARAM_SLICENUM_OFFSET 0 +#define CODA_FMOPARAM_SLICENUM_MASK 0x0f +#define CODADX6_CMD_ENC_SEQ_INTRA_QP 0x1bc +#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8 +#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc +#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4 +#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX 0x1c8 +#define CODA_QPMIN_OFFSET 8 +#define CODA_QPMIN_MASK 0x3f +#define CODA_QPMAX_OFFSET 0 +#define CODA_QPMAX_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc +#define CODA_GAMMA_OFFSET 0 +#define CODA_GAMMA_MASK 0xffff +#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE 0x1d0 +#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT 0x1d4 +#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8 +#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 + +/* Encoder Picture Run */ +#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 +#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 +#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC 0x1a4 +#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y 0x1a8 +#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB 0x1ac +#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR 0x1b0 +#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188 +#define CODA_CMD_ENC_PIC_QS 0x18c +#define CODA_CMD_ENC_PIC_ROT_MODE 0x190 +#define CODA_ROT_MIR_ENABLE (1 << 4) +#define CODA_ROT_0 (0x0 << 0) +#define CODA_ROT_90 (0x1 << 0) +#define CODA_ROT_180 (0x2 << 0) +#define CODA_ROT_270 (0x3 << 0) +#define CODA_MIR_NONE (0x0 << 2) +#define CODA_MIR_VER (0x1 << 2) +#define CODA_MIR_HOR (0x2 << 2) +#define CODA_MIR_VER_HOR (0x3 << 2) +#define CODA_CMD_ENC_PIC_OPTION 0x194 +#define CODA_FORCE_IPICTURE BIT(1) +#define CODA_REPORT_MB_INFO BIT(3) +#define CODA_REPORT_MV_INFO BIT(4) +#define CODA_REPORT_SLICE_INFO BIT(5) +#define CODA_CMD_ENC_PIC_BB_START 0x198 +#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c +#define CODA_RET_ENC_FRAME_NUM 0x1c0 +#define CODA_RET_ENC_PIC_TYPE 0x1c4 +#define CODA_RET_ENC_PIC_FRAME_IDX 0x1c8 +#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc +#define CODA_RET_ENC_PIC_FLAG 0x1d0 +#define CODA_RET_ENC_PIC_SUCCESS 0x1d8 + +/* Set Frame Buffer */ +#define CODA_CMD_SET_FRAME_BUF_NUM 0x180 +#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184 +#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188 +#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c +#define CODA9_CMD_SET_FRAME_SUBSAMP_A 0x188 +#define CODA9_CMD_SET_FRAME_SUBSAMP_B 0x18c +#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190 +#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194 +#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198 +#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c +#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0 +#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4 +#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR 0x1a4 +#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8 +#define CODA9_CMD_SET_FRAME_CACHE_SIZE 0x1a8 +#define CODA9_CMD_SET_FRAME_CACHE_CONFIG 0x1ac +#define CODA9_CACHE_BYPASS_OFFSET 28 +#define CODA9_CACHE_DUALCONF_OFFSET 26 +#define CODA9_CACHE_PAGEMERGE_OFFSET 24 +#define CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET 16 +#define CODA9_CACHE_CB_BUFFER_SIZE_OFFSET 8 +#define CODA9_CACHE_CR_BUFFER_SIZE_OFFSET 0 +#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC 0x1b0 +#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC 0x1b4 +#define CODA9_CMD_SET_FRAME_DP_BUF_BASE 0x1b0 +#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE 0x1b4 +#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE 0x1b8 +#define CODA9_CMD_SET_FRAME_DELAY 0x1bc + +/* Encoder Header */ +#define CODA_CMD_ENC_HEADER_CODE 0x180 +#define CODA_GAMMA_OFFSET 0 +#define CODA_HEADER_H264_SPS 0 +#define CODA_HEADER_H264_PPS 1 +#define CODA_HEADER_MP4V_VOL 0 +#define CODA_HEADER_MP4V_VOS 1 +#define CODA_HEADER_MP4V_VIS 2 +#define CODA9_HEADER_FRAME_CROP (1 << 3) +#define CODA_CMD_ENC_HEADER_BB_START 0x184 +#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188 +#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H 0x18c +#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V 0x190 + +/* Get Version */ +#define CODA_CMD_FIRMWARE_VERNUM 0x1c0 +#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff) +#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f) +#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f) +#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff) +#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \ + ((product) << 16 | ((major) << 12) | \ + ((minor) << 8) | (release)) +#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4 + +#define CODA9_GDMA_BASE 0x1000 +#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0) +#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac) + +#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0) +#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4) + +#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800) +#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c) + +#define CODA9_GDI_XY2_BA_0 (CODA9_GDMA_BASE + 0x840) +#define CODA9_GDI_XY2_BA_1 (CODA9_GDMA_BASE + 0x844) +#define CODA9_GDI_XY2_BA_2 (CODA9_GDMA_BASE + 0x848) +#define CODA9_GDI_XY2_BA_3 (CODA9_GDMA_BASE + 0x84c) + +#define CODA9_GDI_XY2_RAS_0 (CODA9_GDMA_BASE + 0x850) +#define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) + +#define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) +#define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) +#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) + +#endif -- cgit v1.2.3 From a2b3e46acbf1edfc772a15e79ab1dbd20ad55cba Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:39 -0300 Subject: [media] coda: move defines, enums, and structs into shared header These will have to be shared between multiple code files. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 193 +------------------------- drivers/media/platform/coda/coda.h | 216 ++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 190 deletions(-) create mode 100644 drivers/media/platform/coda/coda.h diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 98784ee9d38a..dc60bbfd6ebc 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -38,6 +38,7 @@ #include #include +#include "coda.h" #include "coda_regs.h" #define CODA_NAME "coda" @@ -50,10 +51,6 @@ #define CODA7_PS_BUF_SIZE 0x28000 #define CODA9_PS_SAVE_SIZE (512 * 1024) -#define CODA_MAX_FRAMEBUFFERS 8 - -#define CODA_MAX_FRAME_SIZE 0x100000 -#define FMO_SLICE_SAVE_BUF_SIZE (32) #define CODA_DEFAULT_GAMMA 4096 #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ @@ -70,207 +67,23 @@ static int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -enum coda_inst_type { - CODA_INST_ENCODER, - CODA_INST_DECODER, -}; - -enum coda_product { - CODA_DX6 = 0xf001, - CODA_7541 = 0xf012, - CODA_960 = 0xf020, -}; - struct coda_fmt { char *name; u32 fourcc; }; -struct coda_codec { - u32 mode; - u32 src_fourcc; - u32 dst_fourcc; - u32 max_w; - u32 max_h; -}; - -struct coda_devtype { - char *firmware; - enum coda_product product; - const struct coda_codec *codecs; - unsigned int num_codecs; - size_t workbuf_size; - size_t tempbuf_size; - size_t iram_size; -}; - -/* Per-queue, driver-specific private data */ -struct coda_q_data { - unsigned int width; - unsigned int height; - unsigned int bytesperline; - unsigned int sizeimage; - unsigned int fourcc; - struct v4l2_rect rect; -}; - -struct coda_aux_buf { - void *vaddr; - dma_addr_t paddr; - u32 size; - struct debugfs_blob_wrapper blob; - struct dentry *dentry; -}; - -struct coda_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd[2]; - struct platform_device *plat_dev; - const struct coda_devtype *devtype; - - void __iomem *regs_base; - struct clk *clk_per; - struct clk *clk_ahb; - struct reset_control *rstc; - - struct coda_aux_buf codebuf; - struct coda_aux_buf tempbuf; - struct coda_aux_buf workbuf; - struct gen_pool *iram_pool; - struct coda_aux_buf iram; - - spinlock_t irqlock; - struct mutex dev_mutex; - struct mutex coda_mutex; - struct workqueue_struct *workqueue; - struct v4l2_m2m_dev *m2m_dev; - struct vb2_alloc_ctx *alloc_ctx; - struct list_head instances; - unsigned long instance_mask; - struct dentry *debugfs_root; -}; - -struct coda_params { - u8 rot_mode; - u8 h264_intra_qp; - u8 h264_inter_qp; - u8 h264_min_qp; - u8 h264_max_qp; - u8 h264_deblk_enabled; - u8 h264_deblk_alpha; - u8 h264_deblk_beta; - u8 mpeg4_intra_qp; - u8 mpeg4_inter_qp; - u8 gop_size; - int intra_refresh; - int codec_mode; - int codec_mode_aux; - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - u32 framerate; - u16 bitrate; - u32 slice_max_bits; - u32 slice_max_mb; -}; - -struct coda_iram_info { - u32 axi_sram_use; - phys_addr_t buf_bit_use; - phys_addr_t buf_ip_ac_dc_use; - phys_addr_t buf_dbk_y_use; - phys_addr_t buf_dbk_c_use; - phys_addr_t buf_ovl_use; - phys_addr_t buf_btp_use; - phys_addr_t search_ram_paddr; - int search_ram_size; - int remaining; - phys_addr_t next_paddr; -}; - -struct gdi_tiled_map { - int xy2ca_map[16]; - int xy2ba_map[16]; - int xy2ra_map[16]; - int rbc2axi_map[32]; - int xy2rbc_config; - int map_type; -#define GDI_LINEAR_FRAME_MAP 0 -}; - -struct coda_timestamp { - struct list_head list; - u32 sequence; - struct v4l2_timecode timecode; - struct timeval timestamp; -}; - -struct coda_ctx { - struct coda_dev *dev; - struct mutex buffer_mutex; - struct list_head list; - struct work_struct pic_run_work; - struct work_struct seq_end_work; - struct completion completion; - int aborting; - int initialized; - int streamon_out; - int streamon_cap; - u32 isequence; - u32 qsequence; - u32 osequence; - u32 sequence_offset; - struct coda_q_data q_data[2]; - enum coda_inst_type inst_type; - const struct coda_codec *codec; - enum v4l2_colorspace colorspace; - struct coda_params params; - struct v4l2_ctrl_handler ctrls; - struct v4l2_fh fh; - int gopcounter; - int runcounter; - char vpu_header[3][64]; - int vpu_header_size[3]; - struct kfifo bitstream_fifo; - struct mutex bitstream_mutex; - struct coda_aux_buf bitstream; - bool hold; - struct coda_aux_buf parabuf; - struct coda_aux_buf psbuf; - struct coda_aux_buf slicebuf; - struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; - u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; - u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; - struct list_head timestamp_list; - struct coda_aux_buf workbuf; - int num_internal_frames; - int idx; - int reg_idx; - struct coda_iram_info iram_info; - struct gdi_tiled_map tiled_map; - u32 bit_stream_param; - u32 frm_dis_flg; - u32 frame_mem_ctrl; - int display_idx; - struct dentry *debugfs_entry; -}; - static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; -static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg) +void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } -static inline unsigned int coda_read(struct coda_dev *dev, u32 reg) +unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; data = readl(dev->regs_base + reg); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h new file mode 100644 index 000000000000..aafd1869004b --- /dev/null +++ b/drivers/media/platform/coda/coda.h @@ -0,0 +1,216 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix + * + * 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 "coda_regs.h" + +#define CODA_MAX_FRAMEBUFFERS 8 +#define CODA_MAX_FRAME_SIZE 0x100000 +#define FMO_SLICE_SAVE_BUF_SIZE (32) + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum coda_inst_type { + CODA_INST_ENCODER, + CODA_INST_DECODER, +}; + +enum coda_product { + CODA_DX6 = 0xf001, + CODA_7541 = 0xf012, + CODA_960 = 0xf020, +}; + +struct coda_devtype { + char *firmware; + enum coda_product product; + const struct coda_codec *codecs; + unsigned int num_codecs; + size_t workbuf_size; + size_t tempbuf_size; + size_t iram_size; +}; + +struct coda_aux_buf { + void *vaddr; + dma_addr_t paddr; + u32 size; + struct debugfs_blob_wrapper blob; + struct dentry *dentry; +}; + +struct coda_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd[2]; + struct platform_device *plat_dev; + const struct coda_devtype *devtype; + + void __iomem *regs_base; + struct clk *clk_per; + struct clk *clk_ahb; + struct reset_control *rstc; + + struct coda_aux_buf codebuf; + struct coda_aux_buf tempbuf; + struct coda_aux_buf workbuf; + struct gen_pool *iram_pool; + struct coda_aux_buf iram; + + spinlock_t irqlock; + struct mutex dev_mutex; + struct mutex coda_mutex; + struct workqueue_struct *workqueue; + struct v4l2_m2m_dev *m2m_dev; + struct vb2_alloc_ctx *alloc_ctx; + struct list_head instances; + unsigned long instance_mask; + struct dentry *debugfs_root; +}; + +struct coda_codec { + u32 mode; + u32 src_fourcc; + u32 dst_fourcc; + u32 max_w; + u32 max_h; +}; + +struct coda_huff_tab; + +struct coda_params { + u8 rot_mode; + u8 h264_intra_qp; + u8 h264_inter_qp; + u8 h264_min_qp; + u8 h264_max_qp; + u8 h264_deblk_enabled; + u8 h264_deblk_alpha; + u8 h264_deblk_beta; + u8 mpeg4_intra_qp; + u8 mpeg4_inter_qp; + u8 gop_size; + int intra_refresh; + int codec_mode; + int codec_mode_aux; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u32 framerate; + u16 bitrate; + u32 slice_max_bits; + u32 slice_max_mb; +}; + +struct coda_timestamp { + struct list_head list; + u32 sequence; + struct v4l2_timecode timecode; + struct timeval timestamp; +}; + +/* Per-queue, driver-specific private data */ +struct coda_q_data { + unsigned int width; + unsigned int height; + unsigned int bytesperline; + unsigned int sizeimage; + unsigned int fourcc; + struct v4l2_rect rect; +}; + +struct coda_iram_info { + u32 axi_sram_use; + phys_addr_t buf_bit_use; + phys_addr_t buf_ip_ac_dc_use; + phys_addr_t buf_dbk_y_use; + phys_addr_t buf_dbk_c_use; + phys_addr_t buf_ovl_use; + phys_addr_t buf_btp_use; + phys_addr_t search_ram_paddr; + int search_ram_size; + int remaining; + phys_addr_t next_paddr; +}; + +struct gdi_tiled_map { + int xy2ca_map[16]; + int xy2ba_map[16]; + int xy2ra_map[16]; + int rbc2axi_map[32]; + int xy2rbc_config; + int map_type; +#define GDI_LINEAR_FRAME_MAP 0 +}; + +struct coda_ctx { + struct coda_dev *dev; + struct mutex buffer_mutex; + struct list_head list; + struct work_struct pic_run_work; + struct work_struct seq_end_work; + struct completion completion; + int aborting; + int initialized; + int streamon_out; + int streamon_cap; + u32 isequence; + u32 qsequence; + u32 osequence; + u32 sequence_offset; + struct coda_q_data q_data[2]; + enum coda_inst_type inst_type; + const struct coda_codec *codec; + enum v4l2_colorspace colorspace; + struct coda_params params; + struct v4l2_ctrl_handler ctrls; + struct v4l2_fh fh; + int gopcounter; + int runcounter; + char vpu_header[3][64]; + int vpu_header_size[3]; + struct kfifo bitstream_fifo; + struct mutex bitstream_mutex; + struct coda_aux_buf bitstream; + bool hold; + struct coda_aux_buf parabuf; + struct coda_aux_buf psbuf; + struct coda_aux_buf slicebuf; + struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; + u32 frame_types[CODA_MAX_FRAMEBUFFERS]; + struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; + u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; + struct list_head timestamp_list; + struct coda_aux_buf workbuf; + int num_internal_frames; + int idx; + int reg_idx; + struct coda_iram_info iram_info; + struct gdi_tiled_map tiled_map; + u32 bit_stream_param; + u32 frm_dis_flg; + u32 frame_mem_ctrl; + int display_idx; + struct dentry *debugfs_entry; +}; -- cgit v1.2.3 From a1192a17eed8ee30fd0f8d944d66fbe5288641e2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:40 -0300 Subject: [media] coda: add context ops Add a struct coda_context_ops that encapsulates context specific operations. This will simplify adding JPEG support in the future and helps to avoid exporting all functions individually when they move out of the main code file. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 85 ++++++++++++++++++------------- drivers/media/platform/coda/coda.h | 13 +++++ 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dc60bbfd6ebc..07c132485d8f 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -800,7 +800,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int coda_start_decoding(struct coda_ctx *ctx); +static int __coda_start_decoding(struct coda_ctx *ctx); static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) { @@ -976,7 +976,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Run coda_start_decoding (again) if not yet initialized */ if (!ctx->initialized) { - int ret = coda_start_decoding(ctx); + int ret = __coda_start_decoding(ctx); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); @@ -1041,7 +1041,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) return 0; } -static void coda_prepare_encode(struct coda_ctx *ctx) +static int coda_prepare_encode(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; struct vb2_buffer *src_buf, *dst_buf; @@ -1183,6 +1183,8 @@ static void coda_prepare_encode(struct coda_ctx *ctx) ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); } + + return 0; } static void coda_device_run(void *m2m_priv) @@ -1233,16 +1235,12 @@ static void coda_pic_run_work(struct work_struct *work) mutex_lock(&ctx->buffer_mutex); mutex_lock(&dev->coda_mutex); - if (ctx->inst_type == CODA_INST_DECODER) { - ret = coda_prepare_decode(ctx); - if (ret < 0) { - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - /* job_finish scheduled by prepare_decode */ - return; - } - } else { - coda_prepare_encode(ctx); + ret = ctx->ops->prepare_run(ctx); + if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) { + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); + /* job_finish scheduled by prepare_decode */ + return; } if (dev->devtype->product != CODA_DX6) @@ -1260,10 +1258,7 @@ static void coda_pic_run_work(struct work_struct *work) coda_hw_reset(ctx); } else if (!ctx->aborting) { - if (ctx->inst_type == CODA_INST_DECODER) - coda_finish_decode(ctx); - else - coda_finish_encode(ctx); + ctx->ops->finish_run(ctx); } if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) @@ -1846,7 +1841,7 @@ err: return ret; } -static int coda_start_decoding(struct coda_ctx *ctx) +static int __coda_start_decoding(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; u32 bitstream_buf, bitstream_size; @@ -2037,6 +2032,18 @@ static int coda_start_decoding(struct coda_ctx *ctx) return 0; } +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&dev->coda_mutex); + ret = __coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + + return ret; +} + static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, int header_code, u8 *header, int *size) { @@ -2081,7 +2088,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) { struct coda_ctx *ctx = vb2_get_drv_priv(q); struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_src, *q_data_dst; u32 dst_fourcc; int ret = 0; @@ -2133,16 +2139,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (ret < 0) return ret; + ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { - mutex_lock(&dev->coda_mutex); - ret = coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); if (ret == -EAGAIN) return 0; else if (ret < 0) return ret; - } else { - ret = coda_start_encoding(ctx); } ctx->initialized = 1; @@ -2737,10 +2739,9 @@ static int coda_next_free_instance(struct coda_dev *dev) return idx; } -static int coda_open(struct file *file, enum coda_inst_type inst_type) +static int coda_open(struct file *file, enum coda_inst_type inst_type, + const struct coda_context_ops *ctx_ops) { - int (*queue_init)(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); struct coda_dev *dev = video_drvdata(file); struct coda_ctx *ctx = NULL; char *name; @@ -2763,9 +2764,10 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type) kfree(name); ctx->inst_type = inst_type; + ctx->ops = ctx_ops; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); + INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -2796,11 +2798,8 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type) goto err_clk_ahb; set_default_params(ctx); - if (inst_type == CODA_INST_ENCODER) - queue_init = coda_encoder_queue_init; - else - queue_init = coda_decoder_queue_init; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, + ctx->ops->queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); @@ -2871,14 +2870,30 @@ err_coda_max: return ret; } +struct coda_context_ops coda_encode_ops = { + .queue_init = coda_encoder_queue_init, + .start_streaming = coda_start_encoding, + .prepare_run = coda_prepare_encode, + .finish_run = coda_finish_encode, + .seq_end_work = coda_seq_end_work, +}; + +struct coda_context_ops coda_decode_ops = { + .queue_init = coda_decoder_queue_init, + .start_streaming = coda_start_decoding, + .prepare_run = coda_prepare_decode, + .finish_run = coda_finish_decode, + .seq_end_work = coda_seq_end_work +}; + static int coda_encoder_open(struct file *file) { - return coda_open(file, CODA_INST_ENCODER); + return coda_open(file, CODA_INST_ENCODER, &coda_encode_ops); } static int coda_decoder_open(struct file *file) { - return coda_open(file, CODA_INST_DECODER); + return coda_open(file, CODA_INST_DECODER, &coda_decode_ops); } static int coda_release(struct file *file) diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index aafd1869004b..c98270c2532a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -164,6 +164,18 @@ struct gdi_tiled_map { #define GDI_LINEAR_FRAME_MAP 0 }; +struct coda_ctx; + +struct coda_context_ops { + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + int (*start_streaming)(struct coda_ctx *ctx); + int (*prepare_run)(struct coda_ctx *ctx); + void (*finish_run)(struct coda_ctx *ctx); + void (*seq_end_work)(struct work_struct *work); + void (*release)(struct coda_ctx *ctx); +}; + struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; @@ -171,6 +183,7 @@ struct coda_ctx { struct work_struct pic_run_work; struct work_struct seq_end_work; struct completion completion; + const struct coda_context_ops *ops; int aborting; int initialized; int streamon_out; -- cgit v1.2.3 From 8a82c6ba2e92dbd39cb7e5f46aa40daf3432b967 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:41 -0300 Subject: [media] coda: move BIT processor command execution out of pic_run_work In preparation for the split, move the AXI_SRAM_USE register access and the PIC_RUN command execution out of pic_run_work into prepare_encode/decode. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 07c132485d8f..3e6bcca45be6 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1038,6 +1038,13 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_kfifo_sync_to_device_full(ctx); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + return 0; } @@ -1184,6 +1191,12 @@ static int coda_prepare_encode(struct coda_ctx *ctx) coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); } + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + return 0; } @@ -1243,14 +1256,6 @@ static void coda_pic_run_work(struct work_struct *work) return; } - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - if (ctx->inst_type == CODA_INST_DECODER) - coda_kfifo_sync_to_device_full(ctx); - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); -- cgit v1.2.3 From 347bb7f019db8ff52a9285abc6d776c6a776e0e9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:42 -0300 Subject: [media] coda: add coda_bit_stream_set_flag helper This adds a helper function to consolidate three occurences where the bitstream parameter stream end flag is set during operation. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 52 +++++++++++-------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3e6bcca45be6..3e232441549b 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -187,6 +187,20 @@ static int coda_hw_reset(struct coda_ctx *ctx) return ret; } +static void coda_bit_stream_end_flag(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* If this context is currently running, update the hardware flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + static struct coda_q_data *get_q_data(struct coda_ctx *ctx, enum v4l2_buf_type type) { @@ -730,7 +744,6 @@ static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_dev *dev = ctx->dev; int ret; ret = coda_try_decoder_cmd(file, fh, dc); @@ -741,15 +754,8 @@ static int coda_decoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_DECODER) return 0; - /* Set the strem-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); ctx->hold = false; v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); @@ -1472,7 +1478,6 @@ static int coda_buf_prepare(struct vb2_buffer *vb) static void coda_buf_queue(struct vb2_buffer *vb) { struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data; q_data = get_q_data(ctx, vb->vb2_queue->type); @@ -1487,15 +1492,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) * For backwards compatibility, queuing an empty buffer marks * the stream end */ - if (vb2_get_plane_payload(vb, 0) == 0) { - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* if this decoder instance is running, set the stream end flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - } + if (vb2_get_plane_payload(vb, 0) == 0) + coda_bit_stream_end_flag(ctx); mutex_lock(&ctx->bitstream_mutex); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); if (vb2_is_streaming(vb->vb2_queue)) @@ -2492,19 +2490,7 @@ static void coda_stop_streaming(struct vb2_queue *q) "%s: output\n", __func__); ctx->streamon_out = 0; - if (ctx->inst_type == CODA_INST_DECODER && - coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) { - /* if this decoder instance is running, set the stream end flag */ - if (dev->devtype->product == CODA_960) { - u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM); - - val |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM); - ctx->bit_stream_param = val; - } - } - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - + coda_bit_stream_end_flag(ctx); ctx->isequence = 0; } else { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, -- cgit v1.2.3 From 58b7677db01585736d2175f385dcfcc313aed3de Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:43 -0300 Subject: [media] coda: move per-instance buffer allocation and cleanup This patch moves the context buffer allocation into the context start_streaming callbacks. The context buffer and internal framebuffer cleanup is moved into the context release callback. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3e232441549b..64151aafd21f 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1861,6 +1861,11 @@ static int __coda_start_decoding(struct coda_ctx *ctx) bitstream_size = ctx->bitstream.size; src_fourcc = q_data_src->fourcc; + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); /* Update coda bitstream read and write pointers from kfifo */ @@ -2137,11 +2142,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return -EINVAL; } - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { if (ret == -EAGAIN) @@ -2168,6 +2168,11 @@ static int coda_start_encoding(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_fourcc = q_data_dst->fourcc; + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); bitstream_size = q_data_dst->sizeimage; @@ -2838,7 +2843,6 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, return 0; err_dma_writecombine: - coda_free_context_buffers(ctx); if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); coda_free_aux_buf(dev, &ctx->parabuf); @@ -2861,12 +2865,19 @@ err_coda_max: return ret; } +static void coda_bit_release(struct coda_ctx *ctx) +{ + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); +} + struct coda_context_ops coda_encode_ops = { .queue_init = coda_encoder_queue_init, .start_streaming = coda_start_encoding, .prepare_run = coda_prepare_encode, .finish_run = coda_finish_encode, .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, }; struct coda_context_ops coda_decode_ops = { @@ -2874,7 +2885,8 @@ struct coda_context_ops coda_decode_ops = { .start_streaming = coda_start_decoding, .prepare_run = coda_prepare_decode, .finish_run = coda_finish_decode, - .seq_end_work = coda_seq_end_work + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, }; static int coda_encoder_open(struct file *file) @@ -2906,15 +2918,12 @@ static int coda_release(struct file *file) flush_work(&ctx->seq_end_work); } - coda_free_framebuffers(ctx); - coda_lock(ctx); list_del(&ctx->list); coda_unlock(ctx); dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, ctx->bitstream.paddr); - coda_free_context_buffers(ctx); if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); @@ -2926,6 +2935,8 @@ static int coda_release(struct file *file) v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); clear_bit(ctx->idx, &dev->instance_mask); + if (ctx->ops->release) + ctx->ops->release(ctx); kfree(ctx); return 0; -- cgit v1.2.3 From 4f4ee9ee88720e27b2e90e5dc3d9c086b069a316 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:44 -0300 Subject: [media] coda: move H.264 helper function into separate file Currently there is only the coda_h264_padding function, but we will have to add more H.264 specific helpers later. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-common.c | 22 ------------------- drivers/media/platform/coda/coda-h264.c | 36 +++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 4 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 drivers/media/platform/coda/coda-h264.c diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 13d9ad6df51f..0e59fbd06ae6 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,3 @@ -coda-objs := coda-common.o +coda-objs := coda-common.o coda-h264.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 64151aafd21f..574742e1e82c 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -72,10 +72,6 @@ struct coda_fmt { u32 fourcc; }; -static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; - void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, @@ -1627,24 +1623,6 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d return 0; } -static int coda_h264_padding(int size, char *p) -{ - int nal_size; - int diff; - - diff = size - (size & ~0x7); - if (diff == 0) - return 0; - - nal_size = coda_filler_size[diff]; - memcpy(p, coda_filler_nal, nal_size); - - /* Add rbsp stop bit and trailing at the end */ - *(p + nal_size - 1) = 0x80; - - return nal_size; -} - static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) { phys_addr_t ret; diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c new file mode 100644 index 000000000000..0b2fdbeea7cb --- /dev/null +++ b/drivers/media/platform/coda/coda-h264.c @@ -0,0 +1,36 @@ +/* + * Coda multi-standard codec IP - H.264 helper functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * + * 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 + +static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; +static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; + +int coda_h264_padding(int size, char *p) +{ + int nal_size; + int diff; + + diff = size - (size & ~0x7); + if (diff == 0) + return 0; + + nal_size = coda_filler_size[diff]; + memcpy(p, coda_filler_nal, nal_size); + + /* Add rbsp stop bit and trailing at the end */ + *(p + nal_size - 1) = 0x80; + + return nal_size; +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c98270c2532a..84e0829afc85 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -227,3 +227,5 @@ struct coda_ctx { int display_idx; struct dentry *debugfs_entry; }; + +int coda_h264_padding(int size, char *p); -- cgit v1.2.3 From 79924ca9cf95544213d320e3f20d0aff3288e0cb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:45 -0300 Subject: [media] coda: move BIT specific functions into separate file This patch moves the BIT processor specific coda_context_ops, the firmware upload and other related functions from coda-common.c into coda-bit.c. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-bit.c | 1810 ++++++++++++++++++++++++++++ drivers/media/platform/coda/coda-common.c | 1857 +---------------------------- drivers/media/platform/coda/coda.h | 56 + 4 files changed, 1893 insertions(+), 1832 deletions(-) create mode 100644 drivers/media/platform/coda/coda-bit.c diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 0e59fbd06ae6..3543291e6273 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,3 @@ -coda-objs := coda-common.o coda-h264.o +coda-objs := coda-common.o coda-bit.o coda-h264.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c new file mode 100644 index 000000000000..1d2716d564a1 --- /dev/null +++ b/drivers/media/platform/coda/coda-bit.c @@ -0,0 +1,1810 @@ +/* + * Coda multi-standard codec IP - BIT processor functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix + * + * 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 "coda.h" + +#define CODA7_PS_BUF_SIZE 0x28000 +#define CODA9_PS_SAVE_SIZE (512 * 1024) + +#define CODA_DEFAULT_GAMMA 4096 +#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ + +static inline int coda_is_initialized(struct coda_dev *dev) +{ + return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); +} + +static inline unsigned long coda_isbusy(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_BUSY); +} + +static int coda_wait_timeout(struct coda_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (coda_isbusy(dev)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + } + return 0; +} + +static void coda_command_async(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + if (dev->devtype->product == CODA_960 || + dev->devtype->product == CODA_7541) { + /* Restore context related registers to CODA */ + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + coda_write(dev, ctx->frame_mem_ctrl, + CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + } + + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + + coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); + + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); +} + +static int coda_command_sync(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + coda_command_async(ctx, cmd); + return coda_wait_timeout(dev); +} + +int coda_hw_reset(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + unsigned long timeout; + unsigned int idx; + int ret; + + if (!dev->rstc) + return -ENOENT; + + idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); + + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } + } + + ret = reset_control_reset(dev->rstc); + if (ret < 0) + return ret; + + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + ret = coda_wait_timeout(dev); + coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); + + return ret; +} + +static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr; + + rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + kfifo->out = (kfifo->in & ~kfifo->mask) | + (rd_ptr - ctx->bitstream.paddr); + if (kfifo->out > kfifo->in) + kfifo->out -= kfifo->mask + 1; +} + +static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr, wr_ptr; + + rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); + coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr; + + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) +{ + u32 src_size = vb2_get_plane_payload(src_buf, 0); + u32 n; + + n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); + if (n < src_size) + return -ENOSPC; + + dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, + ctx->bitstream.size, DMA_TO_DEVICE); + + src_buf->v4l2_buf.sequence = ctx->qsequence++; + + return 0; +} + +static bool coda_bitstream_try_queue(struct coda_ctx *ctx, + struct vb2_buffer *src_buf) +{ + int ret; + + if (coda_get_bitstream_payload(ctx) + + vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) + return false; + + if (vb2_plane_vaddr(src_buf, 0) == NULL) { + v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); + return true; + } + + ret = coda_bitstream_queue(ctx, src_buf); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); + return false; + } + /* Sync read pointer to device */ + if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) + coda_kfifo_sync_to_device_write(ctx); + + ctx->hold = false; + + return true; +} + +void coda_fill_bitstream(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf; + struct coda_timestamp *ts; + + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + + if (coda_bitstream_try_queue(ctx, src_buf)) { + /* + * Source buffer is queued in the bitstream ringbuffer; + * queue the timestamp and mark source buffer as done + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + + ts = kmalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + ts->sequence = src_buf->v4l2_buf.sequence; + ts->timecode = src_buf->v4l2_buf.timecode; + ts->timestamp = src_buf->v4l2_buf.timestamp; + list_add_tail(&ts->list, &ctx->timestamp_list); + } + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + break; + } + } +} + +void coda_bit_stream_end_flag(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* If this context is currently running, update the hardware flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + +static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) +{ + struct coda_dev *dev = ctx->dev; + u32 *p = ctx->parabuf.vaddr; + + if (dev->devtype->product == CODA_DX6) + p[index] = value; + else + p[index ^ 1] = value; +} + +static void coda_free_framebuffers(struct coda_ctx *ctx) +{ + int i; + + for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); +} + +static int coda_alloc_framebuffers(struct coda_ctx *ctx, + struct coda_q_data *q_data, u32 fourcc) +{ + struct coda_dev *dev = ctx->dev; + int width, height; + dma_addr_t paddr; + int ysize; + int ret; + int i; + + if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { + width = round_up(q_data->width, 16); + height = round_up(q_data->height, 16); + } else { + width = round_up(q_data->width, 8); + height = q_data->height; + } + ysize = width * height; + + /* Allocate frame buffers */ + for (i = 0; i < ctx->num_internal_frames; i++) { + size_t size; + char *name; + + size = ysize + ysize / 2; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + size += ysize / 4; + name = kasprintf(GFP_KERNEL, "fb%d", i); + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], + size, name); + kfree(name); + if (ret < 0) { + coda_free_framebuffers(ctx); + return ret; + } + } + + /* Register frame buffers in the parameter buffer */ + for (i = 0; i < ctx->num_internal_frames; i++) { + paddr = ctx->internal_frames[i].paddr; + coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ + coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ + coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ + + /* mvcol buffer for h.264 */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + coda_parabuf_write(ctx, 96 + i, + ctx->internal_frames[i].paddr + + ysize + ysize/4 + ysize/4); + } + + /* mvcol buffer for mpeg4 */ + if ((dev->devtype->product != CODA_DX6) && + (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) + coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + + ysize + ysize/4 + ysize/4); + + return 0; +} + +static void coda_free_context_buffers(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + coda_free_aux_buf(dev, &ctx->slicebuf); + coda_free_aux_buf(dev, &ctx->psbuf); + if (dev->devtype->product != CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); +} + +static int coda_alloc_context_buffers(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + struct coda_dev *dev = ctx->dev; + size_t size; + int ret; + + if (dev->devtype->product == CODA_DX6) + return 0; + + if (ctx->psbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); + return -EBUSY; + } + if (ctx->slicebuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); + return -EBUSY; + } + if (ctx->workbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); + ret = -EBUSY; + return -ENOMEM; + } + + if (q_data->fourcc == V4L2_PIX_FMT_H264) { + /* worst case slice size */ + size = (DIV_ROUND_UP(q_data->width, 16) * + DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", + ctx->slicebuf.size); + return ret; + } + } + + if (dev->devtype->product == CODA_7541) { + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); + goto err; + } + } + + size = dev->devtype->workbuf_size; + if (dev->devtype->product == CODA_960 && + q_data->fourcc == V4L2_PIX_FMT_H264) + size += CODA9_PS_SAVE_SIZE; + ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", + ctx->workbuf.size); + goto err; + } + + return 0; + +err: + coda_free_context_buffers(ctx); + return ret; +} + +static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, + int header_code, u8 *header, int *size) +{ + struct coda_dev *dev = ctx->dev; + size_t bufsize; + int ret; + int i; + + if (dev->devtype->product == CODA_960) + memset(vb2_plane_vaddr(buf, 0), 0, 64); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), + CODA_CMD_ENC_HEADER_BB_START); + bufsize = vb2_plane_size(buf, 0); + if (dev->devtype->product == CODA_960) + bufsize /= 1024; + coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); + ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return ret; + } + + if (dev->devtype->product == CODA_960) { + for (i = 63; i > 0; i--) + if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) + break; + *size = i + 1; + } else { + *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + } + memcpy(header, vb2_plane_vaddr(buf, 0), *size); + + return 0; +} + +static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) +{ + phys_addr_t ret; + + size = round_up(size, 1024); + if (size > iram->remaining) + return 0; + iram->remaining -= size; + + ret = iram->next_paddr; + iram->next_paddr += size; + + return ret; +} + +static void coda_setup_iram(struct coda_ctx *ctx) +{ + struct coda_iram_info *iram_info = &ctx->iram_info; + struct coda_dev *dev = ctx->dev; + int mb_width; + int dbk_bits; + int bit_bits; + int ip_bits; + + memset(iram_info, 0, sizeof(*iram_info)); + iram_info->next_paddr = dev->iram.paddr; + iram_info->remaining = dev->iram.size; + + switch (dev->devtype->product) { + case CODA_7541: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + case CODA_960: + dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; + bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + default: /* CODA_DX6 */ + return; + } + + if (ctx->inst_type == CODA_INST_ENCODER) { + struct coda_q_data *q_data_src; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + mb_width = DIV_ROUND_UP(q_data_src->width, 16); + + /* Prioritize in case IRAM is too small for everything */ + if (dev->devtype->product == CODA_7541) { + iram_info->search_ram_size = round_up(mb_width * 16 * + 36 + 2048, 1024); + iram_info->search_ram_paddr = coda_iram_alloc(iram_info, + iram_info->search_ram_size); + if (!iram_info->search_ram_paddr) { + pr_err("IRAM is smaller than the search ram size\n"); + goto out; + } + iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | + CODA7_USE_ME_ENABLE; + } + + /* Only H.264BP and H.263P3 are considered */ + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP disabled for encoder */ + } else if (ctx->inst_type == CODA_INST_DECODER) { + struct coda_q_data *q_data_dst; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP unused as there is no VC1 support yet */ + } + +out: + if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "IRAM smaller than needed\n"); + + if (dev->devtype->product == CODA_7541) { + /* TODO - Enabling these causes picture errors on CODA7541 */ + if (ctx->inst_type == CODA_INST_DECODER) { + /* fw 1.4.50 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_IP_ENABLE); + } else { + /* fw 13.4.29 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_HOST_DBK_ENABLE | + CODA7_USE_IP_ENABLE | + CODA7_USE_DBK_ENABLE); + } + } +} + +static u32 coda_supported_firmwares[] = { + CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), +}; + +static bool coda_firmware_supported(u32 vernum) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) + if (vernum == coda_supported_firmwares[i]) + return true; + return false; +} + +int coda_check_firmware(struct coda_dev *dev) +{ + u16 product, major, minor, release; + u32 data; + int ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); + if (coda_wait_timeout(dev)) { + v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); + ret = -EIO; + goto err_run_cmd; + } + + if (dev->devtype->product == CODA_960) { + data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); + v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", + data); + } + + /* Check we are compatible with the loaded firmware */ + data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); + product = CODA_FIRMWARE_PRODUCT(data); + major = CODA_FIRMWARE_MAJOR(data); + minor = CODA_FIRMWARE_MINOR(data); + release = CODA_FIRMWARE_RELEASE(data); + + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + + if (product != dev->devtype->product) { + v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," + " Version: %u.%u.%u\n", + coda_product_name(dev->devtype->product), + coda_product_name(product), major, minor, release); + return -EINVAL; + } + + v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", + coda_product_name(product)); + + if (coda_firmware_supported(data)) { + v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", + major, minor, release); + } else { + v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " + "%u.%u.%u\n", major, minor, release); + } + + return 0; + +err_run_cmd: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +/* + * Encoder context operations + */ + +static int coda_start_encoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct vb2_buffer *buf; + int gamma, ret, value; + u32 dst_fourcc; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); + bitstream_size = q_data_dst->sizeimage; + + if (!coda_is_initialized(dev)) { + v4l2_err(v4l2_dev, "coda is not initialized.\n"); + return -EFAULT; + } + + mutex_lock(&dev->coda_mutex); + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | + CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + case CODA_960: + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + /* fallthrough */ + case CODA_7541: + coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | + CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + } + + value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); + value &= ~(1 << 2 | 0x7 << 9); + ctx->frame_mem_ctrl = value; + coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product == CODA_DX6) { + /* Configure the coda */ + coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + } + + /* Could set rotation here if needed */ + switch (dev->devtype->product) { + case CODA_DX6: + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + case CODA_7541: + if (dst_fourcc == V4L2_PIX_FMT_H264) { + value = (round_up(q_data_src->width, 16) & + CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (round_up(q_data_src->height, 16) & + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + } + /* fallthrough */ + case CODA_960: + value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_SEQ_SRC_F_RATE); + + ctx->params.codec_mode = ctx->codec->mode; + switch (dst_fourcc) { + case V4L2_PIX_FMT_MPEG4: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); + break; + case V4L2_PIX_FMT_H264: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + if (ctx->params.h264_deblk_enabled) { + value = ((ctx->params.h264_deblk_alpha & + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | + ((ctx->params.h264_deblk_beta & + CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); + } else { + value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); + break; + default: + v4l2_err(v4l2_dev, + "dst format (0x%08x) invalid.\n", dst_fourcc); + ret = -EINVAL; + goto out; + } + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + value = 0; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); + + if (ctx->params.bitrate) { + /* Rate control enabled */ + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + if (dev->devtype->product == CODA_960) + value |= BIT(31); /* disable autoskip */ + } else { + value = 0; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_SEQ_INTRA_REFRESH); + + coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); + + + value = 0; + if (dev->devtype->product == CODA_960) + gamma = CODA9_DEFAULT_GAMMA; + else + gamma = CODA_DEFAULT_GAMMA; + if (gamma > 0) { + coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, + CODA_CMD_ENC_SEQ_RC_GAMMA); + } + + if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { + coda_write(dev, + ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | + ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, + CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); + } + if (dev->devtype->product == CODA_960) { + if (ctx->params.h264_max_qp) + value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; + if (CODA_DEFAULT_GAMMA > 0) + value |= 1 << CODA9_OPTION_GAMMA_OFFSET; + } else { + if (CODA_DEFAULT_GAMMA > 0) { + if (dev->devtype->product == CODA_DX6) + value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; + else + value |= 1 << CODA7_OPTION_GAMMA_OFFSET; + } + if (ctx->params.h264_min_qp) + value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; + if (ctx->params.h264_max_qp) + value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); + + coda_setup_iram(ctx); + + if (dst_fourcc == V4L2_PIX_FMT_H264) { + switch (dev->devtype->product) { + case CODA_DX6: + value = FMO_SLICE_SAVE_BUF_SIZE << 7; + coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); + break; + case CODA_7541: + coda_write(dev, ctx->iram_info.search_ram_paddr, + CODA7_CMD_ENC_SEQ_SEARCH_BASE); + coda_write(dev, ctx->iram_info.search_ram_size, + CODA7_CMD_ENC_SEQ_SEARCH_SIZE); + break; + case CODA_960: + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + goto out; + } + + if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); + ret = -EFAULT; + goto out; + } + + if (dev->devtype->product == CODA_960) + ctx->num_internal_frames = 4; + else + ctx->num_internal_frames = 2; + ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); + goto out; + } + + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, q_data_src->bytesperline, + CODA_CMD_SET_FRAME_BUF_STRIDE); + if (dev->devtype->product == CODA_7541) { + coda_write(dev, q_data_src->bytesperline, + CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); + } + if (dev->devtype->product != CODA_DX6) { + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) { + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + + /* FIXME */ + coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + goto out; + } + + /* Save stream headers */ + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + /* + * Get SPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + /* + * Get PPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + /* + * Length of H.264 headers is variable and thus it might not be + * aligned for the coda to append the encoded frame. In that is + * the case a filler NAL must be added to header 2. + */ + ctx->vpu_header_size[2] = coda_h264_padding( + (ctx->vpu_header_size[0] + + ctx->vpu_header_size[1]), + ctx->vpu_header[2]); + break; + case V4L2_PIX_FMT_MPEG4: + /* + * Get VOS in the first frame and copy it to an + * intermediate buffer + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, + &ctx->vpu_header[2][0], + &ctx->vpu_header_size[2]); + if (ret < 0) + goto out; + break; + default: + /* No more formats need to save headers at the moment */ + break; + } + +out: + mutex_unlock(&dev->coda_mutex); + return ret; +} + +static int coda_prepare_encode(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + int force_ipicture; + int quant_param = 0; + u32 picture_y, picture_cb, picture_cr; + u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 dst_fourcc; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + src_buf->v4l2_buf.sequence = ctx->osequence; + dst_buf->v4l2_buf.sequence = ctx->osequence; + ctx->osequence++; + + /* + * Workaround coda firmware BUG that only marks the first + * frame as IDR. This is a problem for some decoders that can't + * recover when a frame is lost. + */ + if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } else { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* + * Copy headers at the beginning of the first frame for H.264 only. + * In MPEG4 they are already copied by the coda. + */ + if (src_buf->v4l2_buf.sequence == 0) { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - + ctx->vpu_header_size[0] - + ctx->vpu_header_size[1] - + ctx->vpu_header_size[2]; + memcpy(vb2_plane_vaddr(dst_buf, 0), + &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], + &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1], &ctx->vpu_header[2][0], + ctx->vpu_header_size[2]); + } else { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; + } + + if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + force_ipicture = 1; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_intra_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_intra_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set intra qp, fmt not supported\n"); + break; + } + } else { + force_ipicture = 0; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_inter_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_inter_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set inter qp, fmt not supported\n"); + break; + } + } + + /* submit */ + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); + + + picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); + switch (q_data_src->fourcc) { + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + picture_cr = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cb = picture_cr + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + case V4L2_PIX_FMT_YUV420: + default: + picture_cb = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cr = picture_cb + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); + coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); + coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); + + coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); + } else { + coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); + } + coda_write(dev, force_ipicture << 1 & 0x2, + CODA_CMD_ENC_PIC_OPTION); + + coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); + coda_write(dev, pic_stream_buffer_size / 1024, + CODA_CMD_ENC_PIC_BB_SIZE); + + if (!ctx->streamon_out) { + /* After streamoff on the output side, set the stream end flag */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static void coda_finish_encode(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr, start_ptr; + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Get results from the coda */ + start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); + wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + + /* Calculate bytesused field */ + if (dst_buf->v4l2_buf.sequence == 0) { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]); + } else { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", + wr_ptr - start_ptr); + + coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); + coda_read(dev, CODA_RET_ENC_PIC_FLAG); + + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } else { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } + + dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.flags |= + src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + ctx->gopcounter--; + if (ctx->gopcounter < 0) + ctx->gopcounter = ctx->params.gop_size - 1; + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: encoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); +} + +static void coda_seq_end_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); + struct coda_dev *dev = ctx->dev; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_END failed\n"); + } + + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); + + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static void coda_bit_release(struct coda_ctx *ctx) +{ + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); +} + +const struct coda_context_ops coda_bit_encode_ops = { + .queue_init = coda_encoder_queue_init, + .start_streaming = coda_start_encoding, + .prepare_run = coda_prepare_encode, + .finish_run = coda_finish_encode, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +/* + * Decoder context operations + */ + +static int __coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct coda_dev *dev = ctx->dev; + int width, height; + u32 src_fourcc; + u32 val; + int ret; + + /* Start decoding */ + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + bitstream_buf = ctx->bitstream.paddr; + bitstream_size = ctx->bitstream.size; + src_fourcc = q_data_src->fourcc; + + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + + /* Update coda bitstream read and write pointers from kfifo */ + coda_kfifo_sync_to_device_full(ctx); + + ctx->display_idx = -1; + ctx->frm_dis_flg = 0; + coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, + CODA_REG_BIT_BIT_STREAM_PARAM); + + coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); + val = 0; + if ((dev->devtype->product == CODA_7541) || + (dev->devtype->product == CODA_960)) + val |= CODA_REORDER_ENABLE; + coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); + + ctx->params.codec_mode = ctx->codec->mode; + if (dev->devtype->product == CODA_960 && + src_fourcc == V4L2_PIX_FMT_MPEG4) + ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; + else + ctx->params.codec_mode_aux = 0; + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (dev->devtype->product == CODA_7541) { + coda_write(dev, ctx->psbuf.paddr, + CODA_CMD_DEC_SEQ_PS_BB_START); + coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), + CODA_CMD_DEC_SEQ_PS_BB_SIZE); + } + if (dev->devtype->product == CODA_960) { + coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); + coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); + } + } + if (dev->devtype->product != CODA_960) + coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); + + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + return -ETIMEDOUT; + } + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + + if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", + coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); + return -EAGAIN; + } + + val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); + if (dev->devtype->product == CODA_DX6) { + width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; + height = val & CODADX6_PICHEIGHT_MASK; + } else { + width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; + height = val & CODA7_PICHEIGHT_MASK; + } + + if (width > q_data_dst->width || height > q_data_dst->height) { + v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", + width, height, q_data_dst->width, q_data_dst->height); + return -EINVAL; + } + + width = round_up(width, 16); + height = round_up(height, 16); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", + __func__, ctx->idx, width, height); + + ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); + if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { + v4l2_err(&dev->v4l2_dev, + "not enough framebuffers to decode (%d < %d)\n", + CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); + return -EINVAL; + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); + + q_data_dst->rect.left = (left_right >> 10) & 0x3ff; + q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; + q_data_dst->rect.width = width - q_data_dst->rect.left - + (left_right & 0x3ff); + q_data_dst->rect.height = height - q_data_dst->rect.top - + (top_bottom & 0x3ff); + } + + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); + if (ret < 0) + return ret; + + /* Tell the decoder how many frame buffers we allocated. */ + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); + + if (dev->devtype->product != CODA_DX6) { + /* Set secondary AXI IRAM */ + coda_setup_iram(ctx); + + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); + coda_write(dev, ctx->iram_info.buf_ovl_use, + CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); + if (dev->devtype->product == CODA_960) + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + + coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); + coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | + 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, + CODA9_CMD_SET_FRAME_CACHE_CONFIG); + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + coda_write(dev, ctx->slicebuf.paddr, + CODA_CMD_SET_FRAME_SLICE_BB_START); + coda_write(dev, ctx->slicebuf.size / 1024, + CODA_CMD_SET_FRAME_SLICE_BB_SIZE); + } + + if (dev->devtype->product == CODA_7541) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); + } else if (dev->devtype->product == CODA_960) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { + v4l2_err(&ctx->dev->v4l2_dev, + "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&dev->coda_mutex); + ret = __coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + + return ret; +} + +static int coda_prepare_decode(struct coda_ctx *ctx) +{ + struct vb2_buffer *dst_buf; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_dst; + u32 stridey, height; + u32 picture_y, picture_cb, picture_cr; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + if (ctx->params.rot_mode & CODA_ROT_90) { + stridey = q_data_dst->height; + height = q_data_dst->width; + } else { + stridey = q_data_dst->width; + height = q_data_dst->height; + } + + /* Try to copy source buffer contents into the bitstream ringbuffer */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + + if (coda_get_bitstream_payload(ctx) < 512 && + (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "bitstream payload: %d, skipping\n", + coda_get_bitstream_payload(ctx)); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } + + /* Run coda_start_decoding (again) if not yet initialized */ + if (!ctx->initialized) { + int ret = __coda_start_decoding(ctx); + + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } else { + ctx->initialized = 1; + } + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* Set rotator output */ + picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { + /* Switch Cr and Cb for YVU420 format */ + picture_cr = picture_y + stridey * height; + picture_cb = picture_cr + stridey / 2 * height / 2; + } else { + picture_cb = picture_y + stridey * height; + picture_cr = picture_cb + stridey / 2 * height / 2; + } + + if (dev->devtype->product == CODA_960) { + /* + * The CODA960 seems to have an internal list of buffers with + * 64 entries that includes the registered frame buffers as + * well as the rotator buffer output. + * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. + */ + coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, + CODA9_CMD_DEC_PIC_ROT_INDEX); + coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); + } else { + coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); + } + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, + CODA_CMD_DEC_PIC_ROT_MODE); + + switch (dev->devtype->product) { + case CODA_DX6: + /* TBD */ + case CODA_7541: + coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); + break; + case CODA_960: + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ + break; + } + + coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); + + coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); + coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_kfifo_sync_to_device_full(ctx); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static void coda_finish_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src; + struct coda_q_data *q_data_dst; + struct vb2_buffer *dst_buf; + struct coda_timestamp *ts; + int width, height; + int decoded_idx; + int display_idx; + u32 src_fourcc; + int success; + u32 err_mb; + u32 val; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + /* + * in stream-end mode, the read pointer can overshoot the write pointer + * by up to 512 bytes + */ + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { + if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_fourcc = q_data_src->fourcc; + + val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); + if (val != 1) + pr_err("DEC_PIC_SUCCESS = %d\n", val); + + success = val & 0x1; + if (!success) + v4l2_err(&dev->v4l2_dev, "decode failed\n"); + + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (val & (1 << 3)) + v4l2_err(&dev->v4l2_dev, + "insufficient PS buffer space (%d bytes)\n", + ctx->psbuf.size); + if (val & (1 << 2)) + v4l2_err(&dev->v4l2_dev, + "insufficient slice buffer space (%d bytes)\n", + ctx->slicebuf.size); + } + + val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); + width = (val >> 16) & 0xffff; + height = val & 0xffff; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* frame crop information */ + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); + + if (left_right == 0xffffffff && top_bottom == 0xffffffff) { + /* Keep current crop information */ + } else { + struct v4l2_rect *rect = &q_data_dst->rect; + + rect->left = left_right >> 16 & 0xffff; + rect->top = top_bottom >> 16 & 0xffff; + rect->width = width - rect->left - + (left_right & 0xffff); + rect->height = height - rect->top - + (top_bottom & 0xffff); + } + } else { + /* no cropping */ + } + + err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); + if (err_mb > 0) + v4l2_err(&dev->v4l2_dev, + "errors in %d macroblocks\n", err_mb); + + if (dev->devtype->product == CODA_7541) { + val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); + if (val == 0) { + /* not enough bitstream data */ + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "prescan failed: %d\n", val); + ctx->hold = true; + return; + } + } + + ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + /* + * The previous display frame was copied out by the rotator, + * now it can be overwritten again + */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + ctx->frm_dis_flg &= ~(1 << ctx->display_idx); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + } + + /* + * The index of the last decoded frame, not necessarily in + * display order, and the index of the next display frame. + * The latter could have been decoded in a previous run. + */ + decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); + display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); + + if (decoded_idx == -1) { + /* no frame was decoded, but we might have a display frame */ + if (display_idx >= 0 && display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; + else if (ctx->display_idx < 0) + ctx->hold = true; + } else if (decoded_idx == -2) { + /* no frame was decoded, we still return the remaining buffers */ + } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "decoded frame index out of range: %d\n", decoded_idx); + } else { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + val -= ctx->sequence_offset; + if (val != (ts->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + val, ctx->sequence_offset, ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; + if (val == 0) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; + else if (val == 1) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; + else + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; + + ctx->frame_errors[decoded_idx] = err_mb; + } + + if (display_idx == -1) { + /* + * no more frames to be decoded, but there could still + * be rotator output to dequeue + */ + ctx->hold = true; + } else if (display_idx == -3) { + /* possibly prescan failure */ + } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "presentation frame index out of range: %d\n", + display_idx); + } + + /* If a frame was copied out, return it */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->v4l2_buf.sequence = ctx->osequence++; + + dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME); + dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; + ts = &ctx->frame_timestamps[ctx->display_idx]; + dst_buf->v4l2_buf.timecode = ts->timecode; + dst_buf->v4l2_buf.timestamp = ts->timestamp; + + vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); + + v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: decoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); + } else { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: no frame decoded\n"); + } + + /* The rotator will copy the current display frame next time */ + ctx->display_idx = display_idx; +} + +const struct coda_context_ops coda_bit_decode_ops = { + .queue_init = coda_decoder_queue_init, + .start_streaming = coda_start_decoding, + .prepare_run = coda_prepare_decode, + .finish_run = coda_finish_decode, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +irqreturn_t coda_irq_handler(int irq, void *data) +{ + struct coda_dev *dev = data; + struct coda_ctx *ctx; + + /* read status register to attend the IRQ */ + coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, + CODA_REG_BIT_INT_CLEAR); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (ctx == NULL) { + v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + mutex_unlock(&dev->coda_mutex); + return IRQ_HANDLED; + } + + if (ctx->aborting) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "task has been aborted\n"); + } + + if (coda_isbusy(ctx->dev)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "coda is still busy!!!!\n"); + return IRQ_NONE; + } + + complete(&ctx->completion); + + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 574742e1e82c..dc9740d0ea5e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -48,12 +48,6 @@ #define CODA_PARA_BUF_SIZE (10 * 1024) #define CODA_ISRAM_SIZE (2048 * 2) -#define CODA7_PS_BUF_SIZE 0x28000 -#define CODA9_PS_SAVE_SIZE (512 * 1024) - -#define CODA_DEFAULT_GAMMA 4096 -#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ - #define MIN_W 176 #define MIN_H 144 @@ -63,7 +57,7 @@ #define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) -static int coda_debug; +int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); @@ -88,128 +82,6 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) return data; } -static inline unsigned long coda_isbusy(struct coda_dev *dev) -{ - return coda_read(dev, CODA_REG_BIT_BUSY); -} - -static inline int coda_is_initialized(struct coda_dev *dev) -{ - return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); -} - -static int coda_wait_timeout(struct coda_dev *dev) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - while (coda_isbusy(dev)) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - } - return 0; -} - -static void coda_command_async(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { - /* Restore context related registers to CODA */ - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - coda_write(dev, ctx->frame_mem_ctrl, - CODA_REG_BIT_FRAME_MEM_CTRL); - coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - } - - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - - coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); - - coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); -} - -static int coda_command_sync(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - coda_command_async(ctx, cmd); - return coda_wait_timeout(dev); -} - -static int coda_hw_reset(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - unsigned long timeout; - unsigned int idx; - int ret; - - if (!dev->rstc) - return -ENOENT; - - idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - - if (dev->devtype->product == CODA_960) { - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - } - - ret = reset_control_reset(dev->rstc); - if (ret < 0) - return ret; - - if (dev->devtype->product == CODA_960) - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - ret = coda_wait_timeout(dev); - coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); - - return ret; -} - -static void coda_bit_stream_end_flag(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } -} - -static struct coda_q_data *get_q_data(struct coda_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &(ctx->q_data[V4L2_M2M_SRC]); - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &(ctx->q_data[V4L2_M2M_DST]); - default: - return NULL; - } -} - /* * Array of all formats supported by any version of Coda: */ @@ -330,7 +202,7 @@ static void coda_get_max_dimensions(struct coda_dev *dev, *max_h = h; } -static char *coda_product_name(int product) +const char *coda_product_name(int product) { static char buf[9]; @@ -802,124 +674,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int __coda_start_decoding(struct coda_ctx *ctx); - -static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) -{ - return kfifo_len(&ctx->bitstream_fifo); -} - -static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr; - - rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - kfifo->out = (kfifo->in & ~kfifo->mask) | - (rd_ptr - ctx->bitstream.paddr); - if (kfifo->out > kfifo->in) - kfifo->out -= kfifo->mask + 1; -} - -static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr, wr_ptr; - - rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); - coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr; - - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) -{ - u32 src_size = vb2_get_plane_payload(src_buf, 0); - u32 n; - - n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); - if (n < src_size) - return -ENOSPC; - - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, - ctx->bitstream.size, DMA_TO_DEVICE); - - src_buf->v4l2_buf.sequence = ctx->qsequence++; - - return 0; -} - -static bool coda_bitstream_try_queue(struct coda_ctx *ctx, - struct vb2_buffer *src_buf) -{ - int ret; - - if (coda_get_bitstream_payload(ctx) + - vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) - return false; - - if (vb2_plane_vaddr(src_buf, 0) == NULL) { - v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); - return true; - } - - ret = coda_bitstream_queue(ctx, src_buf); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); - return false; - } - /* Sync read pointer to device */ - if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) - coda_kfifo_sync_to_device_write(ctx); - - ctx->hold = false; - - return true; -} - -static void coda_fill_bitstream(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf; - struct coda_timestamp *ts; - - while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - - if (coda_bitstream_try_queue(ctx, src_buf)) { - /* - * Source buffer is queued in the bitstream ringbuffer; - * queue the timestamp and mark source buffer as done - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - - ts = kmalloc(sizeof(*ts), GFP_KERNEL); - if (ts) { - ts->sequence = src_buf->v4l2_buf.sequence; - ts->timecode = src_buf->v4l2_buf.timecode; - ts->timestamp = src_buf->v4l2_buf.timestamp; - list_add_tail(&ts->list, &ctx->timestamp_list); - } - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } else { - break; - } - } -} - -static void coda_set_gdi_regs(struct coda_ctx *ctx) +void coda_set_gdi_regs(struct coda_ctx *ctx) { struct gdi_tiled_map *tiled_map = &ctx->tiled_map; struct coda_dev *dev = ctx->dev; @@ -943,264 +698,6 @@ static void coda_set_gdi_regs(struct coda_ctx *ctx) /* * Mem-to-mem operations. */ -static int coda_prepare_decode(struct coda_ctx *ctx) -{ - struct vb2_buffer *dst_buf; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_dst; - u32 stridey, height; - u32 picture_y, picture_cb, picture_cr; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - if (ctx->params.rot_mode & CODA_ROT_90) { - stridey = q_data_dst->height; - height = q_data_dst->width; - } else { - stridey = q_data_dst->width; - height = q_data_dst->height; - } - - /* Try to copy source buffer contents into the bitstream ringbuffer */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); - - if (coda_get_bitstream_payload(ctx) < 512 && - (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "bitstream payload: %d, skipping\n", - coda_get_bitstream_payload(ctx)); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } - - /* Run coda_start_decoding (again) if not yet initialized */ - if (!ctx->initialized) { - int ret = __coda_start_decoding(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } else { - ctx->initialized = 1; - } - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* Set rotator output */ - picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { - /* Switch Cr and Cb for YVU420 format */ - picture_cr = picture_y + stridey * height; - picture_cb = picture_cr + stridey / 2 * height / 2; - } else { - picture_cb = picture_y + stridey * height; - picture_cr = picture_cb + stridey / 2 * height / 2; - } - - if (dev->devtype->product == CODA_960) { - /* - * The CODA960 seems to have an internal list of buffers with - * 64 entries that includes the registered frame buffers as - * well as the rotator buffer output. - * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. - */ - coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, - CODA9_CMD_DEC_PIC_ROT_INDEX); - coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); - } else { - coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); - } - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, - CODA_CMD_DEC_PIC_ROT_MODE); - - switch (dev->devtype->product) { - case CODA_DX6: - /* TBD */ - case CODA_7541: - coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); - break; - case CODA_960: - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ - break; - } - - coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); - - coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); - coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - coda_kfifo_sync_to_device_full(ctx); - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} - -static int coda_prepare_encode(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - int force_ipicture; - int quant_param = 0; - u32 picture_y, picture_cb, picture_cr; - u32 pic_stream_buffer_addr, pic_stream_buffer_size; - u32 dst_fourcc; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - src_buf->v4l2_buf.sequence = ctx->osequence; - dst_buf->v4l2_buf.sequence = ctx->osequence; - ctx->osequence++; - - /* - * Workaround coda firmware BUG that only marks the first - * frame as IDR. This is a problem for some decoders that can't - * recover when a frame is lost. - */ - if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } else { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* - * Copy headers at the beginning of the first frame for H.264 only. - * In MPEG4 they are already copied by the coda. - */ - if (src_buf->v4l2_buf.sequence == 0) { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0) + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]; - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - - ctx->vpu_header_size[0] - - ctx->vpu_header_size[1] - - ctx->vpu_header_size[2]; - memcpy(vb2_plane_vaddr(dst_buf, 0), - &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], - &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + - ctx->vpu_header_size[1], &ctx->vpu_header[2][0], - ctx->vpu_header_size[2]); - } else { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; - } - - if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { - force_ipicture = 1; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_intra_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_intra_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set intra qp, fmt not supported\n"); - break; - } - } else { - force_ipicture = 0; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_inter_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_inter_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set inter qp, fmt not supported\n"); - break; - } - } - - /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); - coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); - - - picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); - switch (q_data_src->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - picture_cr = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cb = picture_cr + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - case V4L2_PIX_FMT_YUV420: - default: - picture_cb = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cr = picture_cb + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); - coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); - coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); - - coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); - } else { - coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); - } - coda_write(dev, force_ipicture << 1 & 0x2, - CODA_CMD_ENC_PIC_OPTION); - - coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); - coda_write(dev, pic_stream_buffer_size / 1024, - CODA_CMD_ENC_PIC_BB_SIZE); - - if (!ctx->streamon_out) { - /* After streamoff on the output side, set the stream end flag */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} static void coda_device_run(void *m2m_priv) { @@ -1210,37 +707,6 @@ static void coda_device_run(void *m2m_priv) queue_work(dev->workqueue, &ctx->pic_run_work); } -static void coda_free_framebuffers(struct coda_ctx *ctx); -static void coda_free_context_buffers(struct coda_ctx *ctx); - -static void coda_seq_end_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); - struct coda_dev *dev = ctx->dev; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_END failed\n"); - } - - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); - - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); -} - -static void coda_finish_decode(struct coda_ctx *ctx); -static void coda_finish_encode(struct coda_ctx *ctx); - static void coda_pic_run_work(struct work_struct *work) { struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); @@ -1500,20 +966,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) } } -static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) -{ - struct coda_dev *dev = ctx->dev; - u32 *p = ctx->parabuf.vaddr; - - if (dev->devtype->product == CODA_DX6) - p[index] = value; - else - p[index ^ 1] = value; -} - -static int coda_alloc_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf, size_t size, - const char *name, struct dentry *parent) +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent) { buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, GFP_KERNEL); @@ -1534,15 +988,8 @@ static int coda_alloc_aux_buf(struct coda_dev *dev, return 0; } -static inline int coda_alloc_context_buf(struct coda_ctx *ctx, - struct coda_aux_buf *buf, size_t size, - const char *name) -{ - return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); -} - -static void coda_free_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf) +void coda_free_aux_buf(struct coda_dev *dev, + struct coda_aux_buf *buf) { if (buf->vaddr) { dma_free_coherent(&dev->plat_dev->dev, buf->size, @@ -1553,538 +1000,21 @@ static void coda_free_aux_buf(struct coda_dev *dev, debugfs_remove(buf->dentry); } -static void coda_free_framebuffers(struct coda_ctx *ctx) +static int coda_start_streaming(struct vb2_queue *q, unsigned int count) { - int i; + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 dst_fourcc; + int ret = 0; - for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); -} - -static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc) -{ - struct coda_dev *dev = ctx->dev; - int width, height; - dma_addr_t paddr; - int ysize; - int ret; - int i; - - if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { - width = round_up(q_data->width, 16); - height = round_up(q_data->height, 16); - } else { - width = round_up(q_data->width, 8); - height = q_data->height; - } - ysize = width * height; - - /* Allocate frame buffers */ - for (i = 0; i < ctx->num_internal_frames; i++) { - size_t size; - char *name; - - size = ysize + ysize / 2; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - size += ysize / 4; - name = kasprintf(GFP_KERNEL, "fb%d", i); - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], - size, name); - kfree(name); - if (ret < 0) { - coda_free_framebuffers(ctx); - return ret; - } - } - - /* Register frame buffers in the parameter buffer */ - for (i = 0; i < ctx->num_internal_frames; i++) { - paddr = ctx->internal_frames[i].paddr; - coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ - - /* mvcol buffer for h.264 */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - coda_parabuf_write(ctx, 96 + i, - ctx->internal_frames[i].paddr + - ysize + ysize/4 + ysize/4); - } - - /* mvcol buffer for mpeg4 */ - if ((dev->devtype->product != CODA_DX6) && - (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) - coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + - ysize + ysize/4 + ysize/4); - - return 0; -} - -static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) -{ - phys_addr_t ret; - - size = round_up(size, 1024); - if (size > iram->remaining) - return 0; - iram->remaining -= size; - - ret = iram->next_paddr; - iram->next_paddr += size; - - return ret; -} - -static void coda_setup_iram(struct coda_ctx *ctx) -{ - struct coda_iram_info *iram_info = &ctx->iram_info; - struct coda_dev *dev = ctx->dev; - int mb_width; - int dbk_bits; - int bit_bits; - int ip_bits; - - memset(iram_info, 0, sizeof(*iram_info)); - iram_info->next_paddr = dev->iram.paddr; - iram_info->remaining = dev->iram.size; - - switch (dev->devtype->product) { - case CODA_7541: - dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; - bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - case CODA_960: - dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; - bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - default: /* CODA_DX6 */ - return; - } - - if (ctx->inst_type == CODA_INST_ENCODER) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - mb_width = DIV_ROUND_UP(q_data_src->width, 16); - - /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { - iram_info->search_ram_size = round_up(mb_width * 16 * - 36 + 2048, 1024); - iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); - if (!iram_info->search_ram_paddr) { - pr_err("IRAM is smaller than the search ram size\n"); - goto out; - } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; - } - - /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP disabled for encoder */ - } else if (ctx->inst_type == CODA_INST_DECODER) { - struct coda_q_data *q_data_dst; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - mb_width = DIV_ROUND_UP(q_data_dst->width, 16); - - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP unused as there is no VC1 support yet */ - } - -out: - if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "IRAM smaller than needed\n"); - - if (dev->devtype->product == CODA_7541) { - /* TODO - Enabling these causes picture errors on CODA7541 */ - if (ctx->inst_type == CODA_INST_DECODER) { - /* fw 1.4.50 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_IP_ENABLE); - } else { - /* fw 13.4.29 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_HOST_DBK_ENABLE | - CODA7_USE_IP_ENABLE | - CODA7_USE_DBK_ENABLE); - } - } -} - -static void coda_free_context_buffers(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - coda_free_aux_buf(dev, &ctx->slicebuf); - coda_free_aux_buf(dev, &ctx->psbuf); - if (dev->devtype->product != CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); -} - -static int coda_alloc_context_buffers(struct coda_ctx *ctx, - struct coda_q_data *q_data) -{ - struct coda_dev *dev = ctx->dev; - size_t size; - int ret; - - if (dev->devtype->product == CODA_DX6) - return 0; - - if (ctx->psbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); - return -EBUSY; - } - if (ctx->slicebuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); - return -EBUSY; - } - if (ctx->workbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); - ret = -EBUSY; - return -ENOMEM; - } - - if (q_data->fourcc == V4L2_PIX_FMT_H264) { - /* worst case slice size */ - size = (DIV_ROUND_UP(q_data->width, 16) * - DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", - ctx->slicebuf.size); - return ret; - } - } - - if (dev->devtype->product == CODA_7541) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); - goto err; - } - } - - size = dev->devtype->workbuf_size; - if (dev->devtype->product == CODA_960 && - q_data->fourcc == V4L2_PIX_FMT_H264) - size += CODA9_PS_SAVE_SIZE; - ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", - ctx->workbuf.size); - goto err; - } - - return 0; - -err: - coda_free_context_buffers(ctx); - return ret; -} - -static int __coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct coda_dev *dev = ctx->dev; - int width, height; - u32 src_fourcc; - u32 val; - int ret; - - /* Start decoding */ - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - bitstream_buf = ctx->bitstream.paddr; - bitstream_size = ctx->bitstream.size; - src_fourcc = q_data_src->fourcc; - - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - - /* Update coda bitstream read and write pointers from kfifo */ - coda_kfifo_sync_to_device_full(ctx); - - ctx->display_idx = -1; - ctx->frm_dis_flg = 0; - coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, - CODA_REG_BIT_BIT_STREAM_PARAM); - - coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); - val = 0; - if ((dev->devtype->product == CODA_7541) || - (dev->devtype->product == CODA_960)) - val |= CODA_REORDER_ENABLE; - coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); - - ctx->params.codec_mode = ctx->codec->mode; - if (dev->devtype->product == CODA_960 && - src_fourcc == V4L2_PIX_FMT_MPEG4) - ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; - else - ctx->params.codec_mode_aux = 0; - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { - coda_write(dev, ctx->psbuf.paddr, - CODA_CMD_DEC_SEQ_PS_BB_START); - coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), - CODA_CMD_DEC_SEQ_PS_BB_SIZE); - } - if (dev->devtype->product == CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); - coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); - } - } - if (dev->devtype->product != CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - return -ETIMEDOUT; - } - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - - if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", - coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); - return -EAGAIN; - } - - val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); - if (dev->devtype->product == CODA_DX6) { - width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; - height = val & CODADX6_PICHEIGHT_MASK; - } else { - width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; - height = val & CODA7_PICHEIGHT_MASK; - } - - if (width > q_data_dst->width || height > q_data_dst->height) { - v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->width, q_data_dst->height); - return -EINVAL; - } - - width = round_up(width, 16); - height = round_up(height, 16); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", - __func__, ctx->idx, width, height); - - ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); - if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { - v4l2_err(&dev->v4l2_dev, - "not enough framebuffers to decode (%d < %d)\n", - CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); - return -EINVAL; - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); - - q_data_dst->rect.left = (left_right >> 10) & 0x3ff; - q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; - q_data_dst->rect.width = width - q_data_dst->rect.left - - (left_right & 0x3ff); - q_data_dst->rect.height = height - q_data_dst->rect.top - - (top_bottom & 0x3ff); - } - - ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) - return ret; - - /* Tell the decoder how many frame buffers we allocated. */ - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); - - if (dev->devtype->product != CODA_DX6) { - /* Set secondary AXI IRAM */ - coda_setup_iram(ctx); - - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - - coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); - coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | - 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, - CODA9_CMD_SET_FRAME_CACHE_CONFIG); - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - coda_write(dev, ctx->slicebuf.paddr, - CODA_CMD_SET_FRAME_SLICE_BB_START); - coda_write(dev, ctx->slicebuf.size / 1024, - CODA_CMD_SET_FRAME_SLICE_BB_SIZE); - } - - if (dev->devtype->product == CODA_7541) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); - } else if (dev->devtype->product == CODA_960) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { - v4l2_err(&ctx->dev->v4l2_dev, - "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int ret; - - mutex_lock(&dev->coda_mutex); - ret = __coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); - - return ret; -} - -static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, - int header_code, u8 *header, int *size) -{ - struct coda_dev *dev = ctx->dev; - size_t bufsize; - int ret; - int i; - - if (dev->devtype->product == CODA_960) - memset(vb2_plane_vaddr(buf, 0), 0, 64); - - coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), - CODA_CMD_ENC_HEADER_BB_START); - bufsize = vb2_plane_size(buf, 0); - if (dev->devtype->product == CODA_960) - bufsize /= 1024; - coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); - coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); - ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); - return ret; - } - - if (dev->devtype->product == CODA_960) { - for (i = 63; i > 0; i--) - if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) - break; - *size = i + 1; - } else { - *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - - coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); - } - memcpy(header, vb2_plane_vaddr(buf, 0), *size); - - return 0; -} - -static int coda_start_encoding(struct coda_ctx *ctx); - -static int coda_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 dst_fourcc; - int ret = 0; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { - /* copy the buffers that where queued before streamon */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { + /* copy the buffers that where queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); if (coda_get_bitstream_payload(ctx) < 512) return -EINVAL; @@ -2132,337 +1062,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return ret; } -static int coda_start_encoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct vb2_buffer *buf; - int gamma, ret, value; - u32 dst_fourcc; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); - bitstream_size = q_data_dst->sizeimage; - - if (!coda_is_initialized(dev)) { - v4l2_err(v4l2_dev, "coda is not initialized.\n"); - return -EFAULT; - } - - mutex_lock(&dev->coda_mutex); - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | - CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - case CODA_960: - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - /* fallthrough */ - case CODA_7541: - coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | - CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - } - - value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); - value &= ~(1 << 2 | 0x7 << 9); - ctx->frame_mem_ctrl = value; - coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product == CODA_DX6) { - /* Configure the coda */ - coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); - } - - /* Could set rotation here if needed */ - switch (dev->devtype->product) { - case CODA_DX6: - value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - case CODA_7541: - if (dst_fourcc == V4L2_PIX_FMT_H264) { - value = (round_up(q_data_src->width, 16) & - CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (round_up(q_data_src->height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - } - /* fallthrough */ - case CODA_960: - value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); - coda_write(dev, ctx->params.framerate, - CODA_CMD_ENC_SEQ_SRC_F_RATE); - - ctx->params.codec_mode = ctx->codec->mode; - switch (dst_fourcc) { - case V4L2_PIX_FMT_MPEG4: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); - break; - case V4L2_PIX_FMT_H264: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - if (ctx->params.h264_deblk_enabled) { - value = ((ctx->params.h264_deblk_alpha & - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | - ((ctx->params.h264_deblk_beta & - CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); - } else { - value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); - break; - default: - v4l2_err(v4l2_dev, - "dst format (0x%08x) invalid.\n", dst_fourcc); - ret = -EINVAL; - goto out; - } - - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; - coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); - - if (ctx->params.bitrate) { - /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; - value |= 1 & CODA_RATECONTROL_ENABLE_MASK; - if (dev->devtype->product == CODA_960) - value |= BIT(31); /* disable autoskip */ - } else { - value = 0; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); - - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); - coda_write(dev, ctx->params.intra_refresh, - CODA_CMD_ENC_SEQ_INTRA_REFRESH); - - coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); - - - value = 0; - if (dev->devtype->product == CODA_960) - gamma = CODA9_DEFAULT_GAMMA; - else - gamma = CODA_DEFAULT_GAMMA; - if (gamma > 0) { - coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, - CODA_CMD_ENC_SEQ_RC_GAMMA); - } - - if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { - coda_write(dev, - ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | - ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, - CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); - } - if (dev->devtype->product == CODA_960) { - if (ctx->params.h264_max_qp) - value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; - if (CODA_DEFAULT_GAMMA > 0) - value |= 1 << CODA9_OPTION_GAMMA_OFFSET; - } else { - if (CODA_DEFAULT_GAMMA > 0) { - if (dev->devtype->product == CODA_DX6) - value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; - else - value |= 1 << CODA7_OPTION_GAMMA_OFFSET; - } - if (ctx->params.h264_min_qp) - value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; - if (ctx->params.h264_max_qp) - value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); - - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); - - coda_setup_iram(ctx); - - if (dst_fourcc == V4L2_PIX_FMT_H264) { - switch (dev->devtype->product) { - case CODA_DX6: - value = FMO_SLICE_SAVE_BUF_SIZE << 7; - coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); - break; - case CODA_7541: - coda_write(dev, ctx->iram_info.search_ram_paddr, - CODA7_CMD_ENC_SEQ_SEARCH_BASE); - coda_write(dev, ctx->iram_info.search_ram_size, - CODA7_CMD_ENC_SEQ_SEARCH_SIZE); - break; - case CODA_960: - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - goto out; - } - - if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); - ret = -EFAULT; - goto out; - } - - if (dev->devtype->product == CODA_960) - ctx->num_internal_frames = 4; - else - ctx->num_internal_frames = 2; - ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); - if (ret < 0) { - v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); - goto out; - } - - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, q_data_src->bytesperline, - CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { - coda_write(dev, q_data_src->bytesperline, - CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); - } - if (dev->devtype->product != CODA_DX6) { - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); - coda_write(dev, ctx->iram_info.buf_ovl_use, - CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) { - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - - /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - goto out; - } - - /* Save stream headers */ - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - /* - * Get SPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - /* - * Get PPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - /* - * Length of H.264 headers is variable and thus it might not be - * aligned for the coda to append the encoded frame. In that is - * the case a filler NAL must be added to header 2. - */ - ctx->vpu_header_size[2] = coda_h264_padding( - (ctx->vpu_header_size[0] + - ctx->vpu_header_size[1]), - ctx->vpu_header[2]); - break; - case V4L2_PIX_FMT_MPEG4: - /* - * Get VOS in the first frame and copy it to an - * intermediate buffer - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, - &ctx->vpu_header[2][0], - &ctx->vpu_header_size[2]); - if (ret < 0) - goto out; - break; - default: - /* No more formats need to save headers at the moment */ - break; - } - -out: - mutex_unlock(&dev->coda_mutex); - return ret; -} - static void coda_stop_streaming(struct vb2_queue *q) { struct coda_ctx *ctx = vb2_get_drv_priv(q); @@ -2662,8 +1261,8 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) return vb2_queue_init(vq); } -static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { int ret; @@ -2682,8 +1281,8 @@ static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, return coda_queue_init(priv, dst_vq); } -static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { int ret; @@ -2843,38 +1442,14 @@ err_coda_max: return ret; } -static void coda_bit_release(struct coda_ctx *ctx) -{ - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); -} - -struct coda_context_ops coda_encode_ops = { - .queue_init = coda_encoder_queue_init, - .start_streaming = coda_start_encoding, - .prepare_run = coda_prepare_encode, - .finish_run = coda_finish_encode, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - -struct coda_context_ops coda_decode_ops = { - .queue_init = coda_decoder_queue_init, - .start_streaming = coda_start_decoding, - .prepare_run = coda_prepare_decode, - .finish_run = coda_finish_decode, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - static int coda_encoder_open(struct file *file) { - return coda_open(file, CODA_INST_ENCODER, &coda_encode_ops); + return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops); } static int coda_decoder_open(struct file *file) { - return coda_open(file, CODA_INST_DECODER, &coda_decode_ops); + return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops); } static int coda_release(struct file *file) @@ -2938,316 +1513,6 @@ static const struct v4l2_file_operations coda_decoder_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static void coda_finish_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src; - struct coda_q_data *q_data_dst; - struct vb2_buffer *dst_buf; - struct coda_timestamp *ts; - int width, height; - int decoded_idx; - int display_idx; - u32 src_fourcc; - int success; - u32 err_mb; - u32 val; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - /* - * in stream-end mode, the read pointer can overshoot the write pointer - * by up to 512 bytes - */ - if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - } - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_fourcc = q_data_src->fourcc; - - val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); - if (val != 1) - pr_err("DEC_PIC_SUCCESS = %d\n", val); - - success = val & 0x1; - if (!success) - v4l2_err(&dev->v4l2_dev, "decode failed\n"); - - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (val & (1 << 3)) - v4l2_err(&dev->v4l2_dev, - "insufficient PS buffer space (%d bytes)\n", - ctx->psbuf.size); - if (val & (1 << 2)) - v4l2_err(&dev->v4l2_dev, - "insufficient slice buffer space (%d bytes)\n", - ctx->slicebuf.size); - } - - val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); - width = (val >> 16) & 0xffff; - height = val & 0xffff; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - /* frame crop information */ - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); - - if (left_right == 0xffffffff && top_bottom == 0xffffffff) { - /* Keep current crop information */ - } else { - struct v4l2_rect *rect = &q_data_dst->rect; - - rect->left = left_right >> 16 & 0xffff; - rect->top = top_bottom >> 16 & 0xffff; - rect->width = width - rect->left - - (left_right & 0xffff); - rect->height = height - rect->top - - (top_bottom & 0xffff); - } - } else { - /* no cropping */ - } - - err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); - if (err_mb > 0) - v4l2_err(&dev->v4l2_dev, - "errors in %d macroblocks\n", err_mb); - - if (dev->devtype->product == CODA_7541) { - val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); - if (val == 0) { - /* not enough bitstream data */ - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "prescan failed: %d\n", val); - ctx->hold = true; - return; - } - } - - ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - /* - * The previous display frame was copied out by the rotator, - * now it can be overwritten again - */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - ctx->frm_dis_flg &= ~(1 << ctx->display_idx); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - } - - /* - * The index of the last decoded frame, not necessarily in - * display order, and the index of the next display frame. - * The latter could have been decoded in a previous run. - */ - decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); - display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); - - if (decoded_idx == -1) { - /* no frame was decoded, but we might have a display frame */ - if (display_idx >= 0 && display_idx < ctx->num_internal_frames) - ctx->sequence_offset++; - else if (ctx->display_idx < 0) - ctx->hold = true; - } else if (decoded_idx == -2) { - /* no frame was decoded, we still return the remaining buffers */ - } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "decoded frame index out of range: %d\n", decoded_idx); - } else { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; - val -= ctx->sequence_offset; - if (val != (ts->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, ts->sequence); - } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); - - val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - if (val == 0) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; - else if (val == 1) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; - else - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; - - ctx->frame_errors[decoded_idx] = err_mb; - } - - if (display_idx == -1) { - /* - * no more frames to be decoded, but there could still - * be rotator output to dequeue - */ - ctx->hold = true; - } else if (display_idx == -3) { - /* possibly prescan failure */ - } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "presentation frame index out of range: %d\n", - display_idx); - } - - /* If a frame was copied out, return it */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->v4l2_buf.sequence = ctx->osequence++; - - dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME); - dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; - ts = &ctx->frame_timestamps[ctx->display_idx]; - dst_buf->v4l2_buf.timecode = ts->timecode; - dst_buf->v4l2_buf.timestamp = ts->timestamp; - - vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); - - v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: decoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); - } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: no frame decoded\n"); - } - - /* The rotator will copy the current display frame next time */ - ctx->display_idx = display_idx; -} - -static void coda_finish_encode(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr, start_ptr; - - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Get results from the coda */ - start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); - wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - - /* Calculate bytesused field */ - if (dst_buf->v4l2_buf.sequence == 0) { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]); - } else { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); - } - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", - wr_ptr - start_ptr); - - coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); - coda_read(dev, CODA_RET_ENC_PIC_FLAG); - - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } else { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } - - dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.flags |= - src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); - - ctx->gopcounter--; - if (ctx->gopcounter < 0) - ctx->gopcounter = ctx->params.gop_size - 1; - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: encoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); -} - -static irqreturn_t coda_irq_handler(int irq, void *data) -{ - struct coda_dev *dev = data; - struct coda_ctx *ctx; - - /* read status register to attend the IRQ */ - coda_read(dev, CODA_REG_BIT_INT_STATUS); - coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, - CODA_REG_BIT_INT_CLEAR); - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); - return IRQ_HANDLED; - } - - if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "task has been aborted\n"); - } - - if (coda_isbusy(ctx->dev)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "coda is still busy!!!!\n"); - return IRQ_NONE; - } - - complete(&ctx->completion); - - return IRQ_HANDLED; -} - -static u32 coda_supported_firmwares[] = { - CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), - CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), -}; - -static bool coda_firmware_supported(u32 vernum) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) - if (vernum == coda_supported_firmwares[i]) - return true; - return false; -} - static int coda_hw_init(struct coda_dev *dev) { u32 data; @@ -3344,76 +1609,6 @@ err_clk_per: return ret; } -static int coda_check_firmware(struct coda_dev *dev) -{ - u16 product, major, minor, release; - u32 data; - int ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); - if (coda_wait_timeout(dev)) { - v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); - ret = -EIO; - goto err_run_cmd; - } - - if (dev->devtype->product == CODA_960) { - data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); - v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", - data); - } - - /* Check we are compatible with the loaded firmware */ - data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); - product = CODA_FIRMWARE_PRODUCT(data); - major = CODA_FIRMWARE_MAJOR(data); - minor = CODA_FIRMWARE_MINOR(data); - release = CODA_FIRMWARE_RELEASE(data); - - clk_disable_unprepare(dev->clk_per); - clk_disable_unprepare(dev->clk_ahb); - - if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," - " Version: %u.%u.%u\n", - coda_product_name(dev->devtype->product), - coda_product_name(product), major, minor, release); - return -EINVAL; - } - - v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", - coda_product_name(product)); - - if (coda_firmware_supported(data)) { - v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", - major, minor, release); - } else { - v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " - "%u.%u.%u\n", major, minor, release); - } - - return 0; - -err_run_cmd: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) { vfd->release = video_device_release_empty, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 84e0829afc85..bbc18c0dacd9 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -228,4 +228,60 @@ struct coda_ctx { struct dentry *debugfs_entry; }; +extern int coda_debug; + +void coda_write(struct coda_dev *dev, u32 data, u32 reg); +unsigned int coda_read(struct coda_dev *dev, u32 reg); + +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent); +void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); + +static inline int coda_alloc_context_buf(struct coda_ctx *ctx, + struct coda_aux_buf *buf, size_t size, + const char *name) +{ + return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); +} + +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + +int coda_hw_reset(struct coda_ctx *ctx); + +void coda_fill_bitstream(struct coda_ctx *ctx); + +void coda_set_gdi_regs(struct coda_ctx *ctx); + +static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &(ctx->q_data[V4L2_M2M_SRC]); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &(ctx->q_data[V4L2_M2M_DST]); + default: + return NULL; + } +} + +const char *coda_product_name(int product); + +int coda_check_firmware(struct coda_dev *dev); + +static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) +{ + return kfifo_len(&ctx->bitstream_fifo); +} + +void coda_bit_stream_end_flag(struct coda_ctx *ctx); + int coda_h264_padding(int size, char *p); + +extern const struct coda_context_ops coda_bit_encode_ops; +extern const struct coda_context_ops coda_bit_decode_ops; + +irqreturn_t coda_irq_handler(int irq, void *data); -- cgit v1.2.3 From 2c3759d406ded38b88992cb4e423ce232112001a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:06 -0300 Subject: [media] coda: include header for memcpy coda_h264_padding uses memcpy, we should include string.h for that. Reported-by: Ian Jamison Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-h264.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index 0b2fdbeea7cb..456773af1f1d 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c @@ -12,6 +12,7 @@ */ #include +#include static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -- cgit v1.2.3 From 5727a5a4a1d89a8bf1442e7b0fd83de63512a1b6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:08 -0300 Subject: [media] coda: remove unnecessary peek at next destination buffer from coda_finish_decode The return value of this call to v4l2_m2m_next_dst_buf() is never used. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 1d2716d564a1..cc9afb733b48 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1580,8 +1580,6 @@ static void coda_finish_decode(struct coda_ctx *ctx) u32 err_mb; u32 val; - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); -- cgit v1.2.3 From 540b72e415d6033b72037dbdb1f6c00516034250 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:09 -0300 Subject: [media] coda: request BIT processor interrupt by name Request the main coda interrupt using its name, "bit", if available. Fall back to requesting the first interrupt for backwards compatibility. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dc9740d0ea5e..86fc527a7782 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1835,7 +1835,9 @@ static int coda_probe(struct platform_device *pdev) return PTR_ERR(dev->regs_base); /* IRQ */ - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq_byname(pdev, "bit"); + if (irq < 0) + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get irq resource\n"); return irq; -- cgit v1.2.3 From b906352c23388837a643720d8548ae9459b5ed76 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:10 -0300 Subject: [media] coda: dequeue buffers if start_streaming fails Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 34 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 86fc527a7782..1e938895f5f9 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1005,6 +1005,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *buf; u32 dst_fourcc; int ret = 0; @@ -1016,17 +1017,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) coda_fill_bitstream(ctx); mutex_unlock(&ctx->bitstream_mutex); - if (coda_get_bitstream_payload(ctx) < 512) - return -EINVAL; + if (coda_get_bitstream_payload(ctx) < 512) { + ret = -EINVAL; + goto err; + } } else { - if (count < 1) - return -EINVAL; + if (count < 1) { + ret = -EINVAL; + goto err; + } } ctx->streamon_out = 1; } else { - if (count < 1) - return -EINVAL; + if (count < 1) { + ret = -EINVAL; + goto err; + } ctx->streamon_cap = 1; } @@ -1047,7 +1054,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) q_data_dst->fourcc); if (!ctx->codec) { v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } ret = ctx->ops->start_streaming(ctx); @@ -1055,11 +1063,21 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (ret == -EAGAIN) return 0; else if (ret < 0) - return ret; + goto err; } ctx->initialized = 1; return ret; + +err: + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + } + return ret; } static void coda_stop_streaming(struct vb2_queue *q) -- cgit v1.2.3 From 4a31b52fca20d1fc0abe0d0f5489b9eec2760219 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:11 -0300 Subject: [media] coda: dequeue buffers on streamoff This is needed to decrease the q->owned_by_drv_count to zero before __vb2_queue_cancel is called, to avoid the WARN_ON therein. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1e938895f5f9..6760e346f969 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1084,6 +1084,7 @@ static void coda_stop_streaming(struct vb2_queue *q) { struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; + struct vb2_buffer *buf; if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, @@ -1091,7 +1092,11 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->streamon_out = 0; coda_bit_stream_end_flag(ctx); + ctx->isequence = 0; + + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } else { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s: capture\n", __func__); @@ -1099,6 +1104,9 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->osequence = 0; ctx->sequence_offset = 0; + + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } if (!ctx->streamon_out && !ctx->streamon_cap) { -- cgit v1.2.3 From fcf59764b99c7daa9b0876fe65d1393e6b759673 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:12 -0300 Subject: [media] coda: skip calling coda_find_codec in encoder try_fmt_vid_out We know that it will return NULL in this case, so we can just as well skip it altogether. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6760e346f969..4e85e387f905 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -426,14 +426,15 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec; + const struct coda_codec *codec = NULL; /* Determine codec by encoded format, returns NULL if raw or invalid */ - codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, - V4L2_PIX_FMT_YUV420); - if (!codec && ctx->inst_type == CODA_INST_DECODER) { - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + if (ctx->inst_type == CODA_INST_DECODER) { + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, V4L2_PIX_FMT_YUV420); + if (!codec) + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_YUV420); if (!codec) return -EINVAL; } -- cgit v1.2.3 From 8be31c898deea6ac57bc1dc4973b88c931c82980 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:13 -0300 Subject: [media] coda: allow running coda without iram on mx6dl Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ drivers/media/platform/coda/coda-common.c | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index cc9afb733b48..fddd10d53558 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -474,6 +474,9 @@ static void coda_setup_iram(struct coda_ctx *ctx) iram_info->next_paddr = dev->iram.paddr; iram_info->remaining = dev->iram.size; + if (!dev->iram.vaddr) + return; + switch (dev->devtype->product) { case CODA_7541: dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 4e85e387f905..3bf30b8215dd 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1947,15 +1947,15 @@ static int coda_probe(struct platform_device *pdev) dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, &dev->iram.paddr); if (!dev->iram.vaddr) { - dev_err(&pdev->dev, "unable to alloc iram\n"); - return -ENOMEM; + dev_warn(&pdev->dev, "unable to alloc iram\n"); + } else { + dev->iram.blob.data = dev->iram.vaddr; + dev->iram.blob.size = dev->iram.size; + dev->iram.dentry = debugfs_create_blob("iram", 0644, + dev->debugfs_root, + &dev->iram.blob); } - dev->iram.blob.data = dev->iram.vaddr; - dev->iram.blob.size = dev->iram.size; - dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root, - &dev->iram.blob); - dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); if (!dev->workqueue) { dev_err(&pdev->dev, "unable to alloc workqueue\n"); -- cgit v1.2.3 From b0ed05b9025528b8480ba12d8e706eef6fe1dbc5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:14 -0300 Subject: [media] coda: increase max vertical frame size to 1088 This patch increases the maximum vertical frame size reported by enum_fmt and accepted by try_fmt/s_fmt from 1080 to 1088. Since for 16x16-pixel macroblocks 1080p will be rounded up to this anyway, we may as well admit that we support it. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3bf30b8215dd..6020e336c998 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -39,7 +39,6 @@ #include #include "coda.h" -#include "coda_regs.h" #define CODA_NAME "coda" @@ -122,15 +121,15 @@ static const struct coda_codec codadx6_codecs[] = { static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), - CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; static const struct coda_codec coda9_codecs[] = { - CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), - CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), + CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; static bool coda_format_is_yuv(u32 fourcc) -- cgit v1.2.3 From d60b18ba318ec4fb32851ad72f33e1dbc1b641f0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:15 -0300 Subject: [media] coda: add an intermediate debug level Dumping all register accesses drowns other debugging messages in the log. Add a less verbose debug level. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6020e336c998..73114529b2c4 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -58,7 +58,7 @@ int coda_debug; module_param(coda_debug, int, 0644); -MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); +MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); struct coda_fmt { char *name; @@ -67,7 +67,7 @@ struct coda_fmt { void coda_write(struct coda_dev *dev, u32 data, u32 reg) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } @@ -76,7 +76,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; data = readl(dev->regs_base + reg); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); return data; } -- cgit v1.2.3 From 68fc31c5d29690685476ea3fbc7da8876f227792 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:16 -0300 Subject: [media] coda: improve allocation error messages Produce some error messages when internal buffer allocation fails, for example because the CMA region is too small. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 +++- drivers/media/platform/coda/coda-common.c | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index fddd10d53558..529cc3e8acb0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1378,8 +1378,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) } ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); return ret; + } /* Tell the decoder how many frame buffers we allocated. */ coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 73114529b2c4..0f8a2c970405 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -971,8 +971,12 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, { buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, GFP_KERNEL); - if (!buf->vaddr) + if (!buf->vaddr) { + v4l2_err(&dev->v4l2_dev, + "Failed to allocate %s buffer of size %u\n", + name, size); return -ENOMEM; + } buf->size = size; -- cgit v1.2.3 From 18fd0cceb99fdfd551bb6520703f8e1be4f3f364 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:17 -0300 Subject: [media] coda: fix timestamp list handling Lock modification of the timestamp list with bitstream_mutex and do not try to remove a timestamp element if the list is empty. This can happen if the userspace feeds us garbage or multiple encoded frames in a single buffer. Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 28 +++++++++++++++++++--------- drivers/media/platform/coda/coda-common.c | 2 ++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 529cc3e8acb0..18fa369d204d 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1699,18 +1699,28 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; - if (val != (ts->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, ts->sequence); + mutex_lock(&ctx->bitstream_mutex); + if (!list_empty(&ctx->timestamp_list)) { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + if (val != (ts->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + val, ctx->sequence_offset, + ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + } else { + v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); + memset(&ctx->frame_timestamps[decoded_idx], 0, + sizeof(struct coda_timestamp)); + ctx->frame_timestamps[decoded_idx].sequence = val; } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); + mutex_unlock(&ctx->bitstream_mutex); val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; if (val == 0) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 0f8a2c970405..e84b32088fc0 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1116,12 +1116,14 @@ static void coda_stop_streaming(struct vb2_queue *q) if (!ctx->streamon_out && !ctx->streamon_cap) { struct coda_timestamp *ts; + mutex_lock(&ctx->bitstream_mutex); while (!list_empty(&ctx->timestamp_list)) { ts = list_first_entry(&ctx->timestamp_list, struct coda_timestamp, list); list_del(&ts->list); kfree(ts); } + mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; -- cgit v1.2.3 From 2dc546d00c8deb22aac50c8cc0c6293aab975c6b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:18 -0300 Subject: [media] coda: fix coda_s_fmt_vid_out Set the context color space when s_fmt succeeded, not when it failed. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index e84b32088fc0..dfecb8602f07 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -504,7 +504,9 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ret = coda_s_fmt(ctx, f); if (ret) - ctx->colorspace = f->fmt.pix.colorspace; + return ret; + + ctx->colorspace = f->fmt.pix.colorspace; return ret; } -- cgit v1.2.3 From f95a6ce16736ac3aca4eda2238ccdf1913f3567f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:19 -0300 Subject: [media] coda: set capture frame size with output S_FMT This patch makes coda_s_fmt_vid_out propagate the output frame size to the capture side. The GStreamer v4l2videodec only ever calls S_FMT on the output side and then expects G_FMT on the capture side to return a valid format. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dfecb8602f07..a1080a7728e6 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -496,6 +496,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); + struct v4l2_format f_cap; int ret; ret = coda_try_fmt_vid_out(file, priv, f); @@ -508,7 +509,16 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ctx->colorspace = f->fmt.pix.colorspace; - return ret; + f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + coda_g_fmt(file, priv, &f_cap); + f_cap.fmt.pix.width = f->fmt.pix.width; + f_cap.fmt.pix.height = f->fmt.pix.height; + + ret = coda_try_fmt_vid_cap(file, priv, &f_cap); + if (ret) + return ret; + + return coda_s_fmt(ctx, &f_cap); } static int coda_qbuf(struct file *file, void *priv, -- cgit v1.2.3 From a188a668dda4ea6b9454066343b78d662946fe07 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:20 -0300 Subject: [media] coda: disable old cropping ioctls Since we neither support composing on the OUTPUT side, nor cropping on the CAPTURE side, disable VIDIOC_CROPCAP and VIDIOC_G/S_CROP altogether. This silences a GStreamer warning when GStreamer tries to obtain the pixel aspect ratio using VIDIOC_CROPCAP. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index a1080a7728e6..ffb4c76e5755 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1661,6 +1661,11 @@ static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) vfd->vfl_dir = VFL_DIR_M2M; video_set_drvdata(vfd, dev); + /* Not applicable, use the selection API instead */ + v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP); + v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); + v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); + return video_register_device(vfd, VFL_TYPE_GRABBER, 0); } -- cgit v1.2.3 From f23797b636c4d69b29d2739ba5fc0e36b4e47390 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 6 Aug 2014 08:02:23 -0300 Subject: [media] coda: checkpatch cleanup This patch breaks most long lines, concatenates broken up text strings, and adds or removes parentheses where needed to make checkpatch happy. The long codec list lines and a few 81-wide lines remain. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 143 +++++++++++++++++++----------- drivers/media/platform/coda/coda-common.c | 34 ++++--- 2 files changed, 113 insertions(+), 64 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 18fa369d204d..07fc91aba1e0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -37,7 +37,7 @@ static inline int coda_is_initialized(struct coda_dev *dev) { - return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); + return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; } static inline unsigned long coda_isbusy(struct coda_dev *dev) @@ -165,17 +165,20 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); } -static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) +static int coda_bitstream_queue(struct coda_ctx *ctx, + struct vb2_buffer *src_buf) { u32 src_size = vb2_get_plane_payload(src_buf, 0); u32 n; - n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); + n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), + src_size); if (n < src_size) return -ENOSPC; - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, - ctx->bitstream.size, DMA_TO_DEVICE); + dma_sync_single_for_device(&ctx->dev->plat_dev->dev, + ctx->bitstream.paddr, ctx->bitstream.size, + DMA_TO_DEVICE); src_buf->v4l2_buf.sequence = ctx->qsequence++; @@ -246,11 +249,12 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx) ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + /* If this context is currently running, update the hardware flag */ if ((dev->devtype->product == CODA_960) && coda_isbusy(dev) && (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); } } @@ -315,9 +319,10 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, /* Register frame buffers in the parameter buffer */ for (i = 0; i < ctx->num_internal_frames; i++) { paddr = ctx->internal_frames[i].paddr; - coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ + /* Start addresses of Y, Cb, Cr planes */ + coda_parabuf_write(ctx, i * 3 + 0, paddr); + coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); + coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4); /* mvcol buffer for h.264 */ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && @@ -374,18 +379,22 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, /* worst case slice size */ size = (DIV_ROUND_UP(q_data->width, 16) * DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, + "slicebuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", + v4l2_err(&dev->v4l2_dev, + "failed to allocate %d byte slice buffer", ctx->slicebuf.size); return ret; } } if (dev->devtype->product == CODA_7541) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, + CODA7_PS_BUF_SIZE, "psbuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); + v4l2_err(&dev->v4l2_dev, + "failed to allocate psmem buffer"); goto err; } } @@ -396,7 +405,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, size += CODA9_PS_SAVE_SIZE; ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", + v4l2_err(&dev->v4l2_dev, + "failed to allocate %d byte context buffer", ctx->workbuf.size); goto err; } @@ -465,6 +475,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) { struct coda_iram_info *iram_info = &ctx->iram_info; struct coda_dev *dev = ctx->dev; + int w64, w128; int mb_width; int dbk_bits; int bit_bits; @@ -497,13 +508,15 @@ static void coda_setup_iram(struct coda_ctx *ctx) q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); mb_width = DIV_ROUND_UP(q_data_src->width, 16); + w128 = mb_width * 128; + w64 = mb_width * 64; /* Prioritize in case IRAM is too small for everything */ if (dev->devtype->product == CODA_7541) { iram_info->search_ram_size = round_up(mb_width * 16 * 36 + 2048, 1024); iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); + iram_info->search_ram_size); if (!iram_info->search_ram_paddr) { pr_err("IRAM is smaller than the search ram size\n"); goto out; @@ -513,18 +526,18 @@ static void coda_setup_iram(struct coda_ctx *ctx) } /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); if (!iram_info->buf_dbk_c_use) goto out; iram_info->axi_sram_use |= dbk_bits; - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_bit_use) goto out; iram_info->axi_sram_use |= bit_bits; - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_ip_ac_dc_use) goto out; iram_info->axi_sram_use |= ip_bits; @@ -535,19 +548,20 @@ static void coda_setup_iram(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + w128 = mb_width * 128; - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_dbk_c_use) goto out; iram_info->axi_sram_use |= dbk_bits; - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_bit_use) goto out; iram_info->axi_sram_use |= bit_bits; - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_ip_ac_dc_use) goto out; iram_info->axi_sram_use |= ip_bits; @@ -634,8 +648,8 @@ int coda_check_firmware(struct coda_dev *dev) clk_disable_unprepare(dev->clk_ahb); if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," - " Version: %u.%u.%u\n", + v4l2_err(&dev->v4l2_dev, + "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", coda_product_name(dev->devtype->product), coda_product_name(product), major, minor, release); return -EINVAL; @@ -648,8 +662,9 @@ int coda_check_firmware(struct coda_dev *dev) v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", major, minor, release); } else { - v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " - "%u.%u.%u\n", major, minor, release); + v4l2_warn(&dev->v4l2_dev, + "Unsupported firmware version: %u.%u.%u\n", + major, minor, release); } return 0; @@ -720,27 +735,32 @@ static int coda_start_encoding(struct coda_ctx *ctx) if (dev->devtype->product == CODA_DX6) { /* Configure the coda */ - coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + coda_write(dev, dev->iram.paddr, + CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); } /* Could set rotation here if needed */ switch (dev->devtype->product) { case CODA_DX6: - value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) + << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; break; case CODA_7541: if (dst_fourcc == V4L2_PIX_FMT_H264) { value = (round_up(q_data_src->width, 16) & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; value |= (round_up(q_data_src->height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; } /* fallthrough */ case CODA_960: - value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + value = (q_data_src->width & CODA7_PICWIDTH_MASK) + << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; } coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); coda_write(dev, ctx->params.framerate, @@ -750,16 +770,20 @@ static int coda_start_encoding(struct coda_ctx *ctx) switch (dst_fourcc) { case V4L2_PIX_FMT_MPEG4: if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA9_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); else - coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); break; case V4L2_PIX_FMT_H264: if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA9_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); else - coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); if (ctx->params.h264_deblk_enabled) { value = ((ctx->params.h264_deblk_alpha & CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << @@ -784,13 +808,17 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = 0; break; case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; value |= 1 & CODA_SLICING_MODE_MASK; break; case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; value |= 1 & CODA_SLICING_MODE_MASK; break; } @@ -800,7 +828,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) if (ctx->params.bitrate) { /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) + << CODA_RATECONTROL_BITRATE_OFFSET; value |= 1 & CODA_RATECONTROL_ENABLE_MASK; if (dev->devtype->product == CODA_960) value |= BIT(31); /* disable autoskip */ @@ -919,8 +948,10 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); + coda_write(dev, ctx->internal_frames[2].paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_B); } } @@ -1092,7 +1123,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx) } /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, + CODA_CMD_ENC_PIC_ROT_MODE); coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); @@ -1135,9 +1167,10 @@ static int coda_prepare_encode(struct coda_ctx *ctx) CODA_CMD_ENC_PIC_BB_SIZE); if (!ctx->streamon_out) { - /* After streamoff on the output side, set the stream end flag */ + /* After streamoff on the output side, set stream end flag */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); } if (dev->devtype->product != CODA_DX6) @@ -1217,7 +1250,8 @@ static void coda_seq_end_work(struct work_struct *work) mutex_lock(&dev->coda_mutex); v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); + "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, + __func__); if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_END failed\n"); @@ -1550,7 +1584,8 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); break; case CODA_960: - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ + /* 'hardcode to use interrupt disable mode'? */ + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); break; } @@ -1666,7 +1701,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) } } - ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + ctx->frm_dis_flg = coda_read(dev, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); /* * The previous display frame was copied out by the rotator, @@ -1694,7 +1730,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) else if (ctx->display_idx < 0) ctx->hold = true; } else if (decoded_idx == -2) { - /* no frame was decoded, we still return the remaining buffers */ + /* no frame was decoded, we still return remaining buffers */ } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); @@ -1801,7 +1837,8 @@ irqreturn_t coda_irq_handler(int irq, void *data) ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + v4l2_err(&dev->v4l2_dev, + "Instance released before the end of transaction\n"); mutex_unlock(&dev->coda_mutex); return IRQ_HANDLED; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index ffb4c76e5755..0997b5c677bd 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -75,6 +75,7 @@ void coda_write(struct coda_dev *dev, u32 data, u32 reg) unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; + data = readl(dev->regs_base + reg); v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); @@ -736,7 +737,8 @@ static void coda_pic_run_work(struct work_struct *work) return; } - if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { + if (!wait_for_completion_timeout(&ctx->completion, + msecs_to_jiffies(1000))) { dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); ctx->hold = true; @@ -812,6 +814,7 @@ static void coda_lock(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; struct coda_dev *pcdev = ctx->dev; + mutex_lock(&pcdev->dev_mutex); } @@ -819,6 +822,7 @@ static void coda_unlock(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; struct coda_dev *pcdev = ctx->dev; + mutex_unlock(&pcdev->dev_mutex); } @@ -995,7 +999,8 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, if (name && parent) { buf->blob.data = buf->vaddr; buf->blob.size = size; - buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); + buf->dentry = debugfs_create_blob(name, 0644, parent, + &buf->blob); if (!buf->dentry) dev_warn(&dev->plat_dev->dev, "failed to create debugfs entry %s\n", name); @@ -1276,17 +1281,20 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500); + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, + 500); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_HEADER_MODE, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, + 1920 * 1088 / 256, 1, 0); if (ctx->ctrls.error) { - v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)", + v4l2_err(&ctx->dev->v4l2_dev, + "control initialization error (%d)", ctx->ctrls.error); return -EINVAL; } @@ -1365,7 +1373,7 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, int ret; int idx; - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -1444,7 +1452,8 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer"); + v4l2_err(&dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); ret = -ENOMEM; goto err_dma_writecombine; } @@ -1617,10 +1626,12 @@ static int coda_hw_init(struct coda_dev *dev) /* Set default values */ switch (dev->devtype->product) { case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); break; default: - coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); } if (dev->devtype->product == CODA_960) coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL); @@ -1854,7 +1865,7 @@ static int coda_probe(struct platform_device *pdev) struct resource *res; int ret, irq; - dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_err(&pdev->dev, "Not enough memory for %s\n", CODA_NAME); @@ -1905,7 +1916,8 @@ static int coda_probe(struct platform_device *pdev) if (ret == -ENOENT || ret == -ENOSYS) { dev->rstc = NULL; } else { - dev_err(&pdev->dev, "failed get reset control: %d\n", ret); + dev_err(&pdev->dev, "failed get reset control: %d\n", + ret); return ret; } } -- cgit v1.2.3 From e47a81d8886d0262f9f6a4ecf7aa7e6ba2cb0dfc Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 11 Jun 2014 10:34:35 -0300 Subject: [media] smiapp: Use unlocked __v4l2_ctrl_modify_range() Instead of modifying the control ranges directly by manipulating struct v4l2_ctrl, use __v4l2_ctrl_modify_range() for the purpose. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 47 +++++++++++----------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 437ec29bdf64..bf8d3380111a 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -320,13 +320,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) + sensor->vblank->val - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN]; - ctrl->maximum = max; - if (ctrl->default_value > max) - ctrl->default_value = max; - if (ctrl->val > max) - ctrl->val = max; - if (ctrl->cur.val > max) - ctrl->cur.val = max; + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } /* @@ -834,36 +828,25 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) { struct v4l2_ctrl *vblank = sensor->vblank; struct v4l2_ctrl *hblank = sensor->hblank; + int min, max; - vblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); - vblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); + max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; - vblank->val = clamp_t(int, vblank->val, - vblank->minimum, vblank->maximum); - vblank->default_value = vblank->minimum; - vblank->val = vblank->val; - vblank->cur.val = vblank->val; - - hblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); - hblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - + __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); + + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); + max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; - hblank->val = clamp_t(int, hblank->val, - hblank->minimum, hblank->maximum); - hblank->default_value = hblank->minimum; - hblank->val = hblank->val; - hblank->cur.val = hblank->val; + __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); __smiapp_update_exposure_limits(sensor); } -- cgit v1.2.3 From a328e7e3fd3030974b74da51daee625a14be0435 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 11 Jun 2014 10:37:36 -0300 Subject: [media] smiapp: Set 64-bit integer control using v4l2_ctrl_s_ctrl_int64() Don't manipulate struct v4l2_ctrl directly. Instead, use v4l2_ctrl_s_ctrl_int64() to change the values. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index bf8d3380111a..c4cc5de3ae59 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -298,8 +298,9 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) if (rval < 0) return rval; - *sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz; - *sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi; + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, + pll->vt_pix_clk_freq_hz); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); return 0; } @@ -509,6 +510,10 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return smiapp_write( sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + case V4L2_CID_PIXEL_RATE: + /* For v4l2_ctrl_s_ctrl_int64() used internally. */ + return 0; + default: return -EINVAL; } -- cgit v1.2.3 From 29bbb7bd0a65e01a0423e1df764676119b71ecb3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 11 Aug 2014 18:09:32 -0300 Subject: [media] siano: add support for PCTV 77e Add support for PCTV microStick (77e) device that uses a sms1140 chipset. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 6 ++++++ drivers/media/common/siano/sms-cards.h | 1 + drivers/media/usb/siano/smsusb.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 82769993eeb7..82c7a1289f05 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -157,6 +157,12 @@ static struct sms_board sms_boards[] = { .type = SMS_DENVER_2160, .default_mode = DEVICE_MODE_DAB_TDMB, }, + [SMS1XXX_BOARD_PCTV_77E] = { + .name = "Hauppauge microStick 77e", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + }, }; struct sms_board *sms_get_board(unsigned id) diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index c63b544c49c5..4c4caddf9869 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -45,6 +45,7 @@ #define SMS1XXX_BOARD_SIANO_RIO 18 #define SMS1XXX_BOARD_SIANO_DENVER_1530 19 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20 +#define SMS1XXX_BOARD_PCTV_77E 21 struct sms_board_gpio_cfg { int lna_vhf_exist; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 1836a416d806..89c86ee2b225 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -655,6 +655,8 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD }, { USB_DEVICE(0x3275, 0x0080), .driver_info = SMS1XXX_BOARD_SIANO_RIO }, + { USB_DEVICE(0x2013, 0x0257), + .driver_info = SMS1XXX_BOARD_PCTV_77E }, { } /* Terminating entry */ }; -- cgit v1.2.3 From 2179de602c33d0b7b87f087dd7fbf35d22da4bd8 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 4 Aug 2014 08:13:16 -0300 Subject: [media] staging: media: as102: replace custom dprintk() with dev_dbg() remove dprintk() and replace it with dev_dbg() or pr_debug() in order to use the common kernel coding style. Signed-off-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 15 +++++------ drivers/staging/media/as102/as102_drv.h | 7 ----- drivers/staging/media/as102/as102_fe.c | 25 +++++++----------- drivers/staging/media/as102/as102_usb_drv.c | 41 +++++++++++++++++------------ 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 09d64cd67502..e0ee618e607a 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -31,10 +31,6 @@ #include "as102_fw.h" #include "dvbdev.h" -int as102_debug; -module_param_named(debug, as102_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); - int dual_tuner; module_param_named(dual_tuner, dual_tuner, int, 0644); MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); @@ -74,7 +70,8 @@ static void as102_stop_stream(struct as102_dev_t *dev) return; if (as10x_cmd_stop_streaming(bus_adap) < 0) - dprintk(debug, "as10x_cmd_stop_streaming failed\n"); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_stop_streaming failed\n"); mutex_unlock(&dev->bus_adap.lock); } @@ -112,14 +109,16 @@ static int as10x_pid_filter(struct as102_dev_t *dev, int ret = -EFAULT; if (mutex_lock_interruptible(&dev->bus_adap.lock)) { - dprintk(debug, "mutex_lock_interruptible(lock) failed !\n"); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "amutex_lock_interruptible(lock) failed !\n"); return -EBUSY; } switch (onoff) { case 0: ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", index, pid, ret); break; case 1: @@ -131,7 +130,7 @@ static int as10x_pid_filter(struct as102_dev_t *dev, filter.pid = pid; ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", index, filter.idx, filter.pid, ret); break; diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index a06837dcc05d..49d0c4259b00 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -27,17 +27,10 @@ #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" -extern int as102_debug; #define debug as102_debug extern struct usb_driver as102_usb_driver; extern int elna_enable; -#define dprintk(debug, args...) \ - do { if (debug) { \ - pr_debug("%s: ", __func__); \ - printk(args); \ - } } while (0) - #define AS102_DEVICE_MAJOR 192 #define AS102_USB_BUF_SIZE 512 diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index b686b7617cdc..67e55b84493f 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -46,7 +46,8 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); if (ret != 0) - dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); mutex_unlock(&dev->bus_adap.lock); @@ -81,13 +82,6 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) static int as102_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *settings) { -#if 0 - dprintk(debug, "step_size = %d\n", settings->step_size); - dprintk(debug, "max_drift = %d\n", settings->max_drift); - dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, - 1000); -#endif - settings->min_delay_ms = 1000; return 0; @@ -110,7 +104,8 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) /* send abilis command: GET_TUNE_STATUS */ ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); if (ret < 0) { - dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", ret); goto out; } @@ -133,7 +128,8 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = TUNE_STATUS_NOT_TUNED; } - dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", tstate.tune_state, tstate.signal_strength, tstate.PER, tstate.BER); @@ -141,10 +137,10 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) if (as10x_cmd_get_demod_stats(&dev->bus_adap, (struct as10x_demod_stats *) &dev->demod_stats) < 0) { memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); } else { - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "demod status: fc: 0x%08x, bad fc: 0x%08x, " "bytes corrected: 0x%08x , MER: 0x%04x\n", dev->demod_stats.frame_count, @@ -531,7 +527,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, break; } - dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", params->frequency, tune_args->bandwidth, tune_args->guard_interval); @@ -556,8 +552,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, as102_fe_get_code_rate(params->code_rate_LP); } - dprintk(debug, - "\thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", + pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", tune_args->hierarchy, tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index e6f6278e97d6..86f83b9b1118 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -104,21 +104,22 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, send_buf, send_buf_len, USB_CTRL_SET_TIMEOUT /* 200 */); if (ret < 0) { - dprintk(debug, "usb_control_msg(send) failed, err %i\n", - ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(send) failed, err %i\n", ret); return ret; } if (ret != send_buf_len) { - dprintk(debug, "only wrote %d of %d bytes\n", - ret, send_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, + "only wrote %d of %d bytes\n", ret, send_buf_len); return -1; } } if (recv_buf != NULL) { #ifdef TRACE - dprintk(debug, "want to read: %d bytes\n", recv_buf_len); + dev_dbg(bus_adap->usb_dev->dev, + "want to read: %d bytes\n", recv_buf_len); #endif ret = usb_control_msg(bus_adap->usb_dev, usb_rcvctrlpipe(bus_adap->usb_dev, 0), @@ -130,12 +131,13 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, recv_buf, recv_buf_len, USB_CTRL_GET_TIMEOUT /* 200 */); if (ret < 0) { - dprintk(debug, "usb_control_msg(recv) failed, err %i\n", - ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(recv) failed, err %i\n", ret); return ret; } #ifdef TRACE - dprintk(debug, "read %d bytes\n", recv_buf_len); + dev_dbg(bus_adap->usb_dev->dev, + "read %d bytes\n", recv_buf_len); #endif } @@ -153,13 +155,14 @@ static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, usb_sndbulkpipe(bus_adap->usb_dev, 1), send_buf, send_buf_len, &actual_len, 200); if (ret) { - dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(send) failed, err %i\n", ret); return ret; } if (actual_len != send_buf_len) { - dprintk(debug, "only wrote %d of %d bytes\n", - actual_len, send_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", + actual_len, send_buf_len); return -1; } return ret ? ret : actual_len; @@ -177,13 +180,14 @@ static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, usb_rcvbulkpipe(bus_adap->usb_dev, 2), recv_buf, recv_buf_len, &actual_len, 200); if (ret) { - dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(recv) failed, err %i\n", ret); return ret; } if (actual_len != recv_buf_len) { - dprintk(debug, "only read %d of %d bytes\n", - actual_len, recv_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", + actual_len, recv_buf_len); return -1; } return ret ? ret : actual_len; @@ -211,7 +215,8 @@ static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err) - dprintk(debug, "%s: usb_submit_urb failed\n", __func__); + dev_dbg(&urb->dev->dev, + "%s: usb_submit_urb failed\n", __func__); return err; } @@ -256,7 +261,8 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) GFP_KERNEL, &dev->dma_addr); if (!dev->stream) { - dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_buffer_alloc failed\n", __func__); return -ENOMEM; } @@ -268,7 +274,8 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) urb = usb_alloc_urb(0, GFP_ATOMIC); if (urb == NULL) { - dprintk(debug, "%s: usb_alloc_urb failed\n", __func__); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_alloc_urb failed\n", __func__); as102_free_usb_stream_buffer(dev); return -ENOMEM; } -- cgit v1.2.3 From d6317c68f3324e086799e12e4864231bb71829cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:15 -0300 Subject: [media] as102: promote it out of staging This driver is stable and doesn't contain any really serious issue. Move it out of staging. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/Kconfig | 1 + drivers/media/usb/Makefile | 1 + drivers/media/usb/as102/Kconfig | 8 + drivers/media/usb/as102/Makefile | 6 + drivers/media/usb/as102/as102_drv.c | 276 ++++++++++++ drivers/media/usb/as102/as102_drv.h | 92 ++++ drivers/media/usb/as102/as102_fe.c | 566 +++++++++++++++++++++++++ drivers/media/usb/as102/as102_fw.c | 232 ++++++++++ drivers/media/usb/as102/as102_fw.h | 38 ++ drivers/media/usb/as102/as102_usb_drv.c | 479 +++++++++++++++++++++ drivers/media/usb/as102/as102_usb_drv.h | 61 +++ drivers/media/usb/as102/as10x_cmd.c | 418 ++++++++++++++++++ drivers/media/usb/as102/as10x_cmd.h | 529 +++++++++++++++++++++++ drivers/media/usb/as102/as10x_cmd_cfg.c | 206 +++++++++ drivers/media/usb/as102/as10x_cmd_stream.c | 211 +++++++++ drivers/media/usb/as102/as10x_handle.h | 54 +++ drivers/media/usb/as102/as10x_types.h | 194 +++++++++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/as102/Kconfig | 8 - drivers/staging/media/as102/Makefile | 6 - drivers/staging/media/as102/as102_drv.c | 276 ------------ drivers/staging/media/as102/as102_drv.h | 92 ---- drivers/staging/media/as102/as102_fe.c | 566 ------------------------- drivers/staging/media/as102/as102_fw.c | 232 ---------- drivers/staging/media/as102/as102_fw.h | 38 -- drivers/staging/media/as102/as102_usb_drv.c | 479 --------------------- drivers/staging/media/as102/as102_usb_drv.h | 61 --- drivers/staging/media/as102/as10x_cmd.c | 418 ------------------ drivers/staging/media/as102/as10x_cmd.h | 529 ----------------------- drivers/staging/media/as102/as10x_cmd_cfg.c | 206 --------- drivers/staging/media/as102/as10x_cmd_stream.c | 211 --------- drivers/staging/media/as102/as10x_handle.h | 54 --- drivers/staging/media/as102/as10x_types.h | 194 --------- 34 files changed, 3372 insertions(+), 3373 deletions(-) create mode 100644 drivers/media/usb/as102/Kconfig create mode 100644 drivers/media/usb/as102/Makefile create mode 100644 drivers/media/usb/as102/as102_drv.c create mode 100644 drivers/media/usb/as102/as102_drv.h create mode 100644 drivers/media/usb/as102/as102_fe.c create mode 100644 drivers/media/usb/as102/as102_fw.c create mode 100644 drivers/media/usb/as102/as102_fw.h create mode 100644 drivers/media/usb/as102/as102_usb_drv.c create mode 100644 drivers/media/usb/as102/as102_usb_drv.h create mode 100644 drivers/media/usb/as102/as10x_cmd.c create mode 100644 drivers/media/usb/as102/as10x_cmd.h create mode 100644 drivers/media/usb/as102/as10x_cmd_cfg.c create mode 100644 drivers/media/usb/as102/as10x_cmd_stream.c create mode 100644 drivers/media/usb/as102/as10x_handle.h create mode 100644 drivers/media/usb/as102/as10x_types.h delete mode 100644 drivers/staging/media/as102/Kconfig delete mode 100644 drivers/staging/media/as102/Makefile delete mode 100644 drivers/staging/media/as102/as102_drv.c delete mode 100644 drivers/staging/media/as102/as102_drv.h delete mode 100644 drivers/staging/media/as102/as102_fe.c delete mode 100644 drivers/staging/media/as102/as102_fw.c delete mode 100644 drivers/staging/media/as102/as102_fw.h delete mode 100644 drivers/staging/media/as102/as102_usb_drv.c delete mode 100644 drivers/staging/media/as102/as102_usb_drv.h delete mode 100644 drivers/staging/media/as102/as10x_cmd.c delete mode 100644 drivers/staging/media/as102/as10x_cmd.h delete mode 100644 drivers/staging/media/as102/as10x_cmd_cfg.c delete mode 100644 drivers/staging/media/as102/as10x_cmd_stream.c delete mode 100644 drivers/staging/media/as102/as10x_handle.h delete mode 100644 drivers/staging/media/as102/as10x_types.h diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index 94d51e092db3..d6e8edc59b6d 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -46,6 +46,7 @@ source "drivers/media/usb/ttusb-budget/Kconfig" source "drivers/media/usb/ttusb-dec/Kconfig" source "drivers/media/usb/siano/Kconfig" source "drivers/media/usb/b2c2/Kconfig" +source "drivers/media/usb/as102/Kconfig" endif if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index f438efffefc5..b5b645b91f4e 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBTV) += usbtv/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ +obj-$(CONFIG_DVB_AS102) += as102/ diff --git a/drivers/media/usb/as102/Kconfig b/drivers/media/usb/as102/Kconfig new file mode 100644 index 000000000000..28aba00dc629 --- /dev/null +++ b/drivers/media/usb/as102/Kconfig @@ -0,0 +1,8 @@ +config DVB_AS102 + tristate "Abilis AS102 DVB receiver" + depends on DVB_CORE && USB && I2C && INPUT + select FW_LOADER + help + Choose Y or M here if you have a device containing an AS102 + + To compile this driver as a module, choose M here diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile new file mode 100644 index 000000000000..8916d8a909bc --- /dev/null +++ b/drivers/media/usb/as102/Makefile @@ -0,0 +1,6 @@ +dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ + as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o + +obj-$(CONFIG_DVB_AS102) += dvb-as102.o + +ccflags-y += -Idrivers/media/dvb-core diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c new file mode 100644 index 000000000000..e0ee618e607a --- /dev/null +++ b/drivers/media/usb/as102/as102_drv.c @@ -0,0 +1,276 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 +#include +#include +#include +#include + +/* header file for usb device driver*/ +#include "as102_drv.h" +#include "as102_fw.h" +#include "dvbdev.h" + +int dual_tuner; +module_param_named(dual_tuner, dual_tuner, int, 0644); +MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); + +static int fw_upload = 1; +module_param_named(fw_upload, fw_upload, int, 0644); +MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); + +static int pid_filtering; +module_param_named(pid_filtering, pid_filtering, int, 0644); +MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); + +static int ts_auto_disable; +module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); +MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); + +int elna_enable = 1; +module_param_named(elna_enable, elna_enable, int, 0644); +MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void as102_stop_stream(struct as102_dev_t *dev) +{ + struct as10x_bus_adapter_t *bus_adap; + + if (dev != NULL) + bus_adap = &dev->bus_adap; + else + return; + + if (bus_adap->ops->stop_stream != NULL) + bus_adap->ops->stop_stream(dev); + + if (ts_auto_disable) { + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return; + + if (as10x_cmd_stop_streaming(bus_adap) < 0) + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_stop_streaming failed\n"); + + mutex_unlock(&dev->bus_adap.lock); + } +} + +static int as102_start_stream(struct as102_dev_t *dev) +{ + struct as10x_bus_adapter_t *bus_adap; + int ret = -EFAULT; + + if (dev != NULL) + bus_adap = &dev->bus_adap; + else + return ret; + + if (bus_adap->ops->start_stream != NULL) + ret = bus_adap->ops->start_stream(dev); + + if (ts_auto_disable) { + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EFAULT; + + ret = as10x_cmd_start_streaming(bus_adap); + + mutex_unlock(&dev->bus_adap.lock); + } + + return ret; +} + +static int as10x_pid_filter(struct as102_dev_t *dev, + int index, u16 pid, int onoff) { + + struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap; + int ret = -EFAULT; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) { + dev_dbg(&dev->bus_adap.usb_dev->dev, + "amutex_lock_interruptible(lock) failed !\n"); + return -EBUSY; + } + + switch (onoff) { + case 0: + ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + index, pid, ret); + break; + case 1: + { + struct as10x_ts_filter filter; + + filter.type = TS_PID_TYPE_TS; + filter.idx = 0xFF; + filter.pid = pid; + + ret = as10x_cmd_add_PID_filter(bus_adap, &filter); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", + index, filter.idx, filter.pid, ret); + break; + } + } + + mutex_unlock(&dev->bus_adap.lock); + return ret; +} + +static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + int ret = 0; + struct dvb_demux *demux = dvbdmxfeed->demux; + struct as102_dev_t *as102_dev = demux->priv; + + if (mutex_lock_interruptible(&as102_dev->sem)) + return -ERESTARTSYS; + + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 1); + + if (as102_dev->streaming++ == 0) + ret = as102_start_stream(as102_dev); + + mutex_unlock(&as102_dev->sem); + return ret; +} + +static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *demux = dvbdmxfeed->demux; + struct as102_dev_t *as102_dev = demux->priv; + + if (mutex_lock_interruptible(&as102_dev->sem)) + return -ERESTARTSYS; + + if (--as102_dev->streaming == 0) + as102_stop_stream(as102_dev); + + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 0); + + mutex_unlock(&as102_dev->sem); + return 0; +} + +int as102_dvb_register(struct as102_dev_t *as102_dev) +{ + struct device *dev = &as102_dev->bus_adap.usb_dev->dev; + int ret; + + ret = dvb_register_adapter(&as102_dev->dvb_adap, + as102_dev->name, THIS_MODULE, + dev, adapter_nr); + if (ret < 0) { + dev_err(dev, "%s: dvb_register_adapter() failed: %d\n", + __func__, ret); + return ret; + } + + as102_dev->dvb_dmx.priv = as102_dev; + as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256; + as102_dev->dvb_dmx.feednum = 256; + as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed; + as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed; + + as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING; + + as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum; + as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; + as102_dev->dvb_dmxdev.capabilities = 0; + + ret = dvb_dmx_init(&as102_dev->dvb_dmx); + if (ret < 0) { + dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret); + goto edmxinit; + } + + ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); + if (ret < 0) { + dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n", + __func__, ret); + goto edmxdinit; + } + + ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); + if (ret < 0) { + dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", + __func__, ret); + goto efereg; + } + + /* init bus mutex for token locking */ + mutex_init(&as102_dev->bus_adap.lock); + + /* init start / stop stream mutex */ + mutex_init(&as102_dev->sem); + + /* + * try to load as102 firmware. If firmware upload failed, we'll be + * able to upload it later. + */ + if (fw_upload) + try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), + "firmware_class"); + + pr_info("Registered device %s", as102_dev->name); + return 0; + +efereg: + dvb_dmxdev_release(&as102_dev->dvb_dmxdev); +edmxdinit: + dvb_dmx_release(&as102_dev->dvb_dmx); +edmxinit: + dvb_unregister_adapter(&as102_dev->dvb_adap); + return ret; +} + +void as102_dvb_unregister(struct as102_dev_t *as102_dev) +{ + /* unregister as102 frontend */ + as102_dvb_unregister_fe(&as102_dev->dvb_fe); + + /* unregister demux device */ + dvb_dmxdev_release(&as102_dev->dvb_dmxdev); + dvb_dmx_release(&as102_dev->dvb_dmx); + + /* unregister dvb adapter */ + dvb_unregister_adapter(&as102_dev->dvb_adap); + + pr_info("Unregistered device %s", as102_dev->name); +} + +module_usb_driver(as102_usb_driver); + +/* modinfo details */ +MODULE_DESCRIPTION(DRIVER_FULL_NAME); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pierrick Hascoet "); diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h new file mode 100644 index 000000000000..49d0c4259b00 --- /dev/null +++ b/drivers/media/usb/as102/as102_drv.h @@ -0,0 +1,92 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 +#include "as10x_cmd.h" +#include "as102_usb_drv.h" + +#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" +#define DRIVER_NAME "as10x_usb" + +#define debug as102_debug +extern struct usb_driver as102_usb_driver; +extern int elna_enable; + +#define AS102_DEVICE_MAJOR 192 + +#define AS102_USB_BUF_SIZE 512 +#define MAX_STREAM_URB 32 + +struct as10x_bus_adapter_t { + struct usb_device *usb_dev; + /* bus token lock */ + struct mutex lock; + /* low level interface for bus adapter */ + union as10x_bus_token_t { + /* usb token */ + struct as10x_usb_token_cmd_t usb; + } token; + + /* token cmd xfer id */ + uint16_t cmd_xid; + + /* as10x command and response for dvb interface*/ + struct as10x_cmd_t *cmd, *rsp; + + /* bus adapter private ops callback */ + struct as102_priv_ops_t *ops; +}; + +struct as102_dev_t { + const char *name; + struct as10x_bus_adapter_t bus_adap; + struct list_head device_entry; + struct kref kref; + uint8_t elna_cfg; + + struct dvb_adapter dvb_adap; + struct dvb_frontend dvb_fe; + struct dvb_demux dvb_dmx; + struct dmxdev dvb_dmxdev; + + /* demodulator stats */ + struct as10x_demod_stats demod_stats; + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; + + /* timer handle to trig ts stream download */ + struct timer_list timer_handle; + + struct mutex sem; + dma_addr_t dma_addr; + void *stream; + int streaming; + struct urb *stream_urb[MAX_STREAM_URB]; +}; + +int as102_dvb_register(struct as102_dev_t *dev); +void as102_dvb_unregister(struct as102_dev_t *dev); + +int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); +int as102_dvb_unregister_fe(struct dvb_frontend *dev); diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c new file mode 100644 index 000000000000..67e55b84493f --- /dev/null +++ b/drivers/media/usb/as102/as102_fe.c @@ -0,0 +1,566 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 "as102_drv.h" +#include "as10x_types.h" +#include "as10x_cmd.h" + +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, + struct as10x_tps *src); + +static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, + struct dtv_frontend_properties *src); + +static int as102_fe_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tune_args tune_args = { 0 }; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + as102_fe_copy_tune_parameters(&tune_args, p); + + /* send abilis command: SET_TUNE */ + ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); + if (ret != 0) + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); + + mutex_unlock(&dev->bus_adap.lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tps tps = { 0 }; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -EINVAL; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); + + if (ret == 0) + as10x_fe_copy_tps_parameters(p, &tps); + + mutex_unlock(&dev->bus_adap.lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + + settings->min_delay_ms = 1000; + + return 0; +} + + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret = 0; + struct as102_dev_t *dev; + struct as10x_tune_status tstate = { 0 }; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); + if (ret < 0) { + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); + goto out; + } + + dev->signal_strength = tstate.signal_strength; + dev->ber = tstate.BER; + + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + dev_dbg(&dev->bus_adap.usb_dev->dev, + "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (*status & FE_HAS_LOCK) { + if (as10x_cmd_get_demod_stats(&dev->bus_adap, + (struct as10x_demod_stats *) &dev->demod_stats) < 0) { + memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dev_dbg(&dev->bus_adap.usb_dev->dev, + "demod status: fc: 0x%08x, bad fc: 0x%08x, " + "bytes corrected: 0x%08x , MER: 0x%04x\n", + dev->demod_stats.frame_count, + dev->demod_stats.bad_frame_count, + dev->demod_stats.bytes_fixed_by_rs, + dev->demod_stats.mer); + } + } else { + memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); + } + +out: + mutex_unlock(&dev->bus_adap.lock); + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct as102_dev_t *dev; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + *snr = dev->demod_stats.mer; + + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct as102_dev_t *dev; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + *ber = dev->ber; + + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct as102_dev_t *dev; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); + + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct as102_dev_t *dev; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + if (dev->demod_stats.has_started) + *ucblocks = dev->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + return 0; +} + +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct as102_dev_t *dev; + int ret; + + dev = (struct as102_dev_t *) fe->tuner_priv; + if (dev == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&dev->bus_adap.lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(&dev->bus_adap, + CONTEXT_LNA, dev->elna_cfg); + + ret = as10x_cmd_turn_on(&dev->bus_adap); + } else { + ret = as10x_cmd_turn_off(&dev->bus_adap); + } + + mutex_unlock(&dev->bus_adap.lock); + + return ret; +} + +static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Unknown AS102 device", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, +}; + +int as102_dvb_unregister_fe(struct dvb_frontend *fe) +{ + /* unregister frontend */ + dvb_unregister_frontend(fe); + + /* detach frontend */ + dvb_frontend_detach(fe); + + return 0; +} + +int as102_dvb_register_fe(struct as102_dev_t *as102_dev, + struct dvb_frontend *dvb_fe) +{ + int errno; + struct dvb_adapter *dvb_adap; + + if (as102_dev == NULL) + return -EINVAL; + + /* extract dvb_adapter */ + dvb_adap = &as102_dev->dvb_adap; + + /* init frontend callback ops */ + memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(dvb_fe->ops.info.name, as102_dev->name, + sizeof(dvb_fe->ops.info.name)); + + /* register dvb frontend */ + errno = dvb_register_frontend(dvb_adap, dvb_fe); + if (errno == 0) + dvb_fe->tuner_priv = as102_dev; + + return errno; +} + +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, + struct as10x_tps *as10x_tps) +{ + + /* extract constellation */ + switch (as10x_tps->modulation) { + case CONST_QPSK: + fe_tps->modulation = QPSK; + break; + case CONST_QAM16: + fe_tps->modulation = QAM_16; + break; + case CONST_QAM64: + fe_tps->modulation = QAM_64; + break; + } + + /* extract hierarchy */ + switch (as10x_tps->hierarchy) { + case HIER_NONE: + fe_tps->hierarchy = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + fe_tps->hierarchy = HIERARCHY_1; + break; + case HIER_ALPHA_2: + fe_tps->hierarchy = HIERARCHY_2; + break; + case HIER_ALPHA_4: + fe_tps->hierarchy = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch (as10x_tps->code_rate_HP) { + case CODE_RATE_1_2: + fe_tps->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch (as10x_tps->code_rate_LP) { + case CODE_RATE_1_2: + fe_tps->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + fe_tps->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + fe_tps->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + fe_tps->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + fe_tps->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch (as10x_tps->guard_interval) { + case GUARD_INT_1_32: + fe_tps->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + fe_tps->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + fe_tps->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + fe_tps->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch (as10x_tps->transmission_mode) { + case TRANS_MODE_2K: + fe_tps->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + fe_tps->transmission_mode = TRANSMISSION_MODE_8K; + break; + } +} + +static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) +{ + uint8_t c; + + switch (arg) { + case FEC_1_2: + c = CODE_RATE_1_2; + break; + case FEC_2_3: + c = CODE_RATE_2_3; + break; + case FEC_3_4: + c = CODE_RATE_3_4; + break; + case FEC_5_6: + c = CODE_RATE_5_6; + break; + case FEC_7_8: + c = CODE_RATE_7_8; + break; + default: + c = CODE_RATE_UNKNOWN; + break; + } + + return c; +} + +static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, + struct dtv_frontend_properties *params) +{ + + /* set frequency */ + tune_args->freq = params->frequency / 1000; + + /* fix interleaving_mode */ + tune_args->interleaving_mode = INTLV_NATIVE; + + switch (params->bandwidth_hz) { + case 8000000: + tune_args->bandwidth = BW_8_MHZ; + break; + case 7000000: + tune_args->bandwidth = BW_7_MHZ; + break; + case 6000000: + tune_args->bandwidth = BW_6_MHZ; + break; + default: + tune_args->bandwidth = BW_8_MHZ; + } + + switch (params->guard_interval) { + case GUARD_INTERVAL_1_32: + tune_args->guard_interval = GUARD_INT_1_32; + break; + case GUARD_INTERVAL_1_16: + tune_args->guard_interval = GUARD_INT_1_16; + break; + case GUARD_INTERVAL_1_8: + tune_args->guard_interval = GUARD_INT_1_8; + break; + case GUARD_INTERVAL_1_4: + tune_args->guard_interval = GUARD_INT_1_4; + break; + case GUARD_INTERVAL_AUTO: + default: + tune_args->guard_interval = GUARD_UNKNOWN; + break; + } + + switch (params->modulation) { + case QPSK: + tune_args->modulation = CONST_QPSK; + break; + case QAM_16: + tune_args->modulation = CONST_QAM16; + break; + case QAM_64: + tune_args->modulation = CONST_QAM64; + break; + default: + tune_args->modulation = CONST_UNKNOWN; + break; + } + + switch (params->transmission_mode) { + case TRANSMISSION_MODE_2K: + tune_args->transmission_mode = TRANS_MODE_2K; + break; + case TRANSMISSION_MODE_8K: + tune_args->transmission_mode = TRANS_MODE_8K; + break; + default: + tune_args->transmission_mode = TRANS_MODE_UNKNOWN; + } + + switch (params->hierarchy) { + case HIERARCHY_NONE: + tune_args->hierarchy = HIER_NONE; + break; + case HIERARCHY_1: + tune_args->hierarchy = HIER_ALPHA_1; + break; + case HIERARCHY_2: + tune_args->hierarchy = HIER_ALPHA_2; + break; + case HIERARCHY_4: + tune_args->hierarchy = HIER_ALPHA_4; + break; + case HIERARCHY_AUTO: + tune_args->hierarchy = HIER_UNKNOWN; + break; + } + + pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + params->frequency, + tune_args->bandwidth, + tune_args->guard_interval); + + /* + * Detect a hierarchy selection + * if HP/LP are both set to FEC_NONE, HP will be selected. + */ + if ((tune_args->hierarchy != HIER_NONE) && + ((params->code_rate_LP == FEC_NONE) || + (params->code_rate_HP == FEC_NONE))) { + + if (params->code_rate_LP == FEC_NONE) { + tune_args->hier_select = HIER_HIGH_PRIORITY; + tune_args->code_rate = + as102_fe_get_code_rate(params->code_rate_HP); + } + + if (params->code_rate_HP == FEC_NONE) { + tune_args->hier_select = HIER_LOW_PRIORITY; + tune_args->code_rate = + as102_fe_get_code_rate(params->code_rate_LP); + } + + pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", + tune_args->hierarchy, + tune_args->hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args->hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args->code_rate); + } else { + tune_args->code_rate = + as102_fe_get_code_rate(params->code_rate_HP); + } +} diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c new file mode 100644 index 000000000000..f33f752c0aad --- /dev/null +++ b/drivers/media/usb/as102/as102_fw.c @@ -0,0 +1,232 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 +#include + +#include "as102_drv.h" +#include "as102_fw.h" + +static const char as102_st_fw1[] = "as102_data1_st.hex"; +static const char as102_st_fw2[] = "as102_data2_st.hex"; +static const char as102_dt_fw1[] = "as102_data1_dt.hex"; +static const char as102_dt_fw2[] = "as102_data2_dt.hex"; + +static unsigned char atohx(unsigned char *dst, char *src) +{ + unsigned char value = 0; + + char msb = tolower(*src) - '0'; + char lsb = tolower(*(src + 1)) - '0'; + + if (msb > 9) + msb -= 7; + if (lsb > 9) + lsb -= 7; + + *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF); + return value; +} + +/* + * Parse INTEL HEX firmware file to extract address and data. + */ +static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, + unsigned char *data, int *dataLength, + unsigned char *addr_has_changed) { + + int count = 0; + unsigned char *src, dst; + + if (*fw_data++ != ':') { + pr_err("invalid firmware file\n"); + return -EFAULT; + } + + /* locate end of line */ + for (src = fw_data; *src != '\n'; src += 2) { + atohx(&dst, src); + /* parse line to split addr / data */ + switch (count) { + case 0: + *dataLength = dst; + break; + case 1: + addr[2] = dst; + break; + case 2: + addr[3] = dst; + break; + case 3: + /* check if data is an address */ + if (dst == 0x04) + *addr_has_changed = 1; + else + *addr_has_changed = 0; + break; + case 4: + case 5: + if (*addr_has_changed) + addr[(count - 4)] = dst; + else + data[(count - 4)] = dst; + break; + default: + data[(count - 4)] = dst; + break; + } + count++; + } + + /* return read value + ':' + '\n' */ + return (count * 2) + 2; +} + +static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, + unsigned char *cmd, + const struct firmware *firmware) { + + struct as10x_fw_pkt_t fw_pkt; + int total_read_bytes = 0, errno = 0; + unsigned char addr_has_changed = 0; + + for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { + int read_bytes = 0, data_len = 0; + + /* parse intel hex line */ + read_bytes = parse_hex_line( + (u8 *) (firmware->data + total_read_bytes), + fw_pkt.raw.address, + fw_pkt.raw.data, + &data_len, + &addr_has_changed); + + if (read_bytes <= 0) + goto error; + + /* detect the end of file */ + total_read_bytes += read_bytes; + if (total_read_bytes == firmware->size) { + fw_pkt.u.request[0] = 0x00; + fw_pkt.u.request[1] = 0x03; + + /* send EOF command */ + errno = bus_adap->ops->upload_fw_pkt(bus_adap, + (uint8_t *) + &fw_pkt, 2, 0); + if (errno < 0) + goto error; + } else { + if (!addr_has_changed) { + /* prepare command to send */ + fw_pkt.u.request[0] = 0x00; + fw_pkt.u.request[1] = 0x01; + + data_len += sizeof(fw_pkt.u.request); + data_len += sizeof(fw_pkt.raw.address); + + /* send cmd to device */ + errno = bus_adap->ops->upload_fw_pkt(bus_adap, + (uint8_t *) + &fw_pkt, + data_len, + 0); + if (errno < 0) + goto error; + } + } + } +error: + return (errno == 0) ? total_read_bytes : errno; +} + +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) +{ + int errno = -EFAULT; + const struct firmware *firmware = NULL; + unsigned char *cmd_buf = NULL; + const char *fw1, *fw2; + struct usb_device *dev = bus_adap->usb_dev; + + /* select fw file to upload */ + if (dual_tuner) { + fw1 = as102_dt_fw1; + fw2 = as102_dt_fw2; + } else { + fw1 = as102_st_fw1; + fw2 = as102_st_fw2; + } + + /* allocate buffer to store firmware upload command and data */ + cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); + if (cmd_buf == NULL) { + errno = -ENOMEM; + goto error; + } + + /* request kernel to locate firmware file: part1 */ + errno = request_firmware(&firmware, fw1, &dev->dev); + if (errno < 0) { + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw1); + goto error; + } + + /* initiate firmware upload */ + errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); + if (errno < 0) { + pr_err("%s: error during firmware upload part1\n", + DRIVER_NAME); + goto error; + } + + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw1); + release_firmware(firmware); + + /* wait for boot to complete */ + mdelay(100); + + /* request kernel to locate firmware file: part2 */ + errno = request_firmware(&firmware, fw2, &dev->dev); + if (errno < 0) { + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw2); + goto error; + } + + /* initiate firmware upload */ + errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); + if (errno < 0) { + pr_err("%s: error during firmware upload part2\n", + DRIVER_NAME); + goto error; + } + + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw2); +error: + kfree(cmd_buf); + release_firmware(firmware); + + return errno; +} diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h new file mode 100644 index 000000000000..4bfc6849d95a --- /dev/null +++ b/drivers/media/usb/as102/as102_fw.h @@ -0,0 +1,38 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 MAX_FW_PKT_SIZE 64 + +extern int dual_tuner; + +struct as10x_raw_fw_pkt { + unsigned char address[4]; + unsigned char data[MAX_FW_PKT_SIZE - 6]; +} __packed; + +struct as10x_fw_pkt_t { + union { + unsigned char request[2]; + unsigned char length[2]; + } __packed u; + struct as10x_raw_fw_pkt raw; +} __packed; + +#ifdef __KERNEL__ +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap); +#endif diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c new file mode 100644 index 000000000000..86f83b9b1118 --- /dev/null +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -0,0 +1,479 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 +#include + +#include "as102_drv.h" +#include "as102_usb_drv.h" +#include "as102_fw.h" + +static void as102_usb_disconnect(struct usb_interface *interface); +static int as102_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id); + +static int as102_usb_start_stream(struct as102_dev_t *dev); +static void as102_usb_stop_stream(struct as102_dev_t *dev); + +static int as102_open(struct inode *inode, struct file *file); +static int as102_release(struct inode *inode, struct file *file); + +static struct usb_device_id as102_usb_id_table[] = { + { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, + { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, + { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, + { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, + { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, + { } /* Terminating entry */ +}; + +/* Note that this table must always have the same number of entries as the + as102_usb_id_table struct */ +static const char * const as102_device_names[] = { + AS102_REFERENCE_DESIGN, + AS102_PCTV_74E, + AS102_ELGATO_EYETV_DTT_NAME, + AS102_NBOX_DVBT_DONGLE_NAME, + AS102_SKY_IT_DIGITAL_KEY_NAME, + NULL /* Terminating entry */ +}; + +/* eLNA configuration: devices built on the reference design work best + with 0xA0, while custom designs seem to require 0xC0 */ +static uint8_t const as102_elna_cfg[] = { + 0xA0, + 0xC0, + 0xC0, + 0xA0, + 0xA0, + 0x00 /* Terminating entry */ +}; + +struct usb_driver as102_usb_driver = { + .name = DRIVER_FULL_NAME, + .probe = as102_usb_probe, + .disconnect = as102_usb_disconnect, + .id_table = as102_usb_id_table +}; + +static const struct file_operations as102_dev_fops = { + .owner = THIS_MODULE, + .open = as102_open, + .release = as102_release, +}; + +static struct usb_class_driver as102_usb_class_driver = { + .name = "aton2-%d", + .fops = &as102_dev_fops, + .minor_base = AS102_DEVICE_MAJOR, +}; + +static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, + unsigned char *send_buf, int send_buf_len, + unsigned char *recv_buf, int recv_buf_len) +{ + int ret = 0; + + if (send_buf != NULL) { + ret = usb_control_msg(bus_adap->usb_dev, + usb_sndctrlpipe(bus_adap->usb_dev, 0), + AS102_USB_DEVICE_TX_CTRL_CMD, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + bus_adap->cmd_xid, /* value */ + 0, /* index */ + send_buf, send_buf_len, + USB_CTRL_SET_TIMEOUT /* 200 */); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(send) failed, err %i\n", ret); + return ret; + } + + if (ret != send_buf_len) { + dev_dbg(&bus_adap->usb_dev->dev, + "only wrote %d of %d bytes\n", ret, send_buf_len); + return -1; + } + } + + if (recv_buf != NULL) { +#ifdef TRACE + dev_dbg(bus_adap->usb_dev->dev, + "want to read: %d bytes\n", recv_buf_len); +#endif + ret = usb_control_msg(bus_adap->usb_dev, + usb_rcvctrlpipe(bus_adap->usb_dev, 0), + AS102_USB_DEVICE_RX_CTRL_CMD, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + bus_adap->cmd_xid, /* value */ + 0, /* index */ + recv_buf, recv_buf_len, + USB_CTRL_GET_TIMEOUT /* 200 */); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(recv) failed, err %i\n", ret); + return ret; + } +#ifdef TRACE + dev_dbg(bus_adap->usb_dev->dev, + "read %d bytes\n", recv_buf_len); +#endif + } + + return ret; +} + +static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, + unsigned char *send_buf, + int send_buf_len, + int swap32) +{ + int ret = 0, actual_len; + + ret = usb_bulk_msg(bus_adap->usb_dev, + usb_sndbulkpipe(bus_adap->usb_dev, 1), + send_buf, send_buf_len, &actual_len, 200); + if (ret) { + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(send) failed, err %i\n", ret); + return ret; + } + + if (actual_len != send_buf_len) { + dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", + actual_len, send_buf_len); + return -1; + } + return ret ? ret : actual_len; +} + +static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, + unsigned char *recv_buf, int recv_buf_len) +{ + int ret = 0, actual_len; + + if (recv_buf == NULL) + return -EINVAL; + + ret = usb_bulk_msg(bus_adap->usb_dev, + usb_rcvbulkpipe(bus_adap->usb_dev, 2), + recv_buf, recv_buf_len, &actual_len, 200); + if (ret) { + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(recv) failed, err %i\n", ret); + return ret; + } + + if (actual_len != recv_buf_len) { + dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", + actual_len, recv_buf_len); + return -1; + } + return ret ? ret : actual_len; +} + +static struct as102_priv_ops_t as102_priv_ops = { + .upload_fw_pkt = as102_send_ep1, + .xfer_cmd = as102_usb_xfer_cmd, + .as102_read_ep2 = as102_read_ep2, + .start_stream = as102_usb_start_stream, + .stop_stream = as102_usb_stop_stream, +}; + +static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) +{ + int err; + + usb_fill_bulk_urb(urb, + dev->bus_adap.usb_dev, + usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), + urb->transfer_buffer, + AS102_USB_BUF_SIZE, + as102_urb_stream_irq, + dev); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dev_dbg(&urb->dev->dev, + "%s: usb_submit_urb failed\n", __func__); + + return err; +} + +void as102_urb_stream_irq(struct urb *urb) +{ + struct as102_dev_t *as102_dev = urb->context; + + if (urb->actual_length > 0) { + dvb_dmx_swfilter(&as102_dev->dvb_dmx, + urb->transfer_buffer, + urb->actual_length); + } else { + if (urb->actual_length == 0) + memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); + } + + /* is not stopped, re-submit urb */ + if (as102_dev->streaming) + as102_submit_urb_stream(as102_dev, urb); +} + +static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) +{ + int i; + + for (i = 0; i < MAX_STREAM_URB; i++) + usb_free_urb(dev->stream_urb[i]); + + usb_free_coherent(dev->bus_adap.usb_dev, + MAX_STREAM_URB * AS102_USB_BUF_SIZE, + dev->stream, + dev->dma_addr); +} + +static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) +{ + int i; + + dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, + MAX_STREAM_URB * AS102_USB_BUF_SIZE, + GFP_KERNEL, + &dev->dma_addr); + if (!dev->stream) { + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_buffer_alloc failed\n", __func__); + return -ENOMEM; + } + + memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); + + /* init urb buffers */ + for (i = 0; i < MAX_STREAM_URB; i++) { + struct urb *urb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) { + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_alloc_urb failed\n", __func__); + as102_free_usb_stream_buffer(dev); + return -ENOMEM; + } + + urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); + urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE); + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_buffer_length = AS102_USB_BUF_SIZE; + + dev->stream_urb[i] = urb; + } + return 0; +} + +static void as102_usb_stop_stream(struct as102_dev_t *dev) +{ + int i; + + for (i = 0; i < MAX_STREAM_URB; i++) + usb_kill_urb(dev->stream_urb[i]); +} + +static int as102_usb_start_stream(struct as102_dev_t *dev) +{ + int i, ret = 0; + + for (i = 0; i < MAX_STREAM_URB; i++) { + ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); + if (ret) { + as102_usb_stop_stream(dev); + return ret; + } + } + + return 0; +} + +static void as102_usb_release(struct kref *kref) +{ + struct as102_dev_t *as102_dev; + + as102_dev = container_of(kref, struct as102_dev_t, kref); + if (as102_dev != NULL) { + usb_put_dev(as102_dev->bus_adap.usb_dev); + kfree(as102_dev); + } +} + +static void as102_usb_disconnect(struct usb_interface *intf) +{ + struct as102_dev_t *as102_dev; + + /* extract as102_dev_t from usb_device private data */ + as102_dev = usb_get_intfdata(intf); + + /* unregister dvb layer */ + as102_dvb_unregister(as102_dev); + + /* free usb buffers */ + as102_free_usb_stream_buffer(as102_dev); + + usb_set_intfdata(intf, NULL); + + /* usb unregister device */ + usb_deregister_dev(intf, &as102_usb_class_driver); + + /* decrement usage counter */ + kref_put(&as102_dev->kref, as102_usb_release); + + pr_info("%s: device has been disconnected\n", DRIVER_NAME); +} + +static int as102_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct as102_dev_t *as102_dev; + int i; + + /* This should never actually happen */ + if (ARRAY_SIZE(as102_usb_id_table) != + (sizeof(as102_device_names) / sizeof(const char *))) { + pr_err("Device names table invalid size"); + return -EINVAL; + } + + as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); + if (as102_dev == NULL) + return -ENOMEM; + + /* Assign the user-friendly device name */ + for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) { + if (id == &as102_usb_id_table[i]) { + as102_dev->name = as102_device_names[i]; + as102_dev->elna_cfg = as102_elna_cfg[i]; + } + } + + if (as102_dev->name == NULL) + as102_dev->name = "Unknown AS102 device"; + + /* set private callback functions */ + as102_dev->bus_adap.ops = &as102_priv_ops; + + /* init cmd token for usb bus */ + as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; + as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; + + /* init kernel device reference */ + kref_init(&as102_dev->kref); + + /* store as102 device to usb_device private data */ + usb_set_intfdata(intf, (void *) as102_dev); + + /* store in as102 device the usb_device pointer */ + as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); + + /* we can register the device now, as it is ready */ + ret = usb_register_dev(intf, &as102_usb_class_driver); + if (ret < 0) { + /* something prevented us from registering this driver */ + dev_err(&intf->dev, + "%s: usb_register_dev() failed (errno = %d)\n", + __func__, ret); + goto failed; + } + + pr_info("%s: device has been detected\n", DRIVER_NAME); + + /* request buffer allocation for streaming */ + ret = as102_alloc_usb_stream_buffer(as102_dev); + if (ret != 0) + goto failed_stream; + + /* register dvb layer */ + ret = as102_dvb_register(as102_dev); + if (ret != 0) + goto failed_dvb; + + return ret; + +failed_dvb: + as102_free_usb_stream_buffer(as102_dev); +failed_stream: + usb_deregister_dev(intf, &as102_usb_class_driver); +failed: + usb_put_dev(as102_dev->bus_adap.usb_dev); + usb_set_intfdata(intf, NULL); + kfree(as102_dev); + return ret; +} + +static int as102_open(struct inode *inode, struct file *file) +{ + int ret = 0, minor = 0; + struct usb_interface *intf = NULL; + struct as102_dev_t *dev = NULL; + + /* read minor from inode */ + minor = iminor(inode); + + /* fetch device from usb interface */ + intf = usb_find_interface(&as102_usb_driver, minor); + if (intf == NULL) { + pr_err("%s: can't find device for minor %d\n", + __func__, minor); + ret = -ENODEV; + goto exit; + } + + /* get our device */ + dev = usb_get_intfdata(intf); + if (dev == NULL) { + ret = -EFAULT; + goto exit; + } + + /* save our device object in the file's private structure */ + file->private_data = dev; + + /* increment our usage count for the device */ + kref_get(&dev->kref); + +exit: + return ret; +} + +static int as102_release(struct inode *inode, struct file *file) +{ + struct as102_dev_t *dev = NULL; + + dev = file->private_data; + if (dev != NULL) { + /* decrement the count on our device */ + kref_put(&dev->kref, as102_usb_release); + } + + return 0; +} + +MODULE_DEVICE_TABLE(usb, as102_usb_id_table); diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h new file mode 100644 index 000000000000..1ad1ec52b11e --- /dev/null +++ b/drivers/media/usb/as102/as102_usb_drv.h @@ -0,0 +1,61 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 _AS102_USB_DRV_H_ +#define _AS102_USB_DRV_H_ + +#define AS102_USB_DEVICE_TX_CTRL_CMD 0xF1 +#define AS102_USB_DEVICE_RX_CTRL_CMD 0xF2 + +/* define these values to match the supported devices */ + +/* Abilis system: "TITAN" */ +#define AS102_REFERENCE_DESIGN "Abilis Systems DVB-Titan" +#define AS102_USB_DEVICE_VENDOR_ID 0x1BA6 +#define AS102_USB_DEVICE_PID_0001 0x0001 + +/* PCTV Systems: PCTV picoStick (74e) */ +#define AS102_PCTV_74E "PCTV Systems picoStick (74e)" +#define PCTV_74E_USB_VID 0x2013 +#define PCTV_74E_USB_PID 0x0246 + +/* Elgato: EyeTV DTT Deluxe */ +#define AS102_ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" +#define ELGATO_EYETV_DTT_USB_VID 0x0fd9 +#define ELGATO_EYETV_DTT_USB_PID 0x002c + +/* nBox: nBox DVB-T Dongle */ +#define AS102_NBOX_DVBT_DONGLE_NAME "nBox DVB-T Dongle" +#define NBOX_DVBT_DONGLE_USB_VID 0x0b89 +#define NBOX_DVBT_DONGLE_USB_PID 0x0007 + +/* Sky Italia: Digital Key (green led) */ +#define AS102_SKY_IT_DIGITAL_KEY_NAME "Sky IT Digital Key (green led)" +#define SKY_IT_DIGITAL_KEY_USB_VID 0x2137 +#define SKY_IT_DIGITAL_KEY_USB_PID 0x0001 + +void as102_urb_stream_irq(struct urb *urb); + +struct as10x_usb_token_cmd_t { + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +}; +#endif diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c new file mode 100644 index 000000000000..9e49f15a7c9f --- /dev/null +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -0,0 +1,418 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 "as102_drv.h" +#include "as10x_types.h" +#include "as10x_cmd.h" + +/** + * as10x_cmd_turn_on - send turn on command to AS10x + * @adap: pointer to AS10x bus adapter + * + * Return 0 when no error, < 0 in case of error. + */ +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.turn_on.req)); + + /* fill command */ + pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_on.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_on.rsp) + + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); + +out: + return error; +} + +/** + * as10x_cmd_turn_off - send turn off command to AS10x + * @adap: pointer to AS10x bus adapter + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.turn_off.req)); + + /* fill command */ + pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); + +out: + return error; +} + +/** + * as10x_cmd_set_tune - send set tune command to AS10x + * @adap: pointer to AS10x bus adapter + * @ptune: tune parameters + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, + struct as10x_tune_args *ptune) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *preq, *prsp; + + preq = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(preq, (++adap->cmd_xid), + sizeof(preq->body.set_tune.req)); + + /* fill command */ + preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); + preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); + preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; + preq->body.set_tune.req.args.hier_select = ptune->hier_select; + preq->body.set_tune.req.args.modulation = ptune->modulation; + preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; + preq->body.set_tune.req.args.interleaving_mode = + ptune->interleaving_mode; + preq->body.set_tune.req.args.code_rate = ptune->code_rate; + preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; + preq->body.set_tune.req.args.transmission_mode = + ptune->transmission_mode; + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) preq, + sizeof(preq->body.set_tune.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.set_tune.rsp) + + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); + +out: + return error; +} + +/** + * as10x_cmd_get_tune_status - send get tune status command to AS10x + * @adap: pointer to AS10x bus adapter + * @pstatus: pointer to updated status structure of the current tune + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, + struct as10x_tune_status *pstatus) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *preq, *prsp; + + preq = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(preq, (++adap->cmd_xid), + sizeof(preq->body.get_tune_status.req)); + + /* fill command */ + preq->body.get_tune_status.req.proc_id = + cpu_to_le16(CONTROL_PROC_GETTUNESTAT); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, + (uint8_t *) preq, + sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); + if (error < 0) + goto out; + + /* Response OK -> get response data */ + pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; + pstatus->signal_strength = + le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); + pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); + pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); + +out: + return error; +} + +/** + * as10x_cmd_get_tps - send get TPS command to AS10x + * @adap: pointer to AS10x handle + * @ptps: pointer to TPS parameters structure + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.get_tps.req)); + + /* fill command */ + pcmd->body.get_tune_status.req.proc_id = + cpu_to_le16(CONTROL_PROC_GETTPS); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_tps.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tps.rsp) + + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); + if (error < 0) + goto out; + + /* Response OK -> get response data */ + ptps->modulation = prsp->body.get_tps.rsp.tps.modulation; + ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; + ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; + ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; + ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; + ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; + ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; + ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; + ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; + ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); + +out: + return error; +} + +/** + * as10x_cmd_get_demod_stats - send get demod stats command to AS10x + * @adap: pointer to AS10x bus adapter + * @pdemod_stats: pointer to demod stats parameters structure + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, + struct as10x_demod_stats *pdemod_stats) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.get_demod_stats.req)); + + /* fill command */ + pcmd->body.get_demod_stats.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_demod_stats.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_demod_stats.rsp) + + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP); + if (error < 0) + goto out; + + /* Response OK -> get response data */ + pdemod_stats->frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); + pdemod_stats->bad_frame_count = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); + pdemod_stats->bytes_fixed_by_rs = + le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); + pdemod_stats->mer = + le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); + pdemod_stats->has_started = + prsp->body.get_demod_stats.rsp.stats.has_started; + +out: + return error; +} + +/** + * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x + * @adap: pointer to AS10x bus adapter + * @is_ready: pointer to value indicating when impulse + * response data is ready + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, + uint8_t *is_ready) +{ + int error = AS10X_CMD_ERROR; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.get_impulse_rsp.req)); + + /* fill command */ + pcmd->body.get_impulse_rsp.req.proc_id = + cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_impulse_rsp.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_impulse_rsp.rsp) + + HEADER_SIZE); + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP); + if (error < 0) + goto out; + + /* Response OK -> get response data */ + *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; + +out: + return error; +} + +/** + * as10x_cmd_build - build AS10x command header + * @pcmd: pointer to AS10x command buffer + * @xid: sequence id of the command + * @cmd_len: length of the command + */ +void as10x_cmd_build(struct as10x_cmd_t *pcmd, + uint16_t xid, uint16_t cmd_len) +{ + pcmd->header.req_id = cpu_to_le16(xid); + pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); + pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); + pcmd->header.data_len = cpu_to_le16(cmd_len); +} + +/** + * as10x_rsp_parse - Parse command response + * @prsp: pointer to AS10x command buffer + * @proc_id: id of the command + * + * Return 0 on success or negative value in case of error. + */ +int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) +{ + int error; + + /* extract command error code */ + error = prsp->body.common.rsp.error; + + if ((error == 0) && + (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { + return 0; + } + + return AS10X_CMD_ERROR; +} diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h new file mode 100644 index 000000000000..e21ec6c702a9 --- /dev/null +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -0,0 +1,529 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 _AS10X_CMD_H_ +#define _AS10X_CMD_H_ + +#ifdef __KERNEL__ +#include +#endif + +#include "as10x_types.h" + +/*********************************/ +/* MACRO DEFINITIONS */ +/*********************************/ +#define AS10X_CMD_ERROR -1 + +#define SERVICE_PROG_ID 0x0002 +#define SERVICE_PROG_VERSION 0x0001 + +#define HIER_NONE 0x00 +#define HIER_LOW_PRIORITY 0x01 + +#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) + +/* context request types */ +#define GET_CONTEXT_DATA 1 +#define SET_CONTEXT_DATA 2 + +/* ODSP suspend modes */ +#define CFG_MODE_ODSP_RESUME 0 +#define CFG_MODE_ODSP_SUSPEND 1 + +/* Dump memory size */ +#define DUMP_BLOCK_SIZE_MAX 0x20 + +/*********************************/ +/* TYPE DEFINITION */ +/*********************************/ +enum control_proc { + CONTROL_PROC_TURNON = 0x0001, + CONTROL_PROC_TURNON_RSP = 0x0100, + CONTROL_PROC_SET_REGISTER = 0x0002, + CONTROL_PROC_SET_REGISTER_RSP = 0x0200, + CONTROL_PROC_GET_REGISTER = 0x0003, + CONTROL_PROC_GET_REGISTER_RSP = 0x0300, + CONTROL_PROC_SETTUNE = 0x000A, + CONTROL_PROC_SETTUNE_RSP = 0x0A00, + CONTROL_PROC_GETTUNESTAT = 0x000B, + CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, + CONTROL_PROC_GETTPS = 0x000D, + CONTROL_PROC_GETTPS_RSP = 0x0D00, + CONTROL_PROC_SETFILTER = 0x000E, + CONTROL_PROC_SETFILTER_RSP = 0x0E00, + CONTROL_PROC_REMOVEFILTER = 0x000F, + CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, + CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, + CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, + CONTROL_PROC_START_STREAMING = 0x0013, + CONTROL_PROC_START_STREAMING_RSP = 0x1300, + CONTROL_PROC_STOP_STREAMING = 0x0014, + CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, + CONTROL_PROC_GET_DEMOD_STATS = 0x0015, + CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, + CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, + CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, + CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, + CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, + CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, + CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, + + CONTROL_PROC_CONTEXT = 0x00FC, + CONTROL_PROC_CONTEXT_RSP = 0xFC00, + CONTROL_PROC_DUMP_MEMORY = 0x00FD, + CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, + CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, + CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, + CONTROL_PROC_TURNOFF = 0x00FF, + CONTROL_PROC_TURNOFF_RSP = 0xFF00 +}; + +union as10x_turn_on { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_turn_off { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t err; + } __packed rsp; +} __packed; + +union as10x_set_tune { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* tune params */ + struct as10x_tune_args args; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_get_tune_status { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tune status */ + struct as10x_tune_status sts; + } __packed rsp; +} __packed; + +union as10x_get_tps { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tps details */ + struct as10x_tps tps; + } __packed rsp; +} __packed; + +union as10x_common { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_add_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to filter */ + uint16_t pid; + /* stream type (MPE, PSI/SI or PES )*/ + uint8_t stream_type; + /* PID index in filter table */ + uint8_t idx; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* Filter id */ + uint8_t filter_id; + } __packed rsp; +} __packed; + +union as10x_del_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to remove */ + uint16_t pid; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_start_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_stop_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_get_demod_stats { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* demod stats */ + struct as10x_demod_stats stats; + } __packed rsp; +} __packed; + +union as10x_get_impulse_resp { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* impulse response ready */ + uint8_t is_ready; + } __packed rsp; +} __packed; + +union as10x_fw_context { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* value to write (for set context)*/ + struct as10x_register_value reg_val; + /* context tag */ + uint16_t tag; + /* context request type */ + uint16_t type; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* value read (for get context) */ + struct as10x_register_value reg_val; + /* context request type */ + uint16_t type; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_set_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + /* register content */ + struct as10x_register_value reg_val; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +union as10x_get_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* register content */ + struct as10x_register_value reg_val; + } __packed rsp; +} __packed; + +union as10x_cfg_change_mode { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* mode */ + uint8_t mode; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } __packed rsp; +} __packed; + +struct as10x_cmd_header_t { + uint16_t req_id; + uint16_t prog; + uint16_t version; + uint16_t data_len; +} __packed; + +#define DUMP_BLOCK_SIZE 16 + +union as10x_dump_memory { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + /* register description */ + struct as10x_register_addr reg_addr; + /* nb blocks to read */ + uint16_t num_blocks; + } __packed req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* data */ + union { + uint8_t data8[DUMP_BLOCK_SIZE]; + uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; + uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; + } __packed u; + } __packed rsp; +} __packed; + +union as10x_dumplog_memory { + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + } __packed req; + struct { + /* request identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* dump data */ + uint8_t data[DUMP_BLOCK_SIZE]; + } __packed rsp; +} __packed; + +union as10x_raw_data { + /* request */ + struct { + uint16_t proc_id; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */]; + } __packed req; + /* response */ + struct { + uint16_t proc_id; + uint8_t error; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */ - 1 /* rc */]; + } __packed rsp; +} __packed; + +struct as10x_cmd_t { + struct as10x_cmd_header_t header; + union { + union as10x_turn_on turn_on; + union as10x_turn_off turn_off; + union as10x_set_tune set_tune; + union as10x_get_tune_status get_tune_status; + union as10x_get_tps get_tps; + union as10x_common common; + union as10x_add_pid_filter add_pid_filter; + union as10x_del_pid_filter del_pid_filter; + union as10x_start_streaming start_streaming; + union as10x_stop_streaming stop_streaming; + union as10x_get_demod_stats get_demod_stats; + union as10x_get_impulse_resp get_impulse_rsp; + union as10x_fw_context context; + union as10x_set_register set_register; + union as10x_get_register get_register; + union as10x_cfg_change_mode cfg_change_mode; + union as10x_dump_memory dump_memory; + union as10x_dumplog_memory dumplog_memory; + union as10x_raw_data raw_data; + } __packed body; +} __packed; + +struct as10x_token_cmd_t { + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +} __packed; + + +/**************************/ +/* FUNCTION DECLARATION */ +/**************************/ + +void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, + uint16_t cmd_len); +int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); + +/* as10x cmd */ +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap); +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap); + +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, + struct as10x_tune_args *ptune); + +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, + struct as10x_tune_status *pstatus); + +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, + struct as10x_tps *ptps); + +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, + struct as10x_demod_stats *pdemod_stats); + +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, + uint8_t *is_ready); + +/* as10x cmd stream */ +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, + struct as10x_ts_filter *filter); +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, + uint16_t pid_value); + +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap); +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap); + +/* as10x cmd cfg */ +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, + uint16_t tag, + uint32_t value); +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, + uint16_t tag, + uint32_t *pvalue); + +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode); +int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); +#endif diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c new file mode 100644 index 000000000000..b1e300d88753 --- /dev/null +++ b/drivers/media/usb/as102/as10x_cmd_cfg.c @@ -0,0 +1,206 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 "as102_drv.h" +#include "as10x_types.h" +#include "as10x_cmd.h" + +/***************************/ +/* FUNCTION DEFINITION */ +/***************************/ + +/** + * as10x_cmd_get_context - Send get context command to AS10x + * @adap: pointer to AS10x bus adapter + * @tag: context tag + * @pvalue: pointer where to store context value read + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, + uint32_t *pvalue) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.context.req)); + + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + + if (error == 0) { + /* Response OK -> get response data */ + *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); + /* value returned is always a 32-bit value */ + } + +out: + return error; +} + +/** + * as10x_cmd_set_context - send set context command to AS10x + * @adap: pointer to AS10x bus adapter + * @tag: context tag + * @value: value to set in context + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, + uint32_t value) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.context.req)); + + /* fill command */ + pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); + /* pcmd->body.context.req.reg_val.mode initialization is not required */ + pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); + pcmd->body.context.req.tag = cpu_to_le16(tag); + pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response: context command do not follow the common response */ + /* structure -> specific handling response parse required */ + error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); + +out: + return error; +} + +/** + * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x + * @adap: pointer to AS10x bus adapter + * @mode: mode selected: + * - ON : 0x0 => eLNA always ON + * - OFF : 0x1 => eLNA always OFF + * - AUTO : 0x2 => eLNA follow hysteresis parameters + * to be ON or OFF + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.cfg_change_mode.req)); + + /* fill command */ + pcmd->body.cfg_change_mode.req.proc_id = + cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); + pcmd->body.cfg_change_mode.req.mode = mode; + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.cfg_change_mode.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.cfg_change_mode.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); + +out: + return error; +} + +/** + * as10x_context_rsp_parse - Parse context command response + * @prsp: pointer to AS10x command response buffer + * @proc_id: id of the command + * + * Since the contex command response does not follow the common + * response, a specific parse function is required. + * Return 0 on success or negative value in case of error. + */ +int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) +{ + int err; + + err = prsp->body.context.rsp.error; + + if ((err == 0) && + (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { + return 0; + } + return AS10X_CMD_ERROR; +} diff --git a/drivers/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c new file mode 100644 index 000000000000..1088ca1fe92f --- /dev/null +++ b/drivers/media/usb/as102/as10x_cmd_stream.c @@ -0,0 +1,211 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 "as102_drv.h" +#include "as10x_cmd.h" + +/** + * as10x_cmd_add_PID_filter - send add filter command to AS10x + * @adap: pointer to AS10x bus adapter + * @filter: TSFilter filter for DVB-T + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, + struct as10x_ts_filter *filter) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.add_pid_filter.req)); + + /* fill command */ + pcmd->body.add_pid_filter.req.proc_id = + cpu_to_le16(CONTROL_PROC_SETFILTER); + pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); + pcmd->body.add_pid_filter.req.stream_type = filter->type; + + if (filter->idx < 16) + pcmd->body.add_pid_filter.req.idx = filter->idx; + else + pcmd->body.add_pid_filter.req.idx = 0xFF; + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.add_pid_filter.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.add_pid_filter.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); + + if (error == 0) { + /* Response OK -> get response data */ + filter->idx = prsp->body.add_pid_filter.rsp.filter_id; + } + +out: + return error; +} + +/** + * as10x_cmd_del_PID_filter - Send delete filter command to AS10x + * @adap: pointer to AS10x bus adapte + * @pid_value: PID to delete + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, + uint16_t pid_value) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.del_pid_filter.req)); + + /* fill command */ + pcmd->body.del_pid_filter.req.proc_id = + cpu_to_le16(CONTROL_PROC_REMOVEFILTER); + pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.del_pid_filter.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.del_pid_filter.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); + +out: + return error; +} + +/** + * as10x_cmd_start_streaming - Send start streaming command to AS10x + * @adap: pointer to AS10x bus adapter + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap) +{ + int error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.start_streaming.req)); + + /* fill command */ + pcmd->body.start_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_START_STREAMING); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.start_streaming.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.start_streaming.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); + +out: + return error; +} + +/** + * as10x_cmd_stop_streaming - Send stop streaming command to AS10x + * @adap: pointer to AS10x bus adapter + * + * Return 0 on success or negative value in case of error. + */ +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap) +{ + int8_t error; + struct as10x_cmd_t *pcmd, *prsp; + + pcmd = adap->cmd; + prsp = adap->rsp; + + /* prepare command */ + as10x_cmd_build(pcmd, (++adap->cmd_xid), + sizeof(pcmd->body.stop_streaming.req)); + + /* fill command */ + pcmd->body.stop_streaming.req.proc_id = + cpu_to_le16(CONTROL_PROC_STOP_STREAMING); + + /* send command */ + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.stop_streaming.req) + + HEADER_SIZE, (uint8_t *) prsp, + sizeof(prsp->body.stop_streaming.rsp) + + HEADER_SIZE); + } else { + error = AS10X_CMD_ERROR; + } + + if (error < 0) + goto out; + + /* parse response */ + error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); + +out: + return error; +} diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h new file mode 100644 index 000000000000..5638b191b780 --- /dev/null +++ b/drivers/media/usb/as102/as10x_handle.h @@ -0,0 +1,54 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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. + */ +#ifdef __KERNEL__ +struct as10x_bus_adapter_t; +struct as102_dev_t; + +#include "as10x_cmd.h" + +/* values for "mode" field */ +#define REGMODE8 8 +#define REGMODE16 16 +#define REGMODE32 32 + +struct as102_priv_ops_t { + int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap, + unsigned char *buf, int buflen, int swap32); + + int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap, + unsigned char *buf, int buflen); + + int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap, + unsigned char *send_buf, int send_buf_len, + unsigned char *recv_buf, int recv_buf_len); + + int (*start_stream)(struct as102_dev_t *dev); + void (*stop_stream)(struct as102_dev_t *dev); + + int (*reset_target)(struct as10x_bus_adapter_t *bus_adap); + + int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode, + uint32_t rd_addr, uint16_t rd_len, + uint32_t wr_addr, uint16_t wr_len); + + int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap, + unsigned char *recv_buf, + int recv_buf_len); +}; +#endif diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h new file mode 100644 index 000000000000..af26e057d9a2 --- /dev/null +++ b/drivers/media/usb/as102/as10x_types.h @@ -0,0 +1,194 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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 _AS10X_TYPES_H_ +#define _AS10X_TYPES_H_ + +#include "as10x_handle.h" + +/*********************************/ +/* MACRO DEFINITIONS */ +/*********************************/ + +/* bandwidth constant values */ +#define BW_5_MHZ 0x00 +#define BW_6_MHZ 0x01 +#define BW_7_MHZ 0x02 +#define BW_8_MHZ 0x03 + +/* hierarchy priority selection values */ +#define HIER_NO_PRIORITY 0x00 +#define HIER_LOW_PRIORITY 0x01 +#define HIER_HIGH_PRIORITY 0x02 + +/* constellation available values */ +#define CONST_QPSK 0x00 +#define CONST_QAM16 0x01 +#define CONST_QAM64 0x02 +#define CONST_UNKNOWN 0xFF + +/* hierarchy available values */ +#define HIER_NONE 0x00 +#define HIER_ALPHA_1 0x01 +#define HIER_ALPHA_2 0x02 +#define HIER_ALPHA_4 0x03 +#define HIER_UNKNOWN 0xFF + +/* interleaving available values */ +#define INTLV_NATIVE 0x00 +#define INTLV_IN_DEPTH 0x01 +#define INTLV_UNKNOWN 0xFF + +/* code rate available values */ +#define CODE_RATE_1_2 0x00 +#define CODE_RATE_2_3 0x01 +#define CODE_RATE_3_4 0x02 +#define CODE_RATE_5_6 0x03 +#define CODE_RATE_7_8 0x04 +#define CODE_RATE_UNKNOWN 0xFF + +/* guard interval available values */ +#define GUARD_INT_1_32 0x00 +#define GUARD_INT_1_16 0x01 +#define GUARD_INT_1_8 0x02 +#define GUARD_INT_1_4 0x03 +#define GUARD_UNKNOWN 0xFF + +/* transmission mode available values */ +#define TRANS_MODE_2K 0x00 +#define TRANS_MODE_8K 0x01 +#define TRANS_MODE_4K 0x02 +#define TRANS_MODE_UNKNOWN 0xFF + +/* DVBH signalling available values */ +#define TIMESLICING_PRESENT 0x01 +#define MPE_FEC_PRESENT 0x02 + +/* tune state available */ +#define TUNE_STATUS_NOT_TUNED 0x00 +#define TUNE_STATUS_IDLE 0x01 +#define TUNE_STATUS_LOCKING 0x02 +#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 +#define TUNE_STATUS_STREAM_DETECTED 0x04 +#define TUNE_STATUS_STREAM_TUNED 0x05 +#define TUNE_STATUS_ERROR 0xFF + +/* available TS FID filter types */ +#define TS_PID_TYPE_TS 0 +#define TS_PID_TYPE_PSI_SI 1 +#define TS_PID_TYPE_MPE 2 + +/* number of echos available */ +#define MAX_ECHOS 15 + +/* Context types */ +#define CONTEXT_LNA 1010 +#define CONTEXT_ELNA_HYSTERESIS 4003 +#define CONTEXT_ELNA_GAIN 4004 +#define CONTEXT_MER_THRESHOLD 5005 +#define CONTEXT_MER_OFFSET 5006 +#define CONTEXT_IR_STATE 7000 +#define CONTEXT_TSOUT_MSB_FIRST 7004 +#define CONTEXT_TSOUT_FALLING_EDGE 7005 + +/* Configuration modes */ +#define CFG_MODE_ON 0 +#define CFG_MODE_OFF 1 +#define CFG_MODE_AUTO 2 + +struct as10x_tps { + uint8_t modulation; + uint8_t hierarchy; + uint8_t interleaving_mode; + uint8_t code_rate_HP; + uint8_t code_rate_LP; + uint8_t guard_interval; + uint8_t transmission_mode; + uint8_t DVBH_mask_HP; + uint8_t DVBH_mask_LP; + uint16_t cell_ID; +} __packed; + +struct as10x_tune_args { + /* frequency */ + uint32_t freq; + /* bandwidth */ + uint8_t bandwidth; + /* hierarchy selection */ + uint8_t hier_select; + /* constellation */ + uint8_t modulation; + /* hierarchy */ + uint8_t hierarchy; + /* interleaving mode */ + uint8_t interleaving_mode; + /* code rate */ + uint8_t code_rate; + /* guard interval */ + uint8_t guard_interval; + /* transmission mode */ + uint8_t transmission_mode; +} __packed; + +struct as10x_tune_status { + /* tune status */ + uint8_t tune_state; + /* signal strength */ + int16_t signal_strength; + /* packet error rate 10^-4 */ + uint16_t PER; + /* bit error rate 10^-4 */ + uint16_t BER; +} __packed; + +struct as10x_demod_stats { + /* frame counter */ + uint32_t frame_count; + /* Bad frame counter */ + uint32_t bad_frame_count; + /* Number of wrong bytes fixed by Reed-Solomon */ + uint32_t bytes_fixed_by_rs; + /* Averaged MER */ + uint16_t mer; + /* statistics calculation state indicator (started or not) */ + uint8_t has_started; +} __packed; + +struct as10x_ts_filter { + uint16_t pid; /* valid PID value 0x00 : 0x2000 */ + uint8_t type; /* Red TS_PID_TYPE_ values */ + uint8_t idx; /* index in filtering table */ +} __packed; + +struct as10x_register_value { + uint8_t mode; + union { + uint8_t value8; /* 8 bit value */ + uint16_t value16; /* 16 bit value */ + uint32_t value32; /* 32 bit value */ + } __packed u; +} __packed; + +struct as10x_register_addr { + /* register addr */ + uint32_t addr; + /* register mode access */ + uint8_t mode; +}; + +#endif diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 3323eb5e77b0..655cf5037b0b 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -19,8 +19,6 @@ menuconfig STAGING_MEDIA if STAGING_MEDIA # Please keep them in alphabetic order -source "drivers/staging/media/as102/Kconfig" - source "drivers/staging/media/bcm2048/Kconfig" source "drivers/staging/media/cxd2099/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 7db83f373f63..6dbe578178cd 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_DVB_AS102) += as102/ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig deleted file mode 100644 index 28aba00dc629..000000000000 --- a/drivers/staging/media/as102/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config DVB_AS102 - tristate "Abilis AS102 DVB receiver" - depends on DVB_CORE && USB && I2C && INPUT - select FW_LOADER - help - Choose Y or M here if you have a device containing an AS102 - - To compile this driver as a module, choose M here diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile deleted file mode 100644 index 8916d8a909bc..000000000000 --- a/drivers/staging/media/as102/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ - as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o - -obj-$(CONFIG_DVB_AS102) += dvb-as102.o - -ccflags-y += -Idrivers/media/dvb-core diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c deleted file mode 100644 index e0ee618e607a..000000000000 --- a/drivers/staging/media/as102/as102_drv.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 -#include -#include -#include -#include - -/* header file for usb device driver*/ -#include "as102_drv.h" -#include "as102_fw.h" -#include "dvbdev.h" - -int dual_tuner; -module_param_named(dual_tuner, dual_tuner, int, 0644); -MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); - -static int fw_upload = 1; -module_param_named(fw_upload, fw_upload, int, 0644); -MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); - -static int pid_filtering; -module_param_named(pid_filtering, pid_filtering, int, 0644); -MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); - -static int ts_auto_disable; -module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); -MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); - -int elna_enable = 1; -module_param_named(elna_enable, elna_enable, int, 0644); -MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void as102_stop_stream(struct as102_dev_t *dev) -{ - struct as10x_bus_adapter_t *bus_adap; - - if (dev != NULL) - bus_adap = &dev->bus_adap; - else - return; - - if (bus_adap->ops->stop_stream != NULL) - bus_adap->ops->stop_stream(dev); - - if (ts_auto_disable) { - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return; - - if (as10x_cmd_stop_streaming(bus_adap) < 0) - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_stop_streaming failed\n"); - - mutex_unlock(&dev->bus_adap.lock); - } -} - -static int as102_start_stream(struct as102_dev_t *dev) -{ - struct as10x_bus_adapter_t *bus_adap; - int ret = -EFAULT; - - if (dev != NULL) - bus_adap = &dev->bus_adap; - else - return ret; - - if (bus_adap->ops->start_stream != NULL) - ret = bus_adap->ops->start_stream(dev); - - if (ts_auto_disable) { - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EFAULT; - - ret = as10x_cmd_start_streaming(bus_adap); - - mutex_unlock(&dev->bus_adap.lock); - } - - return ret; -} - -static int as10x_pid_filter(struct as102_dev_t *dev, - int index, u16 pid, int onoff) { - - struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap; - int ret = -EFAULT; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "amutex_lock_interruptible(lock) failed !\n"); - return -EBUSY; - } - - switch (onoff) { - case 0: - ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dev_dbg(&dev->bus_adap.usb_dev->dev, - "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", - index, pid, ret); - break; - case 1: - { - struct as10x_ts_filter filter; - - filter.type = TS_PID_TYPE_TS; - filter.idx = 0xFF; - filter.pid = pid; - - ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dev_dbg(&dev->bus_adap.usb_dev->dev, - "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", - index, filter.idx, filter.pid, ret); - break; - } - } - - mutex_unlock(&dev->bus_adap.lock); - return ret; -} - -static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - int ret = 0; - struct dvb_demux *demux = dvbdmxfeed->demux; - struct as102_dev_t *as102_dev = demux->priv; - - if (mutex_lock_interruptible(&as102_dev->sem)) - return -ERESTARTSYS; - - if (pid_filtering) - as10x_pid_filter(as102_dev, dvbdmxfeed->index, - dvbdmxfeed->pid, 1); - - if (as102_dev->streaming++ == 0) - ret = as102_start_stream(as102_dev); - - mutex_unlock(&as102_dev->sem); - return ret; -} - -static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct as102_dev_t *as102_dev = demux->priv; - - if (mutex_lock_interruptible(&as102_dev->sem)) - return -ERESTARTSYS; - - if (--as102_dev->streaming == 0) - as102_stop_stream(as102_dev); - - if (pid_filtering) - as10x_pid_filter(as102_dev, dvbdmxfeed->index, - dvbdmxfeed->pid, 0); - - mutex_unlock(&as102_dev->sem); - return 0; -} - -int as102_dvb_register(struct as102_dev_t *as102_dev) -{ - struct device *dev = &as102_dev->bus_adap.usb_dev->dev; - int ret; - - ret = dvb_register_adapter(&as102_dev->dvb_adap, - as102_dev->name, THIS_MODULE, - dev, adapter_nr); - if (ret < 0) { - dev_err(dev, "%s: dvb_register_adapter() failed: %d\n", - __func__, ret); - return ret; - } - - as102_dev->dvb_dmx.priv = as102_dev; - as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256; - as102_dev->dvb_dmx.feednum = 256; - as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed; - as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed; - - as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING; - - as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum; - as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; - as102_dev->dvb_dmxdev.capabilities = 0; - - ret = dvb_dmx_init(&as102_dev->dvb_dmx); - if (ret < 0) { - dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret); - goto edmxinit; - } - - ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); - if (ret < 0) { - dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n", - __func__, ret); - goto edmxdinit; - } - - ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); - if (ret < 0) { - dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", - __func__, ret); - goto efereg; - } - - /* init bus mutex for token locking */ - mutex_init(&as102_dev->bus_adap.lock); - - /* init start / stop stream mutex */ - mutex_init(&as102_dev->sem); - - /* - * try to load as102 firmware. If firmware upload failed, we'll be - * able to upload it later. - */ - if (fw_upload) - try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), - "firmware_class"); - - pr_info("Registered device %s", as102_dev->name); - return 0; - -efereg: - dvb_dmxdev_release(&as102_dev->dvb_dmxdev); -edmxdinit: - dvb_dmx_release(&as102_dev->dvb_dmx); -edmxinit: - dvb_unregister_adapter(&as102_dev->dvb_adap); - return ret; -} - -void as102_dvb_unregister(struct as102_dev_t *as102_dev) -{ - /* unregister as102 frontend */ - as102_dvb_unregister_fe(&as102_dev->dvb_fe); - - /* unregister demux device */ - dvb_dmxdev_release(&as102_dev->dvb_dmxdev); - dvb_dmx_release(&as102_dev->dvb_dmx); - - /* unregister dvb adapter */ - dvb_unregister_adapter(&as102_dev->dvb_adap); - - pr_info("Unregistered device %s", as102_dev->name); -} - -module_usb_driver(as102_usb_driver); - -/* modinfo details */ -MODULE_DESCRIPTION(DRIVER_FULL_NAME); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pierrick Hascoet "); diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h deleted file mode 100644 index 49d0c4259b00..000000000000 --- a/drivers/staging/media/as102/as102_drv.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 -#include "as10x_cmd.h" -#include "as102_usb_drv.h" - -#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" -#define DRIVER_NAME "as10x_usb" - -#define debug as102_debug -extern struct usb_driver as102_usb_driver; -extern int elna_enable; - -#define AS102_DEVICE_MAJOR 192 - -#define AS102_USB_BUF_SIZE 512 -#define MAX_STREAM_URB 32 - -struct as10x_bus_adapter_t { - struct usb_device *usb_dev; - /* bus token lock */ - struct mutex lock; - /* low level interface for bus adapter */ - union as10x_bus_token_t { - /* usb token */ - struct as10x_usb_token_cmd_t usb; - } token; - - /* token cmd xfer id */ - uint16_t cmd_xid; - - /* as10x command and response for dvb interface*/ - struct as10x_cmd_t *cmd, *rsp; - - /* bus adapter private ops callback */ - struct as102_priv_ops_t *ops; -}; - -struct as102_dev_t { - const char *name; - struct as10x_bus_adapter_t bus_adap; - struct list_head device_entry; - struct kref kref; - uint8_t elna_cfg; - - struct dvb_adapter dvb_adap; - struct dvb_frontend dvb_fe; - struct dvb_demux dvb_dmx; - struct dmxdev dvb_dmxdev; - - /* demodulator stats */ - struct as10x_demod_stats demod_stats; - /* signal strength */ - uint16_t signal_strength; - /* bit error rate */ - uint32_t ber; - - /* timer handle to trig ts stream download */ - struct timer_list timer_handle; - - struct mutex sem; - dma_addr_t dma_addr; - void *stream; - int streaming; - struct urb *stream_urb[MAX_STREAM_URB]; -}; - -int as102_dvb_register(struct as102_dev_t *dev); -void as102_dvb_unregister(struct as102_dev_t *dev); - -int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); -int as102_dvb_unregister_fe(struct dvb_frontend *dev); diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c deleted file mode 100644 index 67e55b84493f..000000000000 --- a/drivers/staging/media/as102/as102_fe.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 "as102_drv.h" -#include "as10x_types.h" -#include "as10x_cmd.h" - -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, - struct as10x_tps *src); - -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, - struct dtv_frontend_properties *src); - -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_args tune_args = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - as102_fe_copy_tune_parameters(&tune_args, p); - - /* send abilis command: SET_TUNE */ - ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); - if (ret != 0) - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_set_tune failed. (err = %d)\n", ret); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tps tps = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -EINVAL; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TPS */ - ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); - - if (ret == 0) - as10x_fe_copy_tps_parameters(p, &tps); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *settings) { - - settings->min_delay_ms = 1000; - - return 0; -} - - -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_status tstate = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TUNE_STATUS */ - ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); - if (ret < 0) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_tune_status failed (err = %d)\n", - ret); - goto out; - } - - dev->signal_strength = tstate.signal_strength; - dev->ber = tstate.BER; - - switch (tstate.tune_state) { - case TUNE_STATUS_SIGNAL_DVB_OK: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - break; - case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; - break; - case TUNE_STATUS_STREAM_TUNED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; - break; - default: - *status = TUNE_STATUS_NOT_TUNED; - } - - dev_dbg(&dev->bus_adap.usb_dev->dev, - "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (*status & FE_HAS_LOCK) { - if (as10x_cmd_get_demod_stats(&dev->bus_adap, - (struct as10x_demod_stats *) &dev->demod_stats) < 0) { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); - } else { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, " - "bytes corrected: 0x%08x , MER: 0x%04x\n", - dev->demod_stats.frame_count, - dev->demod_stats.bad_frame_count, - dev->demod_stats.bytes_fixed_by_rs, - dev->demod_stats.mer); - } - } else { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - } - -out: - mutex_unlock(&dev->bus_adap.lock); - return ret; -} - -/* - * Note: - * - in AS102 SNR=MER - * - the SNR will be returned in linear terms, i.e. not in dB - * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB - * - the accuracy is >2dB for SNR values outside this range - */ -static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *snr = dev->demod_stats.mer; - - return 0; -} - -static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *ber = dev->ber; - - return 0; -} - -static int as102_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); - - return 0; -} - -static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (dev->demod_stats.has_started) - *ucblocks = dev->demod_stats.bad_frame_count; - else - *ucblocks = 0; - - return 0; -} - -static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct as102_dev_t *dev; - int ret; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - if (acquire) { - if (elna_enable) - as10x_cmd_set_context(&dev->bus_adap, - CONTEXT_LNA, dev->elna_cfg); - - ret = as10x_cmd_turn_on(&dev->bus_adap); - } else { - ret = as10x_cmd_turn_off(&dev->bus_adap); - } - - mutex_unlock(&dev->bus_adap.lock); - - return ret; -} - -static struct dvb_frontend_ops as102_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Unknown AS102 device", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .set_frontend = as102_fe_set_frontend, - .get_frontend = as102_fe_get_frontend, - .get_tune_settings = as102_fe_get_tune_settings, - - .read_status = as102_fe_read_status, - .read_snr = as102_fe_read_snr, - .read_ber = as102_fe_read_ber, - .read_signal_strength = as102_fe_read_signal_strength, - .read_ucblocks = as102_fe_read_ucblocks, - .ts_bus_ctrl = as102_fe_ts_bus_ctrl, -}; - -int as102_dvb_unregister_fe(struct dvb_frontend *fe) -{ - /* unregister frontend */ - dvb_unregister_frontend(fe); - - /* detach frontend */ - dvb_frontend_detach(fe); - - return 0; -} - -int as102_dvb_register_fe(struct as102_dev_t *as102_dev, - struct dvb_frontend *dvb_fe) -{ - int errno; - struct dvb_adapter *dvb_adap; - - if (as102_dev == NULL) - return -EINVAL; - - /* extract dvb_adapter */ - dvb_adap = &as102_dev->dvb_adap; - - /* init frontend callback ops */ - memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(dvb_fe->ops.info.name, as102_dev->name, - sizeof(dvb_fe->ops.info.name)); - - /* register dvb frontend */ - errno = dvb_register_frontend(dvb_adap, dvb_fe); - if (errno == 0) - dvb_fe->tuner_priv = as102_dev; - - return errno; -} - -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, - struct as10x_tps *as10x_tps) -{ - - /* extract constellation */ - switch (as10x_tps->modulation) { - case CONST_QPSK: - fe_tps->modulation = QPSK; - break; - case CONST_QAM16: - fe_tps->modulation = QAM_16; - break; - case CONST_QAM64: - fe_tps->modulation = QAM_64; - break; - } - - /* extract hierarchy */ - switch (as10x_tps->hierarchy) { - case HIER_NONE: - fe_tps->hierarchy = HIERARCHY_NONE; - break; - case HIER_ALPHA_1: - fe_tps->hierarchy = HIERARCHY_1; - break; - case HIER_ALPHA_2: - fe_tps->hierarchy = HIERARCHY_2; - break; - case HIER_ALPHA_4: - fe_tps->hierarchy = HIERARCHY_4; - break; - } - - /* extract code rate HP */ - switch (as10x_tps->code_rate_HP) { - case CODE_RATE_1_2: - fe_tps->code_rate_HP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_HP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_HP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_HP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_HP = FEC_7_8; - break; - } - - /* extract code rate LP */ - switch (as10x_tps->code_rate_LP) { - case CODE_RATE_1_2: - fe_tps->code_rate_LP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_LP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_LP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_LP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_LP = FEC_7_8; - break; - } - - /* extract guard interval */ - switch (as10x_tps->guard_interval) { - case GUARD_INT_1_32: - fe_tps->guard_interval = GUARD_INTERVAL_1_32; - break; - case GUARD_INT_1_16: - fe_tps->guard_interval = GUARD_INTERVAL_1_16; - break; - case GUARD_INT_1_8: - fe_tps->guard_interval = GUARD_INTERVAL_1_8; - break; - case GUARD_INT_1_4: - fe_tps->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - /* extract transmission mode */ - switch (as10x_tps->transmission_mode) { - case TRANS_MODE_2K: - fe_tps->transmission_mode = TRANSMISSION_MODE_2K; - break; - case TRANS_MODE_8K: - fe_tps->transmission_mode = TRANSMISSION_MODE_8K; - break; - } -} - -static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) -{ - uint8_t c; - - switch (arg) { - case FEC_1_2: - c = CODE_RATE_1_2; - break; - case FEC_2_3: - c = CODE_RATE_2_3; - break; - case FEC_3_4: - c = CODE_RATE_3_4; - break; - case FEC_5_6: - c = CODE_RATE_5_6; - break; - case FEC_7_8: - c = CODE_RATE_7_8; - break; - default: - c = CODE_RATE_UNKNOWN; - break; - } - - return c; -} - -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dtv_frontend_properties *params) -{ - - /* set frequency */ - tune_args->freq = params->frequency / 1000; - - /* fix interleaving_mode */ - tune_args->interleaving_mode = INTLV_NATIVE; - - switch (params->bandwidth_hz) { - case 8000000: - tune_args->bandwidth = BW_8_MHZ; - break; - case 7000000: - tune_args->bandwidth = BW_7_MHZ; - break; - case 6000000: - tune_args->bandwidth = BW_6_MHZ; - break; - default: - tune_args->bandwidth = BW_8_MHZ; - } - - switch (params->guard_interval) { - case GUARD_INTERVAL_1_32: - tune_args->guard_interval = GUARD_INT_1_32; - break; - case GUARD_INTERVAL_1_16: - tune_args->guard_interval = GUARD_INT_1_16; - break; - case GUARD_INTERVAL_1_8: - tune_args->guard_interval = GUARD_INT_1_8; - break; - case GUARD_INTERVAL_1_4: - tune_args->guard_interval = GUARD_INT_1_4; - break; - case GUARD_INTERVAL_AUTO: - default: - tune_args->guard_interval = GUARD_UNKNOWN; - break; - } - - switch (params->modulation) { - case QPSK: - tune_args->modulation = CONST_QPSK; - break; - case QAM_16: - tune_args->modulation = CONST_QAM16; - break; - case QAM_64: - tune_args->modulation = CONST_QAM64; - break; - default: - tune_args->modulation = CONST_UNKNOWN; - break; - } - - switch (params->transmission_mode) { - case TRANSMISSION_MODE_2K: - tune_args->transmission_mode = TRANS_MODE_2K; - break; - case TRANSMISSION_MODE_8K: - tune_args->transmission_mode = TRANS_MODE_8K; - break; - default: - tune_args->transmission_mode = TRANS_MODE_UNKNOWN; - } - - switch (params->hierarchy) { - case HIERARCHY_NONE: - tune_args->hierarchy = HIER_NONE; - break; - case HIERARCHY_1: - tune_args->hierarchy = HIER_ALPHA_1; - break; - case HIERARCHY_2: - tune_args->hierarchy = HIER_ALPHA_2; - break; - case HIERARCHY_4: - tune_args->hierarchy = HIER_ALPHA_4; - break; - case HIERARCHY_AUTO: - tune_args->hierarchy = HIER_UNKNOWN; - break; - } - - pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", - params->frequency, - tune_args->bandwidth, - tune_args->guard_interval); - - /* - * Detect a hierarchy selection - * if HP/LP are both set to FEC_NONE, HP will be selected. - */ - if ((tune_args->hierarchy != HIER_NONE) && - ((params->code_rate_LP == FEC_NONE) || - (params->code_rate_HP == FEC_NONE))) { - - if (params->code_rate_LP == FEC_NONE) { - tune_args->hier_select = HIER_HIGH_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); - } - - if (params->code_rate_HP == FEC_NONE) { - tune_args->hier_select = HIER_LOW_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_LP); - } - - pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", - tune_args->hierarchy, - tune_args->hier_select == HIER_HIGH_PRIORITY ? - "HP" : "LP", - tune_args->hier_select == HIER_HIGH_PRIORITY ? - "HP" : "LP", - tune_args->code_rate); - } else { - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); - } -} diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c deleted file mode 100644 index f33f752c0aad..000000000000 --- a/drivers/staging/media/as102/as102_fw.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 -#include - -#include "as102_drv.h" -#include "as102_fw.h" - -static const char as102_st_fw1[] = "as102_data1_st.hex"; -static const char as102_st_fw2[] = "as102_data2_st.hex"; -static const char as102_dt_fw1[] = "as102_data1_dt.hex"; -static const char as102_dt_fw2[] = "as102_data2_dt.hex"; - -static unsigned char atohx(unsigned char *dst, char *src) -{ - unsigned char value = 0; - - char msb = tolower(*src) - '0'; - char lsb = tolower(*(src + 1)) - '0'; - - if (msb > 9) - msb -= 7; - if (lsb > 9) - lsb -= 7; - - *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF); - return value; -} - -/* - * Parse INTEL HEX firmware file to extract address and data. - */ -static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, - unsigned char *data, int *dataLength, - unsigned char *addr_has_changed) { - - int count = 0; - unsigned char *src, dst; - - if (*fw_data++ != ':') { - pr_err("invalid firmware file\n"); - return -EFAULT; - } - - /* locate end of line */ - for (src = fw_data; *src != '\n'; src += 2) { - atohx(&dst, src); - /* parse line to split addr / data */ - switch (count) { - case 0: - *dataLength = dst; - break; - case 1: - addr[2] = dst; - break; - case 2: - addr[3] = dst; - break; - case 3: - /* check if data is an address */ - if (dst == 0x04) - *addr_has_changed = 1; - else - *addr_has_changed = 0; - break; - case 4: - case 5: - if (*addr_has_changed) - addr[(count - 4)] = dst; - else - data[(count - 4)] = dst; - break; - default: - data[(count - 4)] = dst; - break; - } - count++; - } - - /* return read value + ':' + '\n' */ - return (count * 2) + 2; -} - -static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, - unsigned char *cmd, - const struct firmware *firmware) { - - struct as10x_fw_pkt_t fw_pkt; - int total_read_bytes = 0, errno = 0; - unsigned char addr_has_changed = 0; - - for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { - int read_bytes = 0, data_len = 0; - - /* parse intel hex line */ - read_bytes = parse_hex_line( - (u8 *) (firmware->data + total_read_bytes), - fw_pkt.raw.address, - fw_pkt.raw.data, - &data_len, - &addr_has_changed); - - if (read_bytes <= 0) - goto error; - - /* detect the end of file */ - total_read_bytes += read_bytes; - if (total_read_bytes == firmware->size) { - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x03; - - /* send EOF command */ - errno = bus_adap->ops->upload_fw_pkt(bus_adap, - (uint8_t *) - &fw_pkt, 2, 0); - if (errno < 0) - goto error; - } else { - if (!addr_has_changed) { - /* prepare command to send */ - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x01; - - data_len += sizeof(fw_pkt.u.request); - data_len += sizeof(fw_pkt.raw.address); - - /* send cmd to device */ - errno = bus_adap->ops->upload_fw_pkt(bus_adap, - (uint8_t *) - &fw_pkt, - data_len, - 0); - if (errno < 0) - goto error; - } - } - } -error: - return (errno == 0) ? total_read_bytes : errno; -} - -int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) -{ - int errno = -EFAULT; - const struct firmware *firmware = NULL; - unsigned char *cmd_buf = NULL; - const char *fw1, *fw2; - struct usb_device *dev = bus_adap->usb_dev; - - /* select fw file to upload */ - if (dual_tuner) { - fw1 = as102_dt_fw1; - fw2 = as102_dt_fw2; - } else { - fw1 = as102_st_fw1; - fw2 = as102_st_fw2; - } - - /* allocate buffer to store firmware upload command and data */ - cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); - if (cmd_buf == NULL) { - errno = -ENOMEM; - goto error; - } - - /* request kernel to locate firmware file: part1 */ - errno = request_firmware(&firmware, fw1, &dev->dev); - if (errno < 0) { - pr_err("%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw1); - goto error; - } - - /* initiate firmware upload */ - errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); - if (errno < 0) { - pr_err("%s: error during firmware upload part1\n", - DRIVER_NAME); - goto error; - } - - pr_info("%s: firmware: %s loaded with success\n", - DRIVER_NAME, fw1); - release_firmware(firmware); - - /* wait for boot to complete */ - mdelay(100); - - /* request kernel to locate firmware file: part2 */ - errno = request_firmware(&firmware, fw2, &dev->dev); - if (errno < 0) { - pr_err("%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw2); - goto error; - } - - /* initiate firmware upload */ - errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); - if (errno < 0) { - pr_err("%s: error during firmware upload part2\n", - DRIVER_NAME); - goto error; - } - - pr_info("%s: firmware: %s loaded with success\n", - DRIVER_NAME, fw2); -error: - kfree(cmd_buf); - release_firmware(firmware); - - return errno; -} diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h deleted file mode 100644 index 4bfc6849d95a..000000000000 --- a/drivers/staging/media/as102/as102_fw.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 MAX_FW_PKT_SIZE 64 - -extern int dual_tuner; - -struct as10x_raw_fw_pkt { - unsigned char address[4]; - unsigned char data[MAX_FW_PKT_SIZE - 6]; -} __packed; - -struct as10x_fw_pkt_t { - union { - unsigned char request[2]; - unsigned char length[2]; - } __packed u; - struct as10x_raw_fw_pkt raw; -} __packed; - -#ifdef __KERNEL__ -int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap); -#endif diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c deleted file mode 100644 index 86f83b9b1118..000000000000 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 -#include - -#include "as102_drv.h" -#include "as102_usb_drv.h" -#include "as102_fw.h" - -static void as102_usb_disconnect(struct usb_interface *interface); -static int as102_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id); - -static int as102_usb_start_stream(struct as102_dev_t *dev); -static void as102_usb_stop_stream(struct as102_dev_t *dev); - -static int as102_open(struct inode *inode, struct file *file); -static int as102_release(struct inode *inode, struct file *file); - -static struct usb_device_id as102_usb_id_table[] = { - { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, - { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, - { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, - { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, - { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, - { } /* Terminating entry */ -}; - -/* Note that this table must always have the same number of entries as the - as102_usb_id_table struct */ -static const char * const as102_device_names[] = { - AS102_REFERENCE_DESIGN, - AS102_PCTV_74E, - AS102_ELGATO_EYETV_DTT_NAME, - AS102_NBOX_DVBT_DONGLE_NAME, - AS102_SKY_IT_DIGITAL_KEY_NAME, - NULL /* Terminating entry */ -}; - -/* eLNA configuration: devices built on the reference design work best - with 0xA0, while custom designs seem to require 0xC0 */ -static uint8_t const as102_elna_cfg[] = { - 0xA0, - 0xC0, - 0xC0, - 0xA0, - 0xA0, - 0x00 /* Terminating entry */ -}; - -struct usb_driver as102_usb_driver = { - .name = DRIVER_FULL_NAME, - .probe = as102_usb_probe, - .disconnect = as102_usb_disconnect, - .id_table = as102_usb_id_table -}; - -static const struct file_operations as102_dev_fops = { - .owner = THIS_MODULE, - .open = as102_open, - .release = as102_release, -}; - -static struct usb_class_driver as102_usb_class_driver = { - .name = "aton2-%d", - .fops = &as102_dev_fops, - .minor_base = AS102_DEVICE_MAJOR, -}; - -static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, - unsigned char *send_buf, int send_buf_len, - unsigned char *recv_buf, int recv_buf_len) -{ - int ret = 0; - - if (send_buf != NULL) { - ret = usb_control_msg(bus_adap->usb_dev, - usb_sndctrlpipe(bus_adap->usb_dev, 0), - AS102_USB_DEVICE_TX_CTRL_CMD, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, - bus_adap->cmd_xid, /* value */ - 0, /* index */ - send_buf, send_buf_len, - USB_CTRL_SET_TIMEOUT /* 200 */); - if (ret < 0) { - dev_dbg(&bus_adap->usb_dev->dev, - "usb_control_msg(send) failed, err %i\n", ret); - return ret; - } - - if (ret != send_buf_len) { - dev_dbg(&bus_adap->usb_dev->dev, - "only wrote %d of %d bytes\n", ret, send_buf_len); - return -1; - } - } - - if (recv_buf != NULL) { -#ifdef TRACE - dev_dbg(bus_adap->usb_dev->dev, - "want to read: %d bytes\n", recv_buf_len); -#endif - ret = usb_control_msg(bus_adap->usb_dev, - usb_rcvctrlpipe(bus_adap->usb_dev, 0), - AS102_USB_DEVICE_RX_CTRL_CMD, - USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, - bus_adap->cmd_xid, /* value */ - 0, /* index */ - recv_buf, recv_buf_len, - USB_CTRL_GET_TIMEOUT /* 200 */); - if (ret < 0) { - dev_dbg(&bus_adap->usb_dev->dev, - "usb_control_msg(recv) failed, err %i\n", ret); - return ret; - } -#ifdef TRACE - dev_dbg(bus_adap->usb_dev->dev, - "read %d bytes\n", recv_buf_len); -#endif - } - - return ret; -} - -static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, - unsigned char *send_buf, - int send_buf_len, - int swap32) -{ - int ret = 0, actual_len; - - ret = usb_bulk_msg(bus_adap->usb_dev, - usb_sndbulkpipe(bus_adap->usb_dev, 1), - send_buf, send_buf_len, &actual_len, 200); - if (ret) { - dev_dbg(&bus_adap->usb_dev->dev, - "usb_bulk_msg(send) failed, err %i\n", ret); - return ret; - } - - if (actual_len != send_buf_len) { - dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", - actual_len, send_buf_len); - return -1; - } - return ret ? ret : actual_len; -} - -static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, - unsigned char *recv_buf, int recv_buf_len) -{ - int ret = 0, actual_len; - - if (recv_buf == NULL) - return -EINVAL; - - ret = usb_bulk_msg(bus_adap->usb_dev, - usb_rcvbulkpipe(bus_adap->usb_dev, 2), - recv_buf, recv_buf_len, &actual_len, 200); - if (ret) { - dev_dbg(&bus_adap->usb_dev->dev, - "usb_bulk_msg(recv) failed, err %i\n", ret); - return ret; - } - - if (actual_len != recv_buf_len) { - dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", - actual_len, recv_buf_len); - return -1; - } - return ret ? ret : actual_len; -} - -static struct as102_priv_ops_t as102_priv_ops = { - .upload_fw_pkt = as102_send_ep1, - .xfer_cmd = as102_usb_xfer_cmd, - .as102_read_ep2 = as102_read_ep2, - .start_stream = as102_usb_start_stream, - .stop_stream = as102_usb_stop_stream, -}; - -static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) -{ - int err; - - usb_fill_bulk_urb(urb, - dev->bus_adap.usb_dev, - usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), - urb->transfer_buffer, - AS102_USB_BUF_SIZE, - as102_urb_stream_irq, - dev); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) - dev_dbg(&urb->dev->dev, - "%s: usb_submit_urb failed\n", __func__); - - return err; -} - -void as102_urb_stream_irq(struct urb *urb) -{ - struct as102_dev_t *as102_dev = urb->context; - - if (urb->actual_length > 0) { - dvb_dmx_swfilter(&as102_dev->dvb_dmx, - urb->transfer_buffer, - urb->actual_length); - } else { - if (urb->actual_length == 0) - memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); - } - - /* is not stopped, re-submit urb */ - if (as102_dev->streaming) - as102_submit_urb_stream(as102_dev, urb); -} - -static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) -{ - int i; - - for (i = 0; i < MAX_STREAM_URB; i++) - usb_free_urb(dev->stream_urb[i]); - - usb_free_coherent(dev->bus_adap.usb_dev, - MAX_STREAM_URB * AS102_USB_BUF_SIZE, - dev->stream, - dev->dma_addr); -} - -static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) -{ - int i; - - dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, - MAX_STREAM_URB * AS102_USB_BUF_SIZE, - GFP_KERNEL, - &dev->dma_addr); - if (!dev->stream) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "%s: usb_buffer_alloc failed\n", __func__); - return -ENOMEM; - } - - memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); - - /* init urb buffers */ - for (i = 0; i < MAX_STREAM_URB; i++) { - struct urb *urb; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (urb == NULL) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "%s: usb_alloc_urb failed\n", __func__); - as102_free_usb_stream_buffer(dev); - return -ENOMEM; - } - - urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); - urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer_length = AS102_USB_BUF_SIZE; - - dev->stream_urb[i] = urb; - } - return 0; -} - -static void as102_usb_stop_stream(struct as102_dev_t *dev) -{ - int i; - - for (i = 0; i < MAX_STREAM_URB; i++) - usb_kill_urb(dev->stream_urb[i]); -} - -static int as102_usb_start_stream(struct as102_dev_t *dev) -{ - int i, ret = 0; - - for (i = 0; i < MAX_STREAM_URB; i++) { - ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); - if (ret) { - as102_usb_stop_stream(dev); - return ret; - } - } - - return 0; -} - -static void as102_usb_release(struct kref *kref) -{ - struct as102_dev_t *as102_dev; - - as102_dev = container_of(kref, struct as102_dev_t, kref); - if (as102_dev != NULL) { - usb_put_dev(as102_dev->bus_adap.usb_dev); - kfree(as102_dev); - } -} - -static void as102_usb_disconnect(struct usb_interface *intf) -{ - struct as102_dev_t *as102_dev; - - /* extract as102_dev_t from usb_device private data */ - as102_dev = usb_get_intfdata(intf); - - /* unregister dvb layer */ - as102_dvb_unregister(as102_dev); - - /* free usb buffers */ - as102_free_usb_stream_buffer(as102_dev); - - usb_set_intfdata(intf, NULL); - - /* usb unregister device */ - usb_deregister_dev(intf, &as102_usb_class_driver); - - /* decrement usage counter */ - kref_put(&as102_dev->kref, as102_usb_release); - - pr_info("%s: device has been disconnected\n", DRIVER_NAME); -} - -static int as102_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - struct as102_dev_t *as102_dev; - int i; - - /* This should never actually happen */ - if (ARRAY_SIZE(as102_usb_id_table) != - (sizeof(as102_device_names) / sizeof(const char *))) { - pr_err("Device names table invalid size"); - return -EINVAL; - } - - as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); - if (as102_dev == NULL) - return -ENOMEM; - - /* Assign the user-friendly device name */ - for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) { - if (id == &as102_usb_id_table[i]) { - as102_dev->name = as102_device_names[i]; - as102_dev->elna_cfg = as102_elna_cfg[i]; - } - } - - if (as102_dev->name == NULL) - as102_dev->name = "Unknown AS102 device"; - - /* set private callback functions */ - as102_dev->bus_adap.ops = &as102_priv_ops; - - /* init cmd token for usb bus */ - as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; - as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; - - /* init kernel device reference */ - kref_init(&as102_dev->kref); - - /* store as102 device to usb_device private data */ - usb_set_intfdata(intf, (void *) as102_dev); - - /* store in as102 device the usb_device pointer */ - as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); - - /* we can register the device now, as it is ready */ - ret = usb_register_dev(intf, &as102_usb_class_driver); - if (ret < 0) { - /* something prevented us from registering this driver */ - dev_err(&intf->dev, - "%s: usb_register_dev() failed (errno = %d)\n", - __func__, ret); - goto failed; - } - - pr_info("%s: device has been detected\n", DRIVER_NAME); - - /* request buffer allocation for streaming */ - ret = as102_alloc_usb_stream_buffer(as102_dev); - if (ret != 0) - goto failed_stream; - - /* register dvb layer */ - ret = as102_dvb_register(as102_dev); - if (ret != 0) - goto failed_dvb; - - return ret; - -failed_dvb: - as102_free_usb_stream_buffer(as102_dev); -failed_stream: - usb_deregister_dev(intf, &as102_usb_class_driver); -failed: - usb_put_dev(as102_dev->bus_adap.usb_dev); - usb_set_intfdata(intf, NULL); - kfree(as102_dev); - return ret; -} - -static int as102_open(struct inode *inode, struct file *file) -{ - int ret = 0, minor = 0; - struct usb_interface *intf = NULL; - struct as102_dev_t *dev = NULL; - - /* read minor from inode */ - minor = iminor(inode); - - /* fetch device from usb interface */ - intf = usb_find_interface(&as102_usb_driver, minor); - if (intf == NULL) { - pr_err("%s: can't find device for minor %d\n", - __func__, minor); - ret = -ENODEV; - goto exit; - } - - /* get our device */ - dev = usb_get_intfdata(intf); - if (dev == NULL) { - ret = -EFAULT; - goto exit; - } - - /* save our device object in the file's private structure */ - file->private_data = dev; - - /* increment our usage count for the device */ - kref_get(&dev->kref); - -exit: - return ret; -} - -static int as102_release(struct inode *inode, struct file *file) -{ - struct as102_dev_t *dev = NULL; - - dev = file->private_data; - if (dev != NULL) { - /* decrement the count on our device */ - kref_put(&dev->kref, as102_usb_release); - } - - return 0; -} - -MODULE_DEVICE_TABLE(usb, as102_usb_id_table); diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h deleted file mode 100644 index 1ad1ec52b11e..000000000000 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 _AS102_USB_DRV_H_ -#define _AS102_USB_DRV_H_ - -#define AS102_USB_DEVICE_TX_CTRL_CMD 0xF1 -#define AS102_USB_DEVICE_RX_CTRL_CMD 0xF2 - -/* define these values to match the supported devices */ - -/* Abilis system: "TITAN" */ -#define AS102_REFERENCE_DESIGN "Abilis Systems DVB-Titan" -#define AS102_USB_DEVICE_VENDOR_ID 0x1BA6 -#define AS102_USB_DEVICE_PID_0001 0x0001 - -/* PCTV Systems: PCTV picoStick (74e) */ -#define AS102_PCTV_74E "PCTV Systems picoStick (74e)" -#define PCTV_74E_USB_VID 0x2013 -#define PCTV_74E_USB_PID 0x0246 - -/* Elgato: EyeTV DTT Deluxe */ -#define AS102_ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" -#define ELGATO_EYETV_DTT_USB_VID 0x0fd9 -#define ELGATO_EYETV_DTT_USB_PID 0x002c - -/* nBox: nBox DVB-T Dongle */ -#define AS102_NBOX_DVBT_DONGLE_NAME "nBox DVB-T Dongle" -#define NBOX_DVBT_DONGLE_USB_VID 0x0b89 -#define NBOX_DVBT_DONGLE_USB_PID 0x0007 - -/* Sky Italia: Digital Key (green led) */ -#define AS102_SKY_IT_DIGITAL_KEY_NAME "Sky IT Digital Key (green led)" -#define SKY_IT_DIGITAL_KEY_USB_VID 0x2137 -#define SKY_IT_DIGITAL_KEY_USB_PID 0x0001 - -void as102_urb_stream_irq(struct urb *urb); - -struct as10x_usb_token_cmd_t { - /* token cmd */ - struct as10x_cmd_t c; - /* token response */ - struct as10x_cmd_t r; -}; -#endif diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c deleted file mode 100644 index 9e49f15a7c9f..000000000000 --- a/drivers/staging/media/as102/as10x_cmd.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 "as102_drv.h" -#include "as10x_types.h" -#include "as10x_cmd.h" - -/** - * as10x_cmd_turn_on - send turn on command to AS10x - * @adap: pointer to AS10x bus adapter - * - * Return 0 when no error, < 0 in case of error. - */ -int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.turn_on.req)); - - /* fill command */ - pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.turn_on.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.turn_on.rsp) + - HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); - -out: - return error; -} - -/** - * as10x_cmd_turn_off - send turn off command to AS10x - * @adap: pointer to AS10x bus adapter - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.turn_off.req)); - - /* fill command */ - pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd( - adap, (uint8_t *) pcmd, - sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); - -out: - return error; -} - -/** - * as10x_cmd_set_tune - send set tune command to AS10x - * @adap: pointer to AS10x bus adapter - * @ptune: tune parameters - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, - struct as10x_tune_args *ptune) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *preq, *prsp; - - preq = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(preq, (++adap->cmd_xid), - sizeof(preq->body.set_tune.req)); - - /* fill command */ - preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); - preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); - preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; - preq->body.set_tune.req.args.hier_select = ptune->hier_select; - preq->body.set_tune.req.args.modulation = ptune->modulation; - preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; - preq->body.set_tune.req.args.interleaving_mode = - ptune->interleaving_mode; - preq->body.set_tune.req.args.code_rate = ptune->code_rate; - preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; - preq->body.set_tune.req.args.transmission_mode = - ptune->transmission_mode; - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) preq, - sizeof(preq->body.set_tune.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.set_tune.rsp) - + HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); - -out: - return error; -} - -/** - * as10x_cmd_get_tune_status - send get tune status command to AS10x - * @adap: pointer to AS10x bus adapter - * @pstatus: pointer to updated status structure of the current tune - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, - struct as10x_tune_status *pstatus) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *preq, *prsp; - - preq = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(preq, (++adap->cmd_xid), - sizeof(preq->body.get_tune_status.req)); - - /* fill command */ - preq->body.get_tune_status.req.proc_id = - cpu_to_le16(CONTROL_PROC_GETTUNESTAT); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd( - adap, - (uint8_t *) preq, - sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); - if (error < 0) - goto out; - - /* Response OK -> get response data */ - pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; - pstatus->signal_strength = - le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); - pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); - pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); - -out: - return error; -} - -/** - * as10x_cmd_get_tps - send get TPS command to AS10x - * @adap: pointer to AS10x handle - * @ptps: pointer to TPS parameters structure - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.get_tps.req)); - - /* fill command */ - pcmd->body.get_tune_status.req.proc_id = - cpu_to_le16(CONTROL_PROC_GETTPS); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_tps.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_tps.rsp) + - HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); - if (error < 0) - goto out; - - /* Response OK -> get response data */ - ptps->modulation = prsp->body.get_tps.rsp.tps.modulation; - ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; - ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; - ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; - ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; - ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; - ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; - ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; - ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; - ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); - -out: - return error; -} - -/** - * as10x_cmd_get_demod_stats - send get demod stats command to AS10x - * @adap: pointer to AS10x bus adapter - * @pdemod_stats: pointer to demod stats parameters structure - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, - struct as10x_demod_stats *pdemod_stats) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.get_demod_stats.req)); - - /* fill command */ - pcmd->body.get_demod_stats.req.proc_id = - cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_demod_stats.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_demod_stats.rsp) - + HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP); - if (error < 0) - goto out; - - /* Response OK -> get response data */ - pdemod_stats->frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); - pdemod_stats->bad_frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); - pdemod_stats->bytes_fixed_by_rs = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); - pdemod_stats->mer = - le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); - pdemod_stats->has_started = - prsp->body.get_demod_stats.rsp.stats.has_started; - -out: - return error; -} - -/** - * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x - * @adap: pointer to AS10x bus adapter - * @is_ready: pointer to value indicating when impulse - * response data is ready - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, - uint8_t *is_ready) -{ - int error = AS10X_CMD_ERROR; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.get_impulse_rsp.req)); - - /* fill command */ - pcmd->body.get_impulse_rsp.req.proc_id = - cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_impulse_rsp.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_impulse_rsp.rsp) - + HEADER_SIZE); - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP); - if (error < 0) - goto out; - - /* Response OK -> get response data */ - *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; - -out: - return error; -} - -/** - * as10x_cmd_build - build AS10x command header - * @pcmd: pointer to AS10x command buffer - * @xid: sequence id of the command - * @cmd_len: length of the command - */ -void as10x_cmd_build(struct as10x_cmd_t *pcmd, - uint16_t xid, uint16_t cmd_len) -{ - pcmd->header.req_id = cpu_to_le16(xid); - pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); - pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); - pcmd->header.data_len = cpu_to_le16(cmd_len); -} - -/** - * as10x_rsp_parse - Parse command response - * @prsp: pointer to AS10x command buffer - * @proc_id: id of the command - * - * Return 0 on success or negative value in case of error. - */ -int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) -{ - int error; - - /* extract command error code */ - error = prsp->body.common.rsp.error; - - if ((error == 0) && - (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { - return 0; - } - - return AS10X_CMD_ERROR; -} diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h deleted file mode 100644 index e21ec6c702a9..000000000000 --- a/drivers/staging/media/as102/as10x_cmd.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 _AS10X_CMD_H_ -#define _AS10X_CMD_H_ - -#ifdef __KERNEL__ -#include -#endif - -#include "as10x_types.h" - -/*********************************/ -/* MACRO DEFINITIONS */ -/*********************************/ -#define AS10X_CMD_ERROR -1 - -#define SERVICE_PROG_ID 0x0002 -#define SERVICE_PROG_VERSION 0x0001 - -#define HIER_NONE 0x00 -#define HIER_LOW_PRIORITY 0x01 - -#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) - -/* context request types */ -#define GET_CONTEXT_DATA 1 -#define SET_CONTEXT_DATA 2 - -/* ODSP suspend modes */ -#define CFG_MODE_ODSP_RESUME 0 -#define CFG_MODE_ODSP_SUSPEND 1 - -/* Dump memory size */ -#define DUMP_BLOCK_SIZE_MAX 0x20 - -/*********************************/ -/* TYPE DEFINITION */ -/*********************************/ -enum control_proc { - CONTROL_PROC_TURNON = 0x0001, - CONTROL_PROC_TURNON_RSP = 0x0100, - CONTROL_PROC_SET_REGISTER = 0x0002, - CONTROL_PROC_SET_REGISTER_RSP = 0x0200, - CONTROL_PROC_GET_REGISTER = 0x0003, - CONTROL_PROC_GET_REGISTER_RSP = 0x0300, - CONTROL_PROC_SETTUNE = 0x000A, - CONTROL_PROC_SETTUNE_RSP = 0x0A00, - CONTROL_PROC_GETTUNESTAT = 0x000B, - CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, - CONTROL_PROC_GETTPS = 0x000D, - CONTROL_PROC_GETTPS_RSP = 0x0D00, - CONTROL_PROC_SETFILTER = 0x000E, - CONTROL_PROC_SETFILTER_RSP = 0x0E00, - CONTROL_PROC_REMOVEFILTER = 0x000F, - CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, - CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, - CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, - CONTROL_PROC_START_STREAMING = 0x0013, - CONTROL_PROC_START_STREAMING_RSP = 0x1300, - CONTROL_PROC_STOP_STREAMING = 0x0014, - CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, - CONTROL_PROC_GET_DEMOD_STATS = 0x0015, - CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, - CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, - CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, - CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, - CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, - CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, - CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, - - CONTROL_PROC_CONTEXT = 0x00FC, - CONTROL_PROC_CONTEXT_RSP = 0xFC00, - CONTROL_PROC_DUMP_MEMORY = 0x00FD, - CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, - CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, - CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, - CONTROL_PROC_TURNOFF = 0x00FF, - CONTROL_PROC_TURNOFF_RSP = 0xFF00 -}; - -union as10x_turn_on { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_turn_off { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t err; - } __packed rsp; -} __packed; - -union as10x_set_tune { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* tune params */ - struct as10x_tune_args args; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_get_tune_status { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tune status */ - struct as10x_tune_status sts; - } __packed rsp; -} __packed; - -union as10x_get_tps { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tps details */ - struct as10x_tps tps; - } __packed rsp; -} __packed; - -union as10x_common { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_add_pid_filter { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to filter */ - uint16_t pid; - /* stream type (MPE, PSI/SI or PES )*/ - uint8_t stream_type; - /* PID index in filter table */ - uint8_t idx; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* Filter id */ - uint8_t filter_id; - } __packed rsp; -} __packed; - -union as10x_del_pid_filter { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to remove */ - uint16_t pid; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_start_streaming { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_stop_streaming { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_get_demod_stats { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* demod stats */ - struct as10x_demod_stats stats; - } __packed rsp; -} __packed; - -union as10x_get_impulse_resp { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* impulse response ready */ - uint8_t is_ready; - } __packed rsp; -} __packed; - -union as10x_fw_context { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* value to write (for set context)*/ - struct as10x_register_value reg_val; - /* context tag */ - uint16_t tag; - /* context request type */ - uint16_t type; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* value read (for get context) */ - struct as10x_register_value reg_val; - /* context request type */ - uint16_t type; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_set_register { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - /* register content */ - struct as10x_register_value reg_val; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -union as10x_get_register { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* register content */ - struct as10x_register_value reg_val; - } __packed rsp; -} __packed; - -union as10x_cfg_change_mode { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* mode */ - uint8_t mode; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } __packed rsp; -} __packed; - -struct as10x_cmd_header_t { - uint16_t req_id; - uint16_t prog; - uint16_t version; - uint16_t data_len; -} __packed; - -#define DUMP_BLOCK_SIZE 16 - -union as10x_dump_memory { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - /* register description */ - struct as10x_register_addr reg_addr; - /* nb blocks to read */ - uint16_t num_blocks; - } __packed req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* data */ - union { - uint8_t data8[DUMP_BLOCK_SIZE]; - uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; - uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; - } __packed u; - } __packed rsp; -} __packed; - -union as10x_dumplog_memory { - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - } __packed req; - struct { - /* request identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* dump data */ - uint8_t data[DUMP_BLOCK_SIZE]; - } __packed rsp; -} __packed; - -union as10x_raw_data { - /* request */ - struct { - uint16_t proc_id; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) - - 2 /* proc_id */]; - } __packed req; - /* response */ - struct { - uint16_t proc_id; - uint8_t error; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) - - 2 /* proc_id */ - 1 /* rc */]; - } __packed rsp; -} __packed; - -struct as10x_cmd_t { - struct as10x_cmd_header_t header; - union { - union as10x_turn_on turn_on; - union as10x_turn_off turn_off; - union as10x_set_tune set_tune; - union as10x_get_tune_status get_tune_status; - union as10x_get_tps get_tps; - union as10x_common common; - union as10x_add_pid_filter add_pid_filter; - union as10x_del_pid_filter del_pid_filter; - union as10x_start_streaming start_streaming; - union as10x_stop_streaming stop_streaming; - union as10x_get_demod_stats get_demod_stats; - union as10x_get_impulse_resp get_impulse_rsp; - union as10x_fw_context context; - union as10x_set_register set_register; - union as10x_get_register get_register; - union as10x_cfg_change_mode cfg_change_mode; - union as10x_dump_memory dump_memory; - union as10x_dumplog_memory dumplog_memory; - union as10x_raw_data raw_data; - } __packed body; -} __packed; - -struct as10x_token_cmd_t { - /* token cmd */ - struct as10x_cmd_t c; - /* token response */ - struct as10x_cmd_t r; -} __packed; - - -/**************************/ -/* FUNCTION DECLARATION */ -/**************************/ - -void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, - uint16_t cmd_len); -int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); - -/* as10x cmd */ -int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap); -int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap); - -int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, - struct as10x_tune_args *ptune); - -int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, - struct as10x_tune_status *pstatus); - -int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, - struct as10x_tps *ptps); - -int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, - struct as10x_demod_stats *pdemod_stats); - -int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, - uint8_t *is_ready); - -/* as10x cmd stream */ -int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, - struct as10x_ts_filter *filter); -int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, - uint16_t pid_value); - -int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap); -int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap); - -/* as10x cmd cfg */ -int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, - uint16_t tag, - uint32_t value); -int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, - uint16_t tag, - uint32_t *pvalue); - -int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode); -int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); -#endif diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c deleted file mode 100644 index b1e300d88753..000000000000 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 "as102_drv.h" -#include "as10x_types.h" -#include "as10x_cmd.h" - -/***************************/ -/* FUNCTION DEFINITION */ -/***************************/ - -/** - * as10x_cmd_get_context - Send get context command to AS10x - * @adap: pointer to AS10x bus adapter - * @tag: context tag - * @pvalue: pointer where to store context value read - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, - uint32_t *pvalue) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.context.req)); - - /* fill command */ - pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); - pcmd->body.context.req.tag = cpu_to_le16(tag); - pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response: context command do not follow the common response */ - /* structure -> specific handling response parse required */ - error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); - - if (error == 0) { - /* Response OK -> get response data */ - *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); - /* value returned is always a 32-bit value */ - } - -out: - return error; -} - -/** - * as10x_cmd_set_context - send set context command to AS10x - * @adap: pointer to AS10x bus adapter - * @tag: context tag - * @value: value to set in context - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, - uint32_t value) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.context.req)); - - /* fill command */ - pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); - /* pcmd->body.context.req.reg_val.mode initialization is not required */ - pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); - pcmd->body.context.req.tag = cpu_to_le16(tag); - pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response: context command do not follow the common response */ - /* structure -> specific handling response parse required */ - error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); - -out: - return error; -} - -/** - * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x - * @adap: pointer to AS10x bus adapter - * @mode: mode selected: - * - ON : 0x0 => eLNA always ON - * - OFF : 0x1 => eLNA always OFF - * - AUTO : 0x2 => eLNA follow hysteresis parameters - * to be ON or OFF - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.cfg_change_mode.req)); - - /* fill command */ - pcmd->body.cfg_change_mode.req.proc_id = - cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); - pcmd->body.cfg_change_mode.req.mode = mode; - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.cfg_change_mode.req) - + HEADER_SIZE, (uint8_t *) prsp, - sizeof(prsp->body.cfg_change_mode.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); - -out: - return error; -} - -/** - * as10x_context_rsp_parse - Parse context command response - * @prsp: pointer to AS10x command response buffer - * @proc_id: id of the command - * - * Since the contex command response does not follow the common - * response, a specific parse function is required. - * Return 0 on success or negative value in case of error. - */ -int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) -{ - int err; - - err = prsp->body.context.rsp.error; - - if ((err == 0) && - (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { - return 0; - } - return AS10X_CMD_ERROR; -} diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c deleted file mode 100644 index 1088ca1fe92f..000000000000 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 "as102_drv.h" -#include "as10x_cmd.h" - -/** - * as10x_cmd_add_PID_filter - send add filter command to AS10x - * @adap: pointer to AS10x bus adapter - * @filter: TSFilter filter for DVB-T - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, - struct as10x_ts_filter *filter) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.add_pid_filter.req)); - - /* fill command */ - pcmd->body.add_pid_filter.req.proc_id = - cpu_to_le16(CONTROL_PROC_SETFILTER); - pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); - pcmd->body.add_pid_filter.req.stream_type = filter->type; - - if (filter->idx < 16) - pcmd->body.add_pid_filter.req.idx = filter->idx; - else - pcmd->body.add_pid_filter.req.idx = 0xFF; - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.add_pid_filter.req) - + HEADER_SIZE, (uint8_t *) prsp, - sizeof(prsp->body.add_pid_filter.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); - - if (error == 0) { - /* Response OK -> get response data */ - filter->idx = prsp->body.add_pid_filter.rsp.filter_id; - } - -out: - return error; -} - -/** - * as10x_cmd_del_PID_filter - Send delete filter command to AS10x - * @adap: pointer to AS10x bus adapte - * @pid_value: PID to delete - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, - uint16_t pid_value) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.del_pid_filter.req)); - - /* fill command */ - pcmd->body.del_pid_filter.req.proc_id = - cpu_to_le16(CONTROL_PROC_REMOVEFILTER); - pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.del_pid_filter.req) - + HEADER_SIZE, (uint8_t *) prsp, - sizeof(prsp->body.del_pid_filter.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); - -out: - return error; -} - -/** - * as10x_cmd_start_streaming - Send start streaming command to AS10x - * @adap: pointer to AS10x bus adapter - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap) -{ - int error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.start_streaming.req)); - - /* fill command */ - pcmd->body.start_streaming.req.proc_id = - cpu_to_le16(CONTROL_PROC_START_STREAMING); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.start_streaming.req) - + HEADER_SIZE, (uint8_t *) prsp, - sizeof(prsp->body.start_streaming.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); - -out: - return error; -} - -/** - * as10x_cmd_stop_streaming - Send stop streaming command to AS10x - * @adap: pointer to AS10x bus adapter - * - * Return 0 on success or negative value in case of error. - */ -int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap) -{ - int8_t error; - struct as10x_cmd_t *pcmd, *prsp; - - pcmd = adap->cmd; - prsp = adap->rsp; - - /* prepare command */ - as10x_cmd_build(pcmd, (++adap->cmd_xid), - sizeof(pcmd->body.stop_streaming.req)); - - /* fill command */ - pcmd->body.stop_streaming.req.proc_id = - cpu_to_le16(CONTROL_PROC_STOP_STREAMING); - - /* send command */ - if (adap->ops->xfer_cmd) { - error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, - sizeof(pcmd->body.stop_streaming.req) - + HEADER_SIZE, (uint8_t *) prsp, - sizeof(prsp->body.stop_streaming.rsp) - + HEADER_SIZE); - } else { - error = AS10X_CMD_ERROR; - } - - if (error < 0) - goto out; - - /* parse response */ - error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); - -out: - return error; -} diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h deleted file mode 100644 index 5638b191b780..000000000000 --- a/drivers/staging/media/as102/as10x_handle.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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. - */ -#ifdef __KERNEL__ -struct as10x_bus_adapter_t; -struct as102_dev_t; - -#include "as10x_cmd.h" - -/* values for "mode" field */ -#define REGMODE8 8 -#define REGMODE16 16 -#define REGMODE32 32 - -struct as102_priv_ops_t { - int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap, - unsigned char *buf, int buflen, int swap32); - - int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap, - unsigned char *buf, int buflen); - - int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap, - unsigned char *send_buf, int send_buf_len, - unsigned char *recv_buf, int recv_buf_len); - - int (*start_stream)(struct as102_dev_t *dev); - void (*stop_stream)(struct as102_dev_t *dev); - - int (*reset_target)(struct as10x_bus_adapter_t *bus_adap); - - int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode, - uint32_t rd_addr, uint16_t rd_len, - uint32_t wr_addr, uint16_t wr_len); - - int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap, - unsigned char *recv_buf, - int recv_buf_len); -}; -#endif diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h deleted file mode 100644 index af26e057d9a2..000000000000 --- a/drivers/staging/media/as102/as10x_types.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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 _AS10X_TYPES_H_ -#define _AS10X_TYPES_H_ - -#include "as10x_handle.h" - -/*********************************/ -/* MACRO DEFINITIONS */ -/*********************************/ - -/* bandwidth constant values */ -#define BW_5_MHZ 0x00 -#define BW_6_MHZ 0x01 -#define BW_7_MHZ 0x02 -#define BW_8_MHZ 0x03 - -/* hierarchy priority selection values */ -#define HIER_NO_PRIORITY 0x00 -#define HIER_LOW_PRIORITY 0x01 -#define HIER_HIGH_PRIORITY 0x02 - -/* constellation available values */ -#define CONST_QPSK 0x00 -#define CONST_QAM16 0x01 -#define CONST_QAM64 0x02 -#define CONST_UNKNOWN 0xFF - -/* hierarchy available values */ -#define HIER_NONE 0x00 -#define HIER_ALPHA_1 0x01 -#define HIER_ALPHA_2 0x02 -#define HIER_ALPHA_4 0x03 -#define HIER_UNKNOWN 0xFF - -/* interleaving available values */ -#define INTLV_NATIVE 0x00 -#define INTLV_IN_DEPTH 0x01 -#define INTLV_UNKNOWN 0xFF - -/* code rate available values */ -#define CODE_RATE_1_2 0x00 -#define CODE_RATE_2_3 0x01 -#define CODE_RATE_3_4 0x02 -#define CODE_RATE_5_6 0x03 -#define CODE_RATE_7_8 0x04 -#define CODE_RATE_UNKNOWN 0xFF - -/* guard interval available values */ -#define GUARD_INT_1_32 0x00 -#define GUARD_INT_1_16 0x01 -#define GUARD_INT_1_8 0x02 -#define GUARD_INT_1_4 0x03 -#define GUARD_UNKNOWN 0xFF - -/* transmission mode available values */ -#define TRANS_MODE_2K 0x00 -#define TRANS_MODE_8K 0x01 -#define TRANS_MODE_4K 0x02 -#define TRANS_MODE_UNKNOWN 0xFF - -/* DVBH signalling available values */ -#define TIMESLICING_PRESENT 0x01 -#define MPE_FEC_PRESENT 0x02 - -/* tune state available */ -#define TUNE_STATUS_NOT_TUNED 0x00 -#define TUNE_STATUS_IDLE 0x01 -#define TUNE_STATUS_LOCKING 0x02 -#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 -#define TUNE_STATUS_STREAM_DETECTED 0x04 -#define TUNE_STATUS_STREAM_TUNED 0x05 -#define TUNE_STATUS_ERROR 0xFF - -/* available TS FID filter types */ -#define TS_PID_TYPE_TS 0 -#define TS_PID_TYPE_PSI_SI 1 -#define TS_PID_TYPE_MPE 2 - -/* number of echos available */ -#define MAX_ECHOS 15 - -/* Context types */ -#define CONTEXT_LNA 1010 -#define CONTEXT_ELNA_HYSTERESIS 4003 -#define CONTEXT_ELNA_GAIN 4004 -#define CONTEXT_MER_THRESHOLD 5005 -#define CONTEXT_MER_OFFSET 5006 -#define CONTEXT_IR_STATE 7000 -#define CONTEXT_TSOUT_MSB_FIRST 7004 -#define CONTEXT_TSOUT_FALLING_EDGE 7005 - -/* Configuration modes */ -#define CFG_MODE_ON 0 -#define CFG_MODE_OFF 1 -#define CFG_MODE_AUTO 2 - -struct as10x_tps { - uint8_t modulation; - uint8_t hierarchy; - uint8_t interleaving_mode; - uint8_t code_rate_HP; - uint8_t code_rate_LP; - uint8_t guard_interval; - uint8_t transmission_mode; - uint8_t DVBH_mask_HP; - uint8_t DVBH_mask_LP; - uint16_t cell_ID; -} __packed; - -struct as10x_tune_args { - /* frequency */ - uint32_t freq; - /* bandwidth */ - uint8_t bandwidth; - /* hierarchy selection */ - uint8_t hier_select; - /* constellation */ - uint8_t modulation; - /* hierarchy */ - uint8_t hierarchy; - /* interleaving mode */ - uint8_t interleaving_mode; - /* code rate */ - uint8_t code_rate; - /* guard interval */ - uint8_t guard_interval; - /* transmission mode */ - uint8_t transmission_mode; -} __packed; - -struct as10x_tune_status { - /* tune status */ - uint8_t tune_state; - /* signal strength */ - int16_t signal_strength; - /* packet error rate 10^-4 */ - uint16_t PER; - /* bit error rate 10^-4 */ - uint16_t BER; -} __packed; - -struct as10x_demod_stats { - /* frame counter */ - uint32_t frame_count; - /* Bad frame counter */ - uint32_t bad_frame_count; - /* Number of wrong bytes fixed by Reed-Solomon */ - uint32_t bytes_fixed_by_rs; - /* Averaged MER */ - uint16_t mer; - /* statistics calculation state indicator (started or not) */ - uint8_t has_started; -} __packed; - -struct as10x_ts_filter { - uint16_t pid; /* valid PID value 0x00 : 0x2000 */ - uint8_t type; /* Red TS_PID_TYPE_ values */ - uint8_t idx; /* index in filtering table */ -} __packed; - -struct as10x_register_value { - uint8_t mode; - union { - uint8_t value8; /* 8 bit value */ - uint16_t value16; /* 16 bit value */ - uint32_t value32; /* 32 bit value */ - } __packed u; -} __packed; - -struct as10x_register_addr { - /* register addr */ - uint32_t addr; - /* register mode access */ - uint8_t mode; -}; - -#endif -- cgit v1.2.3 From 1f2563d68cce0d45b81a47894c135f65f192b1a9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:16 -0300 Subject: [media] as102: get rid of FSF mail address Make checkpatch happier by removing FSF mail address. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 4 ---- drivers/media/usb/as102/as102_drv.h | 4 ---- drivers/media/usb/as102/as102_fe.c | 4 ---- drivers/media/usb/as102/as102_fw.c | 4 ---- drivers/media/usb/as102/as102_fw.h | 4 ---- drivers/media/usb/as102/as102_usb_drv.c | 4 ---- drivers/media/usb/as102/as102_usb_drv.h | 4 ---- drivers/media/usb/as102/as10x_cmd.c | 4 ---- drivers/media/usb/as102/as10x_cmd.h | 4 ---- drivers/media/usb/as102/as10x_cmd_cfg.c | 4 ---- drivers/media/usb/as102/as10x_cmd_stream.c | 4 ---- drivers/media/usb/as102/as10x_handle.h | 4 ---- drivers/media/usb/as102/as10x_types.h | 4 ---- 13 files changed, 52 deletions(-) diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index e0ee618e607a..d90a6651f03e 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -12,10 +12,6 @@ * 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 diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index 49d0c4259b00..d6e08e23b366 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -11,10 +11,6 @@ * 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 diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 67e55b84493f..29a6d38f91a9 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -12,10 +12,6 @@ * 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 "as102_drv.h" #include "as10x_types.h" diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index f33f752c0aad..07d08c49f4d4 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -12,10 +12,6 @@ * 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 diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h index 4bfc6849d95a..2732b784216d 100644 --- a/drivers/media/usb/as102/as102_fw.h +++ b/drivers/media/usb/as102/as102_fw.h @@ -11,10 +11,6 @@ * 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 MAX_FW_PKT_SIZE 64 diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 86f83b9b1118..43133df771ff 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -12,10 +12,6 @@ * 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 diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h index 1ad1ec52b11e..4fb1baa8cac0 100644 --- a/drivers/media/usb/as102/as102_usb_drv.h +++ b/drivers/media/usb/as102/as102_usb_drv.h @@ -12,10 +12,6 @@ * 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 _AS102_USB_DRV_H_ #define _AS102_USB_DRV_H_ diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c index 9e49f15a7c9f..8868c52500ee 100644 --- a/drivers/media/usb/as102/as10x_cmd.c +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -12,10 +12,6 @@ * 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 diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index e21ec6c702a9..1c9ea2c2175e 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -11,10 +11,6 @@ * 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 _AS10X_CMD_H_ #define _AS10X_CMD_H_ diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c index b1e300d88753..833463343ada 100644 --- a/drivers/media/usb/as102/as10x_cmd_cfg.c +++ b/drivers/media/usb/as102/as10x_cmd_cfg.c @@ -11,10 +11,6 @@ * 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 diff --git a/drivers/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c index 1088ca1fe92f..126aea976639 100644 --- a/drivers/media/usb/as102/as10x_cmd_stream.c +++ b/drivers/media/usb/as102/as10x_cmd_stream.c @@ -11,10 +11,6 @@ * 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 diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h index 5638b191b780..e535fffbcd94 100644 --- a/drivers/media/usb/as102/as10x_handle.h +++ b/drivers/media/usb/as102/as10x_handle.h @@ -11,10 +11,6 @@ * 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. */ #ifdef __KERNEL__ struct as10x_bus_adapter_t; diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h index af26e057d9a2..f82d51e542e3 100644 --- a/drivers/media/usb/as102/as10x_types.h +++ b/drivers/media/usb/as102/as10x_types.h @@ -11,10 +11,6 @@ * 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 _AS10X_TYPES_H_ #define _AS10X_TYPES_H_ -- cgit v1.2.3 From 1d5c2bb1f9ded9af7bb7e4d2b9beeacbfdbc6f2b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:17 -0300 Subject: [media] as102: CodingStyle fixes Fix this warning: WARNING: quoted string split across lines 566: FILE: drivers/media/usb/as102/as102_fe.c:141: + "demod status: fc: 0x%08x, bad fc: 0x%08x, " + "bytes corrected: 0x%08x , MER: 0x%04x\n", Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 29a6d38f91a9..9596756b3869 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -137,8 +137,7 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); } else { dev_dbg(&dev->bus_adap.usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, " - "bytes corrected: 0x%08x , MER: 0x%04x\n", + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", dev->demod_stats.frame_count, dev->demod_stats.bad_frame_count, dev->demod_stats.bytes_fixed_by_rs, -- cgit v1.2.3 From d8eb070b6649c1663204300555fb740affc6cdc2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:18 -0300 Subject: [media] as102: better name the unknown frontend Make the frontend .name more coherent with DVB namespace. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 9596756b3869..041bb80aa4ba 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -245,7 +245,7 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) static struct dvb_frontend_ops as102_fe_ops = { .delsys = { SYS_DVBT }, .info = { - .name = "Unknown AS102 device", + .name = "Abilis AS102 DVB-T", .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, -- cgit v1.2.3 From b601d9a5d668119219d1db95cbe04fdc38eaf5a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:19 -0300 Subject: [media] as102: Move ancillary routines to the beggining Avoid having function prototypes by moving some ancillary routines to the beginning of the file. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 17 +- drivers/media/usb/as102/as102_drv.h | 15 +- drivers/media/usb/as102/as102_fe.c | 542 +++++++++++++++++------------------- 3 files changed, 274 insertions(+), 300 deletions(-) diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index d90a6651f03e..ff5bd2e5657a 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -216,7 +216,17 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) goto edmxdinit; } - ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); + /* Attach the frontend */ + as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name, + &as102_dev->bus_adap, + as102_dev->elna_cfg); + if (!as102_dev->dvb_fe) { + dev_err(dev, "%s: as102_attach() failed: %d", + __func__, ret); + goto efereg; + } + + ret = dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe); if (ret < 0) { dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", __func__, ret); @@ -252,7 +262,10 @@ edmxinit: void as102_dvb_unregister(struct as102_dev_t *as102_dev) { /* unregister as102 frontend */ - as102_dvb_unregister_fe(&as102_dev->dvb_fe); + dvb_unregister_frontend(as102_dev->dvb_fe); + + /* detach frontend */ + dvb_frontend_detach(as102_dev->dvb_fe); /* unregister demux device */ dvb_dmxdev_release(&as102_dev->dvb_dmxdev); diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index d6e08e23b366..1e2a76d3c517 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -60,17 +60,10 @@ struct as102_dev_t { uint8_t elna_cfg; struct dvb_adapter dvb_adap; - struct dvb_frontend dvb_fe; + struct dvb_frontend *dvb_fe; struct dvb_demux dvb_dmx; struct dmxdev dvb_dmxdev; - /* demodulator stats */ - struct as10x_demod_stats demod_stats; - /* signal strength */ - uint16_t signal_strength; - /* bit error rate */ - uint32_t ber; - /* timer handle to trig ts stream download */ struct timer_list timer_handle; @@ -84,5 +77,7 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); -int as102_dvb_unregister_fe(struct dvb_frontend *dev); +/* FIXME: move it to a separate header */ +struct dvb_frontend *as102_attach(const char *name, + struct as10x_bus_adapter_t *bus_adap, + uint8_t elna_cfg); diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 041bb80aa4ba..7ec1c67ba119 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -17,298 +17,19 @@ #include "as10x_types.h" #include "as10x_cmd.h" -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, - struct as10x_tps *src); +struct as102_state { + struct dvb_frontend frontend; + struct as10x_demod_stats demod_stats; + struct as10x_bus_adapter_t *bus_adap; -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, - struct dtv_frontend_properties *src); + uint8_t elna_cfg; -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_args tune_args = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - as102_fe_copy_tune_parameters(&tune_args, p); - - /* send abilis command: SET_TUNE */ - ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); - if (ret != 0) - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_set_tune failed. (err = %d)\n", ret); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tps tps = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -EINVAL; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TPS */ - ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); - - if (ret == 0) - as10x_fe_copy_tps_parameters(p, &tps); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *settings) { - - settings->min_delay_ms = 1000; - - return 0; -} - - -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_status tstate = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TUNE_STATUS */ - ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); - if (ret < 0) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_tune_status failed (err = %d)\n", - ret); - goto out; - } - - dev->signal_strength = tstate.signal_strength; - dev->ber = tstate.BER; - - switch (tstate.tune_state) { - case TUNE_STATUS_SIGNAL_DVB_OK: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - break; - case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; - break; - case TUNE_STATUS_STREAM_TUNED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; - break; - default: - *status = TUNE_STATUS_NOT_TUNED; - } - - dev_dbg(&dev->bus_adap.usb_dev->dev, - "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (*status & FE_HAS_LOCK) { - if (as10x_cmd_get_demod_stats(&dev->bus_adap, - (struct as10x_demod_stats *) &dev->demod_stats) < 0) { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); - } else { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", - dev->demod_stats.frame_count, - dev->demod_stats.bad_frame_count, - dev->demod_stats.bytes_fixed_by_rs, - dev->demod_stats.mer); - } - } else { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - } - -out: - mutex_unlock(&dev->bus_adap.lock); - return ret; -} - -/* - * Note: - * - in AS102 SNR=MER - * - the SNR will be returned in linear terms, i.e. not in dB - * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB - * - the accuracy is >2dB for SNR values outside this range - */ -static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *snr = dev->demod_stats.mer; - - return 0; -} - -static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *ber = dev->ber; - - return 0; -} - -static int as102_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); - - return 0; -} - -static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (dev->demod_stats.has_started) - *ucblocks = dev->demod_stats.bad_frame_count; - else - *ucblocks = 0; - - return 0; -} - -static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct as102_dev_t *dev; - int ret; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - if (acquire) { - if (elna_enable) - as10x_cmd_set_context(&dev->bus_adap, - CONTEXT_LNA, dev->elna_cfg); - - ret = as10x_cmd_turn_on(&dev->bus_adap); - } else { - ret = as10x_cmd_turn_off(&dev->bus_adap); - } - - mutex_unlock(&dev->bus_adap.lock); - - return ret; -} - -static struct dvb_frontend_ops as102_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Abilis AS102 DVB-T", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .set_frontend = as102_fe_set_frontend, - .get_frontend = as102_fe_get_frontend, - .get_tune_settings = as102_fe_get_tune_settings, - - .read_status = as102_fe_read_status, - .read_snr = as102_fe_read_snr, - .read_ber = as102_fe_read_ber, - .read_signal_strength = as102_fe_read_signal_strength, - .read_ucblocks = as102_fe_read_ucblocks, - .ts_bus_ctrl = as102_fe_ts_bus_ctrl, + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; }; -int as102_dvb_unregister_fe(struct dvb_frontend *fe) -{ - /* unregister frontend */ - dvb_unregister_frontend(fe); - - /* detach frontend */ - dvb_frontend_detach(fe); - - return 0; -} - -int as102_dvb_register_fe(struct as102_dev_t *as102_dev, - struct dvb_frontend *dvb_fe) -{ - int errno; - struct dvb_adapter *dvb_adap; - - if (as102_dev == NULL) - return -EINVAL; - - /* extract dvb_adapter */ - dvb_adap = &as102_dev->dvb_adap; - - /* init frontend callback ops */ - memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(dvb_fe->ops.info.name, as102_dev->name, - sizeof(dvb_fe->ops.info.name)); - - /* register dvb frontend */ - errno = dvb_register_frontend(dvb_adap, dvb_fe); - if (errno == 0) - dvb_fe->tuner_priv = as102_dev; - - return errno; -} - static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, struct as10x_tps *as10x_tps) { @@ -559,3 +280,248 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, as102_fe_get_code_rate(params->code_rate_HP); } } + +static int as102_fe_set_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tune_args tune_args = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + as102_fe_copy_tune_parameters(&tune_args, p); + + /* send abilis command: SET_TUNE */ + ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); + if (ret != 0) + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); + + mutex_unlock(&state->bus_adap->lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tps tps = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(state->bus_adap, &tps); + + if (ret == 0) + as10x_fe_copy_tps_parameters(p, &tps); + + mutex_unlock(&state->bus_adap->lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + + settings->min_delay_ms = 1000; + + return 0; +} + + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret = 0; + struct as102_state *state = fe->demodulator_priv; + struct as10x_tune_status tstate = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(state->bus_adap, &tstate); + if (ret < 0) { + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); + goto out; + } + + state->signal_strength = tstate.signal_strength; + state->ber = tstate.BER; + + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + dev_dbg(&state->bus_adap->usb_dev->dev, + "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (*status & FE_HAS_LOCK) { + if (as10x_cmd_get_demod_stats(state->bus_adap, + (struct as10x_demod_stats *) &state->demod_stats) < 0) { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dev_dbg(&state->bus_adap->usb_dev->dev, + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", + state->demod_stats.frame_count, + state->demod_stats.bad_frame_count, + state->demod_stats.bytes_fixed_by_rs, + state->demod_stats.mer); + } + } else { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + } + +out: + mutex_unlock(&state->bus_adap->lock); + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct as102_state *state = fe->demodulator_priv; + + *snr = state->demod_stats.mer; + + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct as102_state *state = fe->demodulator_priv; + + *ber = state->ber; + + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct as102_state *state = fe->demodulator_priv; + + *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); + + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct as102_state *state = fe->demodulator_priv; + + if (state->demod_stats.has_started) + *ucblocks = state->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + return 0; +} + +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct as102_state *state = fe->demodulator_priv; + int ret; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(state->bus_adap, + CONTEXT_LNA, state->elna_cfg); + + ret = as10x_cmd_turn_on(state->bus_adap); + } else { + ret = as10x_cmd_turn_off(state->bus_adap); + } + + mutex_unlock(&state->bus_adap->lock); + + return ret; +} + +static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Abilis AS102 DVB-T", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, +}; + +struct dvb_frontend *as102_attach(const char *name, + struct as10x_bus_adapter_t *bus_adap, + uint8_t elna_cfg) +{ + struct as102_state *state; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + if (state == NULL) { + dev_err(&bus_adap->usb_dev->dev, + "%s: unable to allocate memory for state\n", __func__); + return NULL; + } + fe = &state->frontend; + fe->demodulator_priv = state; + state->bus_adap = bus_adap; + state->elna_cfg = elna_cfg; + + /* init frontend callback ops */ + memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + + return fe; + +} +EXPORT_SYMBOL_GPL(as102_attach); -- cgit v1.2.3 From 1d6207fd2c262deb7006c9269eec33e64c5e514f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:20 -0300 Subject: [media] as102: get rid of as102_fe_copy_tune_parameters() This function just parses the frontend cache and converts to the as102 internal format message. Get rid of it. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 117 +++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 7ec1c67ba119..975ad638ee41 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -156,144 +156,137 @@ static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) return c; } -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dtv_frontend_properties *params) +static int as102_fe_set_frontend(struct dvb_frontend *fe) { + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tune_args tune_args = { 0 }; /* set frequency */ - tune_args->freq = params->frequency / 1000; + tune_args.freq = c->frequency / 1000; /* fix interleaving_mode */ - tune_args->interleaving_mode = INTLV_NATIVE; + tune_args.interleaving_mode = INTLV_NATIVE; - switch (params->bandwidth_hz) { + switch (c->bandwidth_hz) { case 8000000: - tune_args->bandwidth = BW_8_MHZ; + tune_args.bandwidth = BW_8_MHZ; break; case 7000000: - tune_args->bandwidth = BW_7_MHZ; + tune_args.bandwidth = BW_7_MHZ; break; case 6000000: - tune_args->bandwidth = BW_6_MHZ; + tune_args.bandwidth = BW_6_MHZ; break; default: - tune_args->bandwidth = BW_8_MHZ; + tune_args.bandwidth = BW_8_MHZ; } - switch (params->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: - tune_args->guard_interval = GUARD_INT_1_32; + tune_args.guard_interval = GUARD_INT_1_32; break; case GUARD_INTERVAL_1_16: - tune_args->guard_interval = GUARD_INT_1_16; + tune_args.guard_interval = GUARD_INT_1_16; break; case GUARD_INTERVAL_1_8: - tune_args->guard_interval = GUARD_INT_1_8; + tune_args.guard_interval = GUARD_INT_1_8; break; case GUARD_INTERVAL_1_4: - tune_args->guard_interval = GUARD_INT_1_4; + tune_args.guard_interval = GUARD_INT_1_4; break; case GUARD_INTERVAL_AUTO: default: - tune_args->guard_interval = GUARD_UNKNOWN; + tune_args.guard_interval = GUARD_UNKNOWN; break; } - switch (params->modulation) { + switch (c->modulation) { case QPSK: - tune_args->modulation = CONST_QPSK; + tune_args.modulation = CONST_QPSK; break; case QAM_16: - tune_args->modulation = CONST_QAM16; + tune_args.modulation = CONST_QAM16; break; case QAM_64: - tune_args->modulation = CONST_QAM64; + tune_args.modulation = CONST_QAM64; break; default: - tune_args->modulation = CONST_UNKNOWN; + tune_args.modulation = CONST_UNKNOWN; break; } - switch (params->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: - tune_args->transmission_mode = TRANS_MODE_2K; + tune_args.transmission_mode = TRANS_MODE_2K; break; case TRANSMISSION_MODE_8K: - tune_args->transmission_mode = TRANS_MODE_8K; + tune_args.transmission_mode = TRANS_MODE_8K; break; default: - tune_args->transmission_mode = TRANS_MODE_UNKNOWN; + tune_args.transmission_mode = TRANS_MODE_UNKNOWN; } - switch (params->hierarchy) { + switch (c->hierarchy) { case HIERARCHY_NONE: - tune_args->hierarchy = HIER_NONE; + tune_args.hierarchy = HIER_NONE; break; case HIERARCHY_1: - tune_args->hierarchy = HIER_ALPHA_1; + tune_args.hierarchy = HIER_ALPHA_1; break; case HIERARCHY_2: - tune_args->hierarchy = HIER_ALPHA_2; + tune_args.hierarchy = HIER_ALPHA_2; break; case HIERARCHY_4: - tune_args->hierarchy = HIER_ALPHA_4; + tune_args.hierarchy = HIER_ALPHA_4; break; case HIERARCHY_AUTO: - tune_args->hierarchy = HIER_UNKNOWN; + tune_args.hierarchy = HIER_UNKNOWN; break; } pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", - params->frequency, - tune_args->bandwidth, - tune_args->guard_interval); + c->frequency, + tune_args.bandwidth, + tune_args.guard_interval); /* * Detect a hierarchy selection * if HP/LP are both set to FEC_NONE, HP will be selected. */ - if ((tune_args->hierarchy != HIER_NONE) && - ((params->code_rate_LP == FEC_NONE) || - (params->code_rate_HP == FEC_NONE))) { - - if (params->code_rate_LP == FEC_NONE) { - tune_args->hier_select = HIER_HIGH_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); + if ((tune_args.hierarchy != HIER_NONE) && + ((c->code_rate_LP == FEC_NONE) || + (c->code_rate_HP == FEC_NONE))) { + + if (c->code_rate_LP == FEC_NONE) { + tune_args.hier_select = HIER_HIGH_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); } - if (params->code_rate_HP == FEC_NONE) { - tune_args->hier_select = HIER_LOW_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_LP); + if (c->code_rate_HP == FEC_NONE) { + tune_args.hier_select = HIER_LOW_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_LP); } pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", - tune_args->hierarchy, - tune_args->hier_select == HIER_HIGH_PRIORITY ? + tune_args.hierarchy, + tune_args.hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", - tune_args->hier_select == HIER_HIGH_PRIORITY ? + tune_args.hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", - tune_args->code_rate); + tune_args.code_rate); } else { - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); } -} - -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as10x_tune_args tune_args = { 0 }; + /* Set frontend arguments */ if (mutex_lock_interruptible(&state->bus_adap->lock)) return -EBUSY; - as102_fe_copy_tune_parameters(&tune_args, p); - - /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); if (ret != 0) dev_dbg(&state->bus_adap->usb_dev->dev, -- cgit v1.2.3 From c098c219b0c2da64250dd0542c5c54ca7245d1a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:21 -0300 Subject: [media] as102: get rid of as10x_fe_copy_tps_parameters() This function just converts from the as10x internal data into the DVBv5 cache. Get rid of it. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 201 ++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 103 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 975ad638ee41..0cd19f23eca9 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -30,104 +30,6 @@ struct as102_state { uint32_t ber; }; -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, - struct as10x_tps *as10x_tps) -{ - - /* extract constellation */ - switch (as10x_tps->modulation) { - case CONST_QPSK: - fe_tps->modulation = QPSK; - break; - case CONST_QAM16: - fe_tps->modulation = QAM_16; - break; - case CONST_QAM64: - fe_tps->modulation = QAM_64; - break; - } - - /* extract hierarchy */ - switch (as10x_tps->hierarchy) { - case HIER_NONE: - fe_tps->hierarchy = HIERARCHY_NONE; - break; - case HIER_ALPHA_1: - fe_tps->hierarchy = HIERARCHY_1; - break; - case HIER_ALPHA_2: - fe_tps->hierarchy = HIERARCHY_2; - break; - case HIER_ALPHA_4: - fe_tps->hierarchy = HIERARCHY_4; - break; - } - - /* extract code rate HP */ - switch (as10x_tps->code_rate_HP) { - case CODE_RATE_1_2: - fe_tps->code_rate_HP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_HP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_HP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_HP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_HP = FEC_7_8; - break; - } - - /* extract code rate LP */ - switch (as10x_tps->code_rate_LP) { - case CODE_RATE_1_2: - fe_tps->code_rate_LP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_LP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_LP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_LP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_LP = FEC_7_8; - break; - } - - /* extract guard interval */ - switch (as10x_tps->guard_interval) { - case GUARD_INT_1_32: - fe_tps->guard_interval = GUARD_INTERVAL_1_32; - break; - case GUARD_INT_1_16: - fe_tps->guard_interval = GUARD_INTERVAL_1_16; - break; - case GUARD_INT_1_8: - fe_tps->guard_interval = GUARD_INTERVAL_1_8; - break; - case GUARD_INT_1_4: - fe_tps->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - /* extract transmission mode */ - switch (as10x_tps->transmission_mode) { - case TRANS_MODE_2K: - fe_tps->transmission_mode = TRANSMISSION_MODE_2K; - break; - case TRANS_MODE_8K: - fe_tps->transmission_mode = TRANSMISSION_MODE_8K; - break; - } -} - static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) { uint8_t c; @@ -300,7 +202,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) static int as102_fe_get_frontend(struct dvb_frontend *fe) { struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret = 0; struct as10x_tps tps = { 0 }; @@ -310,12 +212,105 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) /* send abilis command: GET_TPS */ ret = as10x_cmd_get_tps(state->bus_adap, &tps); - if (ret == 0) - as10x_fe_copy_tps_parameters(p, &tps); - mutex_unlock(&state->bus_adap->lock); - return (ret < 0) ? -EINVAL : 0; + if (ret < 0) + return ret; + + /* extract constellation */ + switch (tps.modulation) { + case CONST_QPSK: + c->modulation = QPSK; + break; + case CONST_QAM16: + c->modulation = QAM_16; + break; + case CONST_QAM64: + c->modulation = QAM_64; + break; + } + + /* extract hierarchy */ + switch (tps.hierarchy) { + case HIER_NONE: + c->hierarchy = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + c->hierarchy = HIERARCHY_1; + break; + case HIER_ALPHA_2: + c->hierarchy = HIERARCHY_2; + break; + case HIER_ALPHA_4: + c->hierarchy = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch (tps.code_rate_HP) { + case CODE_RATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch (tps.code_rate_LP) { + case CODE_RATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch (tps.guard_interval) { + case GUARD_INT_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch (tps.transmission_mode) { + case TRANS_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; } static int as102_fe_get_tune_settings(struct dvb_frontend *fe, -- cgit v1.2.3 From 47f79129ecf5fd12d847c2e63b6ce39d1df4a648 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:22 -0300 Subject: [media] as102: prepare as102_fe to be compiled as a module Remove the dependencies of as102_cmd from as102, in order to allow it to be compiled as a separate module. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 116 +++++++++++++++++++++++++++++++++ drivers/media/usb/as102/as102_drv.h | 8 +-- drivers/media/usb/as102/as102_fe.c | 105 ++++++++--------------------- drivers/media/usb/as102/as102_fe.h | 29 +++++++++ drivers/media/usb/as102/as10x_cmd.h | 2 - drivers/media/usb/as102/as10x_handle.h | 3 +- drivers/media/usb/as102/as10x_types.h | 2 - 7 files changed, 179 insertions(+), 86 deletions(-) create mode 100644 drivers/media/usb/as102/as102_fe.h diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index ff5bd2e5657a..8be1474b2c36 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -24,6 +24,8 @@ /* header file for usb device driver*/ #include "as102_drv.h" +#include "as10x_cmd.h" +#include "as102_fe.h" #include "as102_fw.h" #include "dvbdev.h" @@ -176,6 +178,119 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return 0; } +static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + /* Set frontend arguments */ + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + ret = as10x_cmd_set_tune(bus_adap, tune_args); + if (ret != 0) + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_tps(void *priv, struct as10x_tps *tps) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(bus_adap, tps); + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_status(void *priv, struct as10x_tune_status *tstate) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(bus_adap, tstate); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); + } + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dev_dbg(&bus_adap->usb_dev->dev, + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", + demod_stats->frame_count, + demod_stats->bad_frame_count, + demod_stats->bytes_fixed_by_rs, + demod_stats->mer); + } + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(bus_adap, + CONTEXT_LNA, elna_cfg); + + ret = as10x_cmd_turn_on(bus_adap); + } else { + ret = as10x_cmd_turn_off(bus_adap); + } + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static const struct as102_fe_ops as102_fe_ops = { + .set_tune = as102_set_tune, + .get_tps = as102_get_tps, + .get_status = as102_get_status, + .get_stats = as102_get_stats, + .stream_ctrl = as102_stream_ctrl, +}; + int as102_dvb_register(struct as102_dev_t *as102_dev) { struct device *dev = &as102_dev->bus_adap.usb_dev->dev; @@ -218,6 +333,7 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) /* Attach the frontend */ as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name, + &as102_fe_ops, &as102_dev->bus_adap, as102_dev->elna_cfg); if (!as102_dev->dvb_fe) { diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index 1e2a76d3c517..9430d30163a3 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -13,10 +13,13 @@ * GNU General Public License for more details. */ +#ifndef _AS102_DRV_H +#define _AS102_DRV_H #include #include #include #include +#include "as10x_handle.h" #include "as10x_cmd.h" #include "as102_usb_drv.h" @@ -77,7 +80,4 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -/* FIXME: move it to a separate header */ -struct dvb_frontend *as102_attach(const char *name, - struct as10x_bus_adapter_t *bus_adap, - uint8_t elna_cfg); +#endif \ No newline at end of file diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 0cd19f23eca9..f57560c191ae 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -13,15 +13,17 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#include "as102_drv.h" -#include "as10x_types.h" -#include "as10x_cmd.h" + +#include + +#include "as102_fe.h" struct as102_state { struct dvb_frontend frontend; struct as10x_demod_stats demod_stats; - struct as10x_bus_adapter_t *bus_adap; + const struct as102_fe_ops *ops; + void *priv; uint8_t elna_cfg; /* signal strength */ @@ -62,7 +64,6 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) { struct as102_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0; struct as10x_tune_args tune_args = { 0 }; /* set frequency */ @@ -186,17 +187,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) } /* Set frontend arguments */ - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - - ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); - if (ret != 0) - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_set_tune failed. (err = %d)\n", ret); - - mutex_unlock(&state->bus_adap->lock); - - return (ret < 0) ? -EINVAL : 0; + return state->ops->set_tune(state->priv, &tune_args); } static int as102_fe_get_frontend(struct dvb_frontend *fe) @@ -206,14 +197,8 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) int ret = 0; struct as10x_tps tps = { 0 }; - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - /* send abilis command: GET_TPS */ - ret = as10x_cmd_get_tps(state->bus_adap, &tps); - - mutex_unlock(&state->bus_adap->lock); - + ret = state->ops->get_tps(state->priv, &tps); if (ret < 0) return ret; @@ -321,24 +306,16 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe, return 0; } - static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) { int ret = 0; struct as102_state *state = fe->demodulator_priv; struct as10x_tune_status tstate = { 0 }; - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - /* send abilis command: GET_TUNE_STATUS */ - ret = as10x_cmd_get_tune_status(state->bus_adap, &tstate); - if (ret < 0) { - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_get_tune_status failed (err = %d)\n", - ret); - goto out; - } + ret = state->ops->get_status(state->priv, &tstate); + if (ret < 0) + return ret; state->signal_strength = tstate.signal_strength; state->ber = tstate.BER; @@ -358,31 +335,19 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = TUNE_STATUS_NOT_TUNED; } - dev_dbg(&state->bus_adap->usb_dev->dev, - "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (*status & FE_HAS_LOCK) { - if (as10x_cmd_get_demod_stats(state->bus_adap, - (struct as10x_demod_stats *) &state->demod_stats) < 0) { - memset(&state->demod_stats, 0, sizeof(state->demod_stats)); - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); - } else { - dev_dbg(&state->bus_adap->usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", - state->demod_stats.frame_count, - state->demod_stats.bad_frame_count, - state->demod_stats.bytes_fixed_by_rs, - state->demod_stats.mer); - } - } else { + pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (!(*status & FE_HAS_LOCK)) { memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return 0; } -out: - mutex_unlock(&state->bus_adap->lock); + ret = state->ops->get_stats(state->priv, &state->demod_stats); + if (ret < 0) + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return ret; } @@ -436,24 +401,9 @@ static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) { struct as102_state *state = fe->demodulator_priv; - int ret; - - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - if (acquire) { - if (elna_enable) - as10x_cmd_set_context(state->bus_adap, - CONTEXT_LNA, state->elna_cfg); - - ret = as10x_cmd_turn_on(state->bus_adap); - } else { - ret = as10x_cmd_turn_off(state->bus_adap); - } - - mutex_unlock(&state->bus_adap->lock); - - return ret; + return state->ops->stream_ctrl(state->priv, acquire, + state->elna_cfg); } static struct dvb_frontend_ops as102_fe_ops = { @@ -488,7 +438,8 @@ static struct dvb_frontend_ops as102_fe_ops = { }; struct dvb_frontend *as102_attach(const char *name, - struct as10x_bus_adapter_t *bus_adap, + const struct as102_fe_ops *ops, + void *priv, uint8_t elna_cfg) { struct as102_state *state; @@ -496,13 +447,13 @@ struct dvb_frontend *as102_attach(const char *name, state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); if (state == NULL) { - dev_err(&bus_adap->usb_dev->dev, - "%s: unable to allocate memory for state\n", __func__); + pr_err("%s: unable to allocate memory for state\n", __func__); return NULL; } fe = &state->frontend; fe->demodulator_priv = state; - state->bus_adap = bus_adap; + state->ops = ops; + state->priv = priv; state->elna_cfg = elna_cfg; /* init frontend callback ops */ diff --git a/drivers/media/usb/as102/as102_fe.h b/drivers/media/usb/as102/as102_fe.h new file mode 100644 index 000000000000..4098cf8f8cf9 --- /dev/null +++ b/drivers/media/usb/as102/as102_fe.h @@ -0,0 +1,29 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2014 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, 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 "as10x_types.h" + +struct as102_fe_ops { + int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); + int (*get_tps)(void *priv, struct as10x_tps *tps); + int (*get_status)(void *priv, struct as10x_tune_status *tstate); + int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats); + int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg); +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg); diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index 1c9ea2c2175e..83c0440dba2f 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -15,9 +15,7 @@ #ifndef _AS10X_CMD_H_ #define _AS10X_CMD_H_ -#ifdef __KERNEL__ #include -#endif #include "as10x_types.h" diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h index e535fffbcd94..d6b58c770500 100644 --- a/drivers/media/usb/as102/as10x_handle.h +++ b/drivers/media/usb/as102/as10x_handle.h @@ -12,7 +12,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#ifdef __KERNEL__ +#ifndef _AS10X_HANDLE_H +#define _AS10X_HANDLE_H struct as10x_bus_adapter_t; struct as102_dev_t; diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h index f82d51e542e3..80a5398b580f 100644 --- a/drivers/media/usb/as102/as10x_types.h +++ b/drivers/media/usb/as102/as10x_types.h @@ -15,8 +15,6 @@ #ifndef _AS10X_TYPES_H_ #define _AS10X_TYPES_H_ -#include "as10x_handle.h" - /*********************************/ /* MACRO DEFINITIONS */ /*********************************/ -- cgit v1.2.3 From dcae77814865122ed411de1a4e8ebd02796cf3c4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:23 -0300 Subject: [media] as102-fe: make it an independent driver Move as102-fe to dvb-frontends directory and make it an independent driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 5 + drivers/media/dvb-frontends/Makefile | 2 +- drivers/media/dvb-frontends/as102_fe.c | 470 +++++++++++++++++++++++++++ drivers/media/dvb-frontends/as102_fe.h | 29 ++ drivers/media/dvb-frontends/as102_fe_types.h | 188 +++++++++++ drivers/media/usb/as102/Makefile | 3 +- drivers/media/usb/as102/as102_fe.c | 466 -------------------------- drivers/media/usb/as102/as102_fe.h | 29 -- drivers/media/usb/as102/as10x_cmd.c | 1 - drivers/media/usb/as102/as10x_cmd.h | 2 +- drivers/media/usb/as102/as10x_cmd_cfg.c | 1 - drivers/media/usb/as102/as10x_types.h | 188 ----------- 12 files changed, 696 insertions(+), 688 deletions(-) create mode 100644 drivers/media/dvb-frontends/as102_fe.c create mode 100644 drivers/media/dvb-frontends/as102_fe.h create mode 100644 drivers/media/dvb-frontends/as102_fe_types.h delete mode 100644 drivers/media/usb/as102/as102_fe.c delete mode 100644 drivers/media/usb/as102/as102_fe.h delete mode 100644 drivers/media/usb/as102/as10x_types.h diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index fe0ddcca192c..aa5ae224626a 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -471,6 +471,11 @@ config DVB_SI2168 help Say Y when you want to support this frontend. +config DVB_AS102_FE + tristate + depends on DVB_CORE + default DVB_AS102 + comment "DVB-C (cable) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index edf103d45920..fc4e689d4b67 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -113,4 +113,4 @@ obj-$(CONFIG_DVB_RTL2832) += rtl2832.o obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o obj-$(CONFIG_DVB_AF9033) += af9033.o - +obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c new file mode 100644 index 000000000000..b272e4ea1860 --- /dev/null +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -0,0 +1,470 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * Copyright (C) 2010 Devin Heitmueller + * + * 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, 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 "as102_fe.h" + +struct as102_state { + struct dvb_frontend frontend; + struct as10x_demod_stats demod_stats; + + const struct as102_fe_ops *ops; + void *priv; + uint8_t elna_cfg; + + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; +}; + +static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) +{ + uint8_t c; + + switch (arg) { + case FEC_1_2: + c = CODE_RATE_1_2; + break; + case FEC_2_3: + c = CODE_RATE_2_3; + break; + case FEC_3_4: + c = CODE_RATE_3_4; + break; + case FEC_5_6: + c = CODE_RATE_5_6; + break; + case FEC_7_8: + c = CODE_RATE_7_8; + break; + default: + c = CODE_RATE_UNKNOWN; + break; + } + + return c; +} + +static int as102_fe_set_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct as10x_tune_args tune_args = { 0 }; + + /* set frequency */ + tune_args.freq = c->frequency / 1000; + + /* fix interleaving_mode */ + tune_args.interleaving_mode = INTLV_NATIVE; + + switch (c->bandwidth_hz) { + case 8000000: + tune_args.bandwidth = BW_8_MHZ; + break; + case 7000000: + tune_args.bandwidth = BW_7_MHZ; + break; + case 6000000: + tune_args.bandwidth = BW_6_MHZ; + break; + default: + tune_args.bandwidth = BW_8_MHZ; + } + + switch (c->guard_interval) { + case GUARD_INTERVAL_1_32: + tune_args.guard_interval = GUARD_INT_1_32; + break; + case GUARD_INTERVAL_1_16: + tune_args.guard_interval = GUARD_INT_1_16; + break; + case GUARD_INTERVAL_1_8: + tune_args.guard_interval = GUARD_INT_1_8; + break; + case GUARD_INTERVAL_1_4: + tune_args.guard_interval = GUARD_INT_1_4; + break; + case GUARD_INTERVAL_AUTO: + default: + tune_args.guard_interval = GUARD_UNKNOWN; + break; + } + + switch (c->modulation) { + case QPSK: + tune_args.modulation = CONST_QPSK; + break; + case QAM_16: + tune_args.modulation = CONST_QAM16; + break; + case QAM_64: + tune_args.modulation = CONST_QAM64; + break; + default: + tune_args.modulation = CONST_UNKNOWN; + break; + } + + switch (c->transmission_mode) { + case TRANSMISSION_MODE_2K: + tune_args.transmission_mode = TRANS_MODE_2K; + break; + case TRANSMISSION_MODE_8K: + tune_args.transmission_mode = TRANS_MODE_8K; + break; + default: + tune_args.transmission_mode = TRANS_MODE_UNKNOWN; + } + + switch (c->hierarchy) { + case HIERARCHY_NONE: + tune_args.hierarchy = HIER_NONE; + break; + case HIERARCHY_1: + tune_args.hierarchy = HIER_ALPHA_1; + break; + case HIERARCHY_2: + tune_args.hierarchy = HIER_ALPHA_2; + break; + case HIERARCHY_4: + tune_args.hierarchy = HIER_ALPHA_4; + break; + case HIERARCHY_AUTO: + tune_args.hierarchy = HIER_UNKNOWN; + break; + } + + pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + c->frequency, + tune_args.bandwidth, + tune_args.guard_interval); + + /* + * Detect a hierarchy selection + * if HP/LP are both set to FEC_NONE, HP will be selected. + */ + if ((tune_args.hierarchy != HIER_NONE) && + ((c->code_rate_LP == FEC_NONE) || + (c->code_rate_HP == FEC_NONE))) { + + if (c->code_rate_LP == FEC_NONE) { + tune_args.hier_select = HIER_HIGH_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); + } + + if (c->code_rate_HP == FEC_NONE) { + tune_args.hier_select = HIER_LOW_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_LP); + } + + pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", + tune_args.hierarchy, + tune_args.hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args.hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args.code_rate); + } else { + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); + } + + /* Set frontend arguments */ + return state->ops->set_tune(state->priv, &tune_args); +} + +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tps tps = { 0 }; + + /* send abilis command: GET_TPS */ + ret = state->ops->get_tps(state->priv, &tps); + if (ret < 0) + return ret; + + /* extract constellation */ + switch (tps.modulation) { + case CONST_QPSK: + c->modulation = QPSK; + break; + case CONST_QAM16: + c->modulation = QAM_16; + break; + case CONST_QAM64: + c->modulation = QAM_64; + break; + } + + /* extract hierarchy */ + switch (tps.hierarchy) { + case HIER_NONE: + c->hierarchy = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + c->hierarchy = HIERARCHY_1; + break; + case HIER_ALPHA_2: + c->hierarchy = HIERARCHY_2; + break; + case HIER_ALPHA_4: + c->hierarchy = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch (tps.code_rate_HP) { + case CODE_RATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch (tps.code_rate_LP) { + case CODE_RATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch (tps.guard_interval) { + case GUARD_INT_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch (tps.transmission_mode) { + case TRANS_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + + settings->min_delay_ms = 1000; + + return 0; +} + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret = 0; + struct as102_state *state = fe->demodulator_priv; + struct as10x_tune_status tstate = { 0 }; + + /* send abilis command: GET_TUNE_STATUS */ + ret = state->ops->get_status(state->priv, &tstate); + if (ret < 0) + return ret; + + state->signal_strength = tstate.signal_strength; + state->ber = tstate.BER; + + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (!(*status & FE_HAS_LOCK)) { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return 0; + } + + ret = state->ops->get_stats(state->priv, &state->demod_stats); + if (ret < 0) + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct as102_state *state = fe->demodulator_priv; + + *snr = state->demod_stats.mer; + + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct as102_state *state = fe->demodulator_priv; + + *ber = state->ber; + + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct as102_state *state = fe->demodulator_priv; + + *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); + + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct as102_state *state = fe->demodulator_priv; + + if (state->demod_stats.has_started) + *ucblocks = state->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + return 0; +} + +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct as102_state *state = fe->demodulator_priv; + + return state->ops->stream_ctrl(state->priv, acquire, + state->elna_cfg); +} + +static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Abilis AS102 DVB-T", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg) +{ + struct as102_state *state; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + if (state == NULL) { + pr_err("%s: unable to allocate memory for state\n", __func__); + return NULL; + } + fe = &state->frontend; + fe->demodulator_priv = state; + state->ops = ops; + state->priv = priv; + state->elna_cfg = elna_cfg; + + /* init frontend callback ops */ + memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + + return fe; + +} +EXPORT_SYMBOL_GPL(as102_attach); + +MODULE_DESCRIPTION("as102-fe"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pierrick Hascoet "); diff --git a/drivers/media/dvb-frontends/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h new file mode 100644 index 000000000000..a7c91430ca3d --- /dev/null +++ b/drivers/media/dvb-frontends/as102_fe.h @@ -0,0 +1,29 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2014 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, 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 "as102_fe_types.h" + +struct as102_fe_ops { + int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); + int (*get_tps)(void *priv, struct as10x_tps *tps); + int (*get_status)(void *priv, struct as10x_tune_status *tstate); + int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats); + int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg); +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg); diff --git a/drivers/media/dvb-frontends/as102_fe_types.h b/drivers/media/dvb-frontends/as102_fe_types.h new file mode 100644 index 000000000000..80a5398b580f --- /dev/null +++ b/drivers/media/dvb-frontends/as102_fe_types.h @@ -0,0 +1,188 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet + * + * 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, 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. + */ +#ifndef _AS10X_TYPES_H_ +#define _AS10X_TYPES_H_ + +/*********************************/ +/* MACRO DEFINITIONS */ +/*********************************/ + +/* bandwidth constant values */ +#define BW_5_MHZ 0x00 +#define BW_6_MHZ 0x01 +#define BW_7_MHZ 0x02 +#define BW_8_MHZ 0x03 + +/* hierarchy priority selection values */ +#define HIER_NO_PRIORITY 0x00 +#define HIER_LOW_PRIORITY 0x01 +#define HIER_HIGH_PRIORITY 0x02 + +/* constellation available values */ +#define CONST_QPSK 0x00 +#define CONST_QAM16 0x01 +#define CONST_QAM64 0x02 +#define CONST_UNKNOWN 0xFF + +/* hierarchy available values */ +#define HIER_NONE 0x00 +#define HIER_ALPHA_1 0x01 +#define HIER_ALPHA_2 0x02 +#define HIER_ALPHA_4 0x03 +#define HIER_UNKNOWN 0xFF + +/* interleaving available values */ +#define INTLV_NATIVE 0x00 +#define INTLV_IN_DEPTH 0x01 +#define INTLV_UNKNOWN 0xFF + +/* code rate available values */ +#define CODE_RATE_1_2 0x00 +#define CODE_RATE_2_3 0x01 +#define CODE_RATE_3_4 0x02 +#define CODE_RATE_5_6 0x03 +#define CODE_RATE_7_8 0x04 +#define CODE_RATE_UNKNOWN 0xFF + +/* guard interval available values */ +#define GUARD_INT_1_32 0x00 +#define GUARD_INT_1_16 0x01 +#define GUARD_INT_1_8 0x02 +#define GUARD_INT_1_4 0x03 +#define GUARD_UNKNOWN 0xFF + +/* transmission mode available values */ +#define TRANS_MODE_2K 0x00 +#define TRANS_MODE_8K 0x01 +#define TRANS_MODE_4K 0x02 +#define TRANS_MODE_UNKNOWN 0xFF + +/* DVBH signalling available values */ +#define TIMESLICING_PRESENT 0x01 +#define MPE_FEC_PRESENT 0x02 + +/* tune state available */ +#define TUNE_STATUS_NOT_TUNED 0x00 +#define TUNE_STATUS_IDLE 0x01 +#define TUNE_STATUS_LOCKING 0x02 +#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 +#define TUNE_STATUS_STREAM_DETECTED 0x04 +#define TUNE_STATUS_STREAM_TUNED 0x05 +#define TUNE_STATUS_ERROR 0xFF + +/* available TS FID filter types */ +#define TS_PID_TYPE_TS 0 +#define TS_PID_TYPE_PSI_SI 1 +#define TS_PID_TYPE_MPE 2 + +/* number of echos available */ +#define MAX_ECHOS 15 + +/* Context types */ +#define CONTEXT_LNA 1010 +#define CONTEXT_ELNA_HYSTERESIS 4003 +#define CONTEXT_ELNA_GAIN 4004 +#define CONTEXT_MER_THRESHOLD 5005 +#define CONTEXT_MER_OFFSET 5006 +#define CONTEXT_IR_STATE 7000 +#define CONTEXT_TSOUT_MSB_FIRST 7004 +#define CONTEXT_TSOUT_FALLING_EDGE 7005 + +/* Configuration modes */ +#define CFG_MODE_ON 0 +#define CFG_MODE_OFF 1 +#define CFG_MODE_AUTO 2 + +struct as10x_tps { + uint8_t modulation; + uint8_t hierarchy; + uint8_t interleaving_mode; + uint8_t code_rate_HP; + uint8_t code_rate_LP; + uint8_t guard_interval; + uint8_t transmission_mode; + uint8_t DVBH_mask_HP; + uint8_t DVBH_mask_LP; + uint16_t cell_ID; +} __packed; + +struct as10x_tune_args { + /* frequency */ + uint32_t freq; + /* bandwidth */ + uint8_t bandwidth; + /* hierarchy selection */ + uint8_t hier_select; + /* constellation */ + uint8_t modulation; + /* hierarchy */ + uint8_t hierarchy; + /* interleaving mode */ + uint8_t interleaving_mode; + /* code rate */ + uint8_t code_rate; + /* guard interval */ + uint8_t guard_interval; + /* transmission mode */ + uint8_t transmission_mode; +} __packed; + +struct as10x_tune_status { + /* tune status */ + uint8_t tune_state; + /* signal strength */ + int16_t signal_strength; + /* packet error rate 10^-4 */ + uint16_t PER; + /* bit error rate 10^-4 */ + uint16_t BER; +} __packed; + +struct as10x_demod_stats { + /* frame counter */ + uint32_t frame_count; + /* Bad frame counter */ + uint32_t bad_frame_count; + /* Number of wrong bytes fixed by Reed-Solomon */ + uint32_t bytes_fixed_by_rs; + /* Averaged MER */ + uint16_t mer; + /* statistics calculation state indicator (started or not) */ + uint8_t has_started; +} __packed; + +struct as10x_ts_filter { + uint16_t pid; /* valid PID value 0x00 : 0x2000 */ + uint8_t type; /* Red TS_PID_TYPE_ values */ + uint8_t idx; /* index in filtering table */ +} __packed; + +struct as10x_register_value { + uint8_t mode; + union { + uint8_t value8; /* 8 bit value */ + uint16_t value16; /* 16 bit value */ + uint32_t value32; /* 32 bit value */ + } __packed u; +} __packed; + +struct as10x_register_addr { + /* register addr */ + uint32_t addr; + /* register mode access */ + uint8_t mode; +}; + +#endif diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile index 8916d8a909bc..22f43eee4a3b 100644 --- a/drivers/media/usb/as102/Makefile +++ b/drivers/media/usb/as102/Makefile @@ -1,6 +1,7 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ - as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o + as102_usb_drv.o as10x_cmd_cfg.o obj-$(CONFIG_DVB_AS102) += dvb-as102.o ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c deleted file mode 100644 index f57560c191ae..000000000000 --- a/drivers/media/usb/as102/as102_fe.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * Copyright (C) 2010 Devin Heitmueller - * - * 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, 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 "as102_fe.h" - -struct as102_state { - struct dvb_frontend frontend; - struct as10x_demod_stats demod_stats; - - const struct as102_fe_ops *ops; - void *priv; - uint8_t elna_cfg; - - /* signal strength */ - uint16_t signal_strength; - /* bit error rate */ - uint32_t ber; -}; - -static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) -{ - uint8_t c; - - switch (arg) { - case FEC_1_2: - c = CODE_RATE_1_2; - break; - case FEC_2_3: - c = CODE_RATE_2_3; - break; - case FEC_3_4: - c = CODE_RATE_3_4; - break; - case FEC_5_6: - c = CODE_RATE_5_6; - break; - case FEC_7_8: - c = CODE_RATE_7_8; - break; - default: - c = CODE_RATE_UNKNOWN; - break; - } - - return c; -} - -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct as10x_tune_args tune_args = { 0 }; - - /* set frequency */ - tune_args.freq = c->frequency / 1000; - - /* fix interleaving_mode */ - tune_args.interleaving_mode = INTLV_NATIVE; - - switch (c->bandwidth_hz) { - case 8000000: - tune_args.bandwidth = BW_8_MHZ; - break; - case 7000000: - tune_args.bandwidth = BW_7_MHZ; - break; - case 6000000: - tune_args.bandwidth = BW_6_MHZ; - break; - default: - tune_args.bandwidth = BW_8_MHZ; - } - - switch (c->guard_interval) { - case GUARD_INTERVAL_1_32: - tune_args.guard_interval = GUARD_INT_1_32; - break; - case GUARD_INTERVAL_1_16: - tune_args.guard_interval = GUARD_INT_1_16; - break; - case GUARD_INTERVAL_1_8: - tune_args.guard_interval = GUARD_INT_1_8; - break; - case GUARD_INTERVAL_1_4: - tune_args.guard_interval = GUARD_INT_1_4; - break; - case GUARD_INTERVAL_AUTO: - default: - tune_args.guard_interval = GUARD_UNKNOWN; - break; - } - - switch (c->modulation) { - case QPSK: - tune_args.modulation = CONST_QPSK; - break; - case QAM_16: - tune_args.modulation = CONST_QAM16; - break; - case QAM_64: - tune_args.modulation = CONST_QAM64; - break; - default: - tune_args.modulation = CONST_UNKNOWN; - break; - } - - switch (c->transmission_mode) { - case TRANSMISSION_MODE_2K: - tune_args.transmission_mode = TRANS_MODE_2K; - break; - case TRANSMISSION_MODE_8K: - tune_args.transmission_mode = TRANS_MODE_8K; - break; - default: - tune_args.transmission_mode = TRANS_MODE_UNKNOWN; - } - - switch (c->hierarchy) { - case HIERARCHY_NONE: - tune_args.hierarchy = HIER_NONE; - break; - case HIERARCHY_1: - tune_args.hierarchy = HIER_ALPHA_1; - break; - case HIERARCHY_2: - tune_args.hierarchy = HIER_ALPHA_2; - break; - case HIERARCHY_4: - tune_args.hierarchy = HIER_ALPHA_4; - break; - case HIERARCHY_AUTO: - tune_args.hierarchy = HIER_UNKNOWN; - break; - } - - pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", - c->frequency, - tune_args.bandwidth, - tune_args.guard_interval); - - /* - * Detect a hierarchy selection - * if HP/LP are both set to FEC_NONE, HP will be selected. - */ - if ((tune_args.hierarchy != HIER_NONE) && - ((c->code_rate_LP == FEC_NONE) || - (c->code_rate_HP == FEC_NONE))) { - - if (c->code_rate_LP == FEC_NONE) { - tune_args.hier_select = HIER_HIGH_PRIORITY; - tune_args.code_rate = - as102_fe_get_code_rate(c->code_rate_HP); - } - - if (c->code_rate_HP == FEC_NONE) { - tune_args.hier_select = HIER_LOW_PRIORITY; - tune_args.code_rate = - as102_fe_get_code_rate(c->code_rate_LP); - } - - pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", - tune_args.hierarchy, - tune_args.hier_select == HIER_HIGH_PRIORITY ? - "HP" : "LP", - tune_args.hier_select == HIER_HIGH_PRIORITY ? - "HP" : "LP", - tune_args.code_rate); - } else { - tune_args.code_rate = - as102_fe_get_code_rate(c->code_rate_HP); - } - - /* Set frontend arguments */ - return state->ops->set_tune(state->priv, &tune_args); -} - -static int as102_fe_get_frontend(struct dvb_frontend *fe) -{ - struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0; - struct as10x_tps tps = { 0 }; - - /* send abilis command: GET_TPS */ - ret = state->ops->get_tps(state->priv, &tps); - if (ret < 0) - return ret; - - /* extract constellation */ - switch (tps.modulation) { - case CONST_QPSK: - c->modulation = QPSK; - break; - case CONST_QAM16: - c->modulation = QAM_16; - break; - case CONST_QAM64: - c->modulation = QAM_64; - break; - } - - /* extract hierarchy */ - switch (tps.hierarchy) { - case HIER_NONE: - c->hierarchy = HIERARCHY_NONE; - break; - case HIER_ALPHA_1: - c->hierarchy = HIERARCHY_1; - break; - case HIER_ALPHA_2: - c->hierarchy = HIERARCHY_2; - break; - case HIER_ALPHA_4: - c->hierarchy = HIERARCHY_4; - break; - } - - /* extract code rate HP */ - switch (tps.code_rate_HP) { - case CODE_RATE_1_2: - c->code_rate_HP = FEC_1_2; - break; - case CODE_RATE_2_3: - c->code_rate_HP = FEC_2_3; - break; - case CODE_RATE_3_4: - c->code_rate_HP = FEC_3_4; - break; - case CODE_RATE_5_6: - c->code_rate_HP = FEC_5_6; - break; - case CODE_RATE_7_8: - c->code_rate_HP = FEC_7_8; - break; - } - - /* extract code rate LP */ - switch (tps.code_rate_LP) { - case CODE_RATE_1_2: - c->code_rate_LP = FEC_1_2; - break; - case CODE_RATE_2_3: - c->code_rate_LP = FEC_2_3; - break; - case CODE_RATE_3_4: - c->code_rate_LP = FEC_3_4; - break; - case CODE_RATE_5_6: - c->code_rate_LP = FEC_5_6; - break; - case CODE_RATE_7_8: - c->code_rate_LP = FEC_7_8; - break; - } - - /* extract guard interval */ - switch (tps.guard_interval) { - case GUARD_INT_1_32: - c->guard_interval = GUARD_INTERVAL_1_32; - break; - case GUARD_INT_1_16: - c->guard_interval = GUARD_INTERVAL_1_16; - break; - case GUARD_INT_1_8: - c->guard_interval = GUARD_INTERVAL_1_8; - break; - case GUARD_INT_1_4: - c->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - /* extract transmission mode */ - switch (tps.transmission_mode) { - case TRANS_MODE_2K: - c->transmission_mode = TRANSMISSION_MODE_2K; - break; - case TRANS_MODE_8K: - c->transmission_mode = TRANSMISSION_MODE_8K; - break; - } - - return 0; -} - -static int as102_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *settings) { - - settings->min_delay_ms = 1000; - - return 0; -} - -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - int ret = 0; - struct as102_state *state = fe->demodulator_priv; - struct as10x_tune_status tstate = { 0 }; - - /* send abilis command: GET_TUNE_STATUS */ - ret = state->ops->get_status(state->priv, &tstate); - if (ret < 0) - return ret; - - state->signal_strength = tstate.signal_strength; - state->ber = tstate.BER; - - switch (tstate.tune_state) { - case TUNE_STATUS_SIGNAL_DVB_OK: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - break; - case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; - break; - case TUNE_STATUS_STREAM_TUNED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; - break; - default: - *status = TUNE_STATUS_NOT_TUNED; - } - - pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (!(*status & FE_HAS_LOCK)) { - memset(&state->demod_stats, 0, sizeof(state->demod_stats)); - return 0; - } - - ret = state->ops->get_stats(state->priv, &state->demod_stats); - if (ret < 0) - memset(&state->demod_stats, 0, sizeof(state->demod_stats)); - - return ret; -} - -/* - * Note: - * - in AS102 SNR=MER - * - the SNR will be returned in linear terms, i.e. not in dB - * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB - * - the accuracy is >2dB for SNR values outside this range - */ -static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct as102_state *state = fe->demodulator_priv; - - *snr = state->demod_stats.mer; - - return 0; -} - -static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct as102_state *state = fe->demodulator_priv; - - *ber = state->ber; - - return 0; -} - -static int as102_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct as102_state *state = fe->demodulator_priv; - - *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); - - return 0; -} - -static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct as102_state *state = fe->demodulator_priv; - - if (state->demod_stats.has_started) - *ucblocks = state->demod_stats.bad_frame_count; - else - *ucblocks = 0; - - return 0; -} - -static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct as102_state *state = fe->demodulator_priv; - - return state->ops->stream_ctrl(state->priv, acquire, - state->elna_cfg); -} - -static struct dvb_frontend_ops as102_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Abilis AS102 DVB-T", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .set_frontend = as102_fe_set_frontend, - .get_frontend = as102_fe_get_frontend, - .get_tune_settings = as102_fe_get_tune_settings, - - .read_status = as102_fe_read_status, - .read_snr = as102_fe_read_snr, - .read_ber = as102_fe_read_ber, - .read_signal_strength = as102_fe_read_signal_strength, - .read_ucblocks = as102_fe_read_ucblocks, - .ts_bus_ctrl = as102_fe_ts_bus_ctrl, -}; - -struct dvb_frontend *as102_attach(const char *name, - const struct as102_fe_ops *ops, - void *priv, - uint8_t elna_cfg) -{ - struct as102_state *state; - struct dvb_frontend *fe; - - state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); - if (state == NULL) { - pr_err("%s: unable to allocate memory for state\n", __func__); - return NULL; - } - fe = &state->frontend; - fe->demodulator_priv = state; - state->ops = ops; - state->priv = priv; - state->elna_cfg = elna_cfg; - - /* init frontend callback ops */ - memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); - - return fe; - -} -EXPORT_SYMBOL_GPL(as102_attach); diff --git a/drivers/media/usb/as102/as102_fe.h b/drivers/media/usb/as102/as102_fe.h deleted file mode 100644 index 4098cf8f8cf9..000000000000 --- a/drivers/media/usb/as102/as102_fe.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2014 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, 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 "as10x_types.h" - -struct as102_fe_ops { - int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); - int (*get_tps)(void *priv, struct as10x_tps *tps); - int (*get_status)(void *priv, struct as10x_tune_status *tstate); - int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats); - int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg); -}; - -struct dvb_frontend *as102_attach(const char *name, - const struct as102_fe_ops *ops, - void *priv, - uint8_t elna_cfg); diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c index 8868c52500ee..ef238022dfe5 100644 --- a/drivers/media/usb/as102/as10x_cmd.c +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -16,7 +16,6 @@ #include #include "as102_drv.h" -#include "as10x_types.h" #include "as10x_cmd.h" /** diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index 83c0440dba2f..09134f73ba3d 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -17,7 +17,7 @@ #include -#include "as10x_types.h" +#include "as102_fe_types.h" /*********************************/ /* MACRO DEFINITIONS */ diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c index 833463343ada..6f9dea1d860b 100644 --- a/drivers/media/usb/as102/as10x_cmd_cfg.c +++ b/drivers/media/usb/as102/as10x_cmd_cfg.c @@ -15,7 +15,6 @@ #include #include "as102_drv.h" -#include "as10x_types.h" #include "as10x_cmd.h" /***************************/ diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h deleted file mode 100644 index 80a5398b580f..000000000000 --- a/drivers/media/usb/as102/as10x_types.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Abilis Systems Single DVB-T Receiver - * Copyright (C) 2008 Pierrick Hascoet - * - * 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, 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. - */ -#ifndef _AS10X_TYPES_H_ -#define _AS10X_TYPES_H_ - -/*********************************/ -/* MACRO DEFINITIONS */ -/*********************************/ - -/* bandwidth constant values */ -#define BW_5_MHZ 0x00 -#define BW_6_MHZ 0x01 -#define BW_7_MHZ 0x02 -#define BW_8_MHZ 0x03 - -/* hierarchy priority selection values */ -#define HIER_NO_PRIORITY 0x00 -#define HIER_LOW_PRIORITY 0x01 -#define HIER_HIGH_PRIORITY 0x02 - -/* constellation available values */ -#define CONST_QPSK 0x00 -#define CONST_QAM16 0x01 -#define CONST_QAM64 0x02 -#define CONST_UNKNOWN 0xFF - -/* hierarchy available values */ -#define HIER_NONE 0x00 -#define HIER_ALPHA_1 0x01 -#define HIER_ALPHA_2 0x02 -#define HIER_ALPHA_4 0x03 -#define HIER_UNKNOWN 0xFF - -/* interleaving available values */ -#define INTLV_NATIVE 0x00 -#define INTLV_IN_DEPTH 0x01 -#define INTLV_UNKNOWN 0xFF - -/* code rate available values */ -#define CODE_RATE_1_2 0x00 -#define CODE_RATE_2_3 0x01 -#define CODE_RATE_3_4 0x02 -#define CODE_RATE_5_6 0x03 -#define CODE_RATE_7_8 0x04 -#define CODE_RATE_UNKNOWN 0xFF - -/* guard interval available values */ -#define GUARD_INT_1_32 0x00 -#define GUARD_INT_1_16 0x01 -#define GUARD_INT_1_8 0x02 -#define GUARD_INT_1_4 0x03 -#define GUARD_UNKNOWN 0xFF - -/* transmission mode available values */ -#define TRANS_MODE_2K 0x00 -#define TRANS_MODE_8K 0x01 -#define TRANS_MODE_4K 0x02 -#define TRANS_MODE_UNKNOWN 0xFF - -/* DVBH signalling available values */ -#define TIMESLICING_PRESENT 0x01 -#define MPE_FEC_PRESENT 0x02 - -/* tune state available */ -#define TUNE_STATUS_NOT_TUNED 0x00 -#define TUNE_STATUS_IDLE 0x01 -#define TUNE_STATUS_LOCKING 0x02 -#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 -#define TUNE_STATUS_STREAM_DETECTED 0x04 -#define TUNE_STATUS_STREAM_TUNED 0x05 -#define TUNE_STATUS_ERROR 0xFF - -/* available TS FID filter types */ -#define TS_PID_TYPE_TS 0 -#define TS_PID_TYPE_PSI_SI 1 -#define TS_PID_TYPE_MPE 2 - -/* number of echos available */ -#define MAX_ECHOS 15 - -/* Context types */ -#define CONTEXT_LNA 1010 -#define CONTEXT_ELNA_HYSTERESIS 4003 -#define CONTEXT_ELNA_GAIN 4004 -#define CONTEXT_MER_THRESHOLD 5005 -#define CONTEXT_MER_OFFSET 5006 -#define CONTEXT_IR_STATE 7000 -#define CONTEXT_TSOUT_MSB_FIRST 7004 -#define CONTEXT_TSOUT_FALLING_EDGE 7005 - -/* Configuration modes */ -#define CFG_MODE_ON 0 -#define CFG_MODE_OFF 1 -#define CFG_MODE_AUTO 2 - -struct as10x_tps { - uint8_t modulation; - uint8_t hierarchy; - uint8_t interleaving_mode; - uint8_t code_rate_HP; - uint8_t code_rate_LP; - uint8_t guard_interval; - uint8_t transmission_mode; - uint8_t DVBH_mask_HP; - uint8_t DVBH_mask_LP; - uint16_t cell_ID; -} __packed; - -struct as10x_tune_args { - /* frequency */ - uint32_t freq; - /* bandwidth */ - uint8_t bandwidth; - /* hierarchy selection */ - uint8_t hier_select; - /* constellation */ - uint8_t modulation; - /* hierarchy */ - uint8_t hierarchy; - /* interleaving mode */ - uint8_t interleaving_mode; - /* code rate */ - uint8_t code_rate; - /* guard interval */ - uint8_t guard_interval; - /* transmission mode */ - uint8_t transmission_mode; -} __packed; - -struct as10x_tune_status { - /* tune status */ - uint8_t tune_state; - /* signal strength */ - int16_t signal_strength; - /* packet error rate 10^-4 */ - uint16_t PER; - /* bit error rate 10^-4 */ - uint16_t BER; -} __packed; - -struct as10x_demod_stats { - /* frame counter */ - uint32_t frame_count; - /* Bad frame counter */ - uint32_t bad_frame_count; - /* Number of wrong bytes fixed by Reed-Solomon */ - uint32_t bytes_fixed_by_rs; - /* Averaged MER */ - uint16_t mer; - /* statistics calculation state indicator (started or not) */ - uint8_t has_started; -} __packed; - -struct as10x_ts_filter { - uint16_t pid; /* valid PID value 0x00 : 0x2000 */ - uint8_t type; /* Red TS_PID_TYPE_ values */ - uint8_t idx; /* index in filtering table */ -} __packed; - -struct as10x_register_value { - uint8_t mode; - union { - uint8_t value8; /* 8 bit value */ - uint16_t value16; /* 16 bit value */ - uint32_t value32; /* 32 bit value */ - } __packed u; -} __packed; - -struct as10x_register_addr { - /* register addr */ - uint32_t addr; - /* register mode access */ - uint8_t mode; -}; - -#endif -- cgit v1.2.3 From 4628f993bf66d595226d019e87a4baca636b71e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:24 -0300 Subject: [media] as102: add missing viterbi lock In order to get FE_HAS_SYNC, the viterbi should already be locked too. So, add the missing FE_HAS_VITERBI lock. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/as102_fe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index b272e4ea1860..ef4c3c667782 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -325,11 +325,12 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; break; case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_VITERBI; break; case TUNE_STATUS_STREAM_TUNED: *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; + FE_HAS_LOCK | FE_HAS_VITERBI; break; default: *status = TUNE_STATUS_NOT_TUNED; -- cgit v1.2.3 From 5b6aa199196220a5901c8d9cbad497fea347850a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 21:35:44 -0300 Subject: [media] as102-fe: Add a release function This is needed to free state and for dvb_detach() to be called. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/as102_fe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index ef4c3c667782..493665899565 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -407,6 +407,14 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) state->elna_cfg); } +static void as102_fe_release(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + + kfree(state); +} + + static struct dvb_frontend_ops as102_fe_ops = { .delsys = { SYS_DVBT }, .info = { @@ -436,6 +444,7 @@ static struct dvb_frontend_ops as102_fe_ops = { .read_signal_strength = as102_fe_read_signal_strength, .read_ucblocks = as102_fe_read_ucblocks, .ts_bus_ctrl = as102_fe_ts_bus_ctrl, + .release = as102_fe_release, }; struct dvb_frontend *as102_attach(const char *name, -- cgit v1.2.3 From 23d3090f8b44ab42162e99e8584445bc25b8922f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Aug 2014 05:11:13 -0300 Subject: [media] vmalloc_sg: off by one in error handling The "i--" needs to happen at the start of the loop or it will try to release something bogus (probably it will crash) and it won't release the first ->vaddr_page[]. Fixes: 7b4eeed174b7 ('[media] vmalloc_sg: make sure all pages in vmalloc area are really DMA-ready') Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-sg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 3c8cc023a5a5..3ff15f1c9d70 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -253,9 +253,11 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, return 0; out_free_pages: while (i > 0) { - void *addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); + void *addr; + i--; + addr = page_address(dma->vaddr_pages[i]); + dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); } kfree(dma->dma_addr); dma->dma_addr = NULL; -- cgit v1.2.3 From f035eb4e976ef5a059e30bc91cfd310ff030a7d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Aug 2014 03:47:14 -0300 Subject: [media] videobuf2: fix lockdep warning The following lockdep warning has been there ever since commit a517cca6b24fc54ac209e44118ec8962051662e3 one year ago: [ 403.117947] ====================================================== [ 403.117949] [ INFO: possible circular locking dependency detected ] [ 403.117953] 3.16.0-rc6-test-media #961 Not tainted [ 403.117954] ------------------------------------------------------- [ 403.117956] v4l2-ctl/15377 is trying to acquire lock: [ 403.117959] (&dev->mutex#3){+.+.+.}, at: [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.117974] [ 403.117974] but task is already holding lock: [ 403.117976] (&mm->mmap_sem){++++++}, at: [] vm_mmap_pgoff+0x6f/0xc0 [ 403.117987] [ 403.117987] which lock already depends on the new lock. [ 403.117987] [ 403.117990] [ 403.117990] the existing dependency chain (in reverse order) is: [ 403.117992] [ 403.117992] -> #1 (&mm->mmap_sem){++++++}: [ 403.117997] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118006] [] __lock_acquire+0x4d3/0xd30 [ 403.118010] [] lock_acquire+0xa7/0x160 [ 403.118014] [] might_fault+0x7c/0xb0 [ 403.118018] [] video_usercopy+0x425/0x610 [videodev] [ 403.118028] [] video_ioctl2+0x15/0x20 [videodev] [ 403.118034] [] v4l2_ioctl+0x184/0x1a0 [videodev] [ 403.118040] [] do_vfs_ioctl+0x2f0/0x4f0 [ 403.118307] [] SyS_ioctl+0x81/0xa0 [ 403.118311] [] system_call_fastpath+0x16/0x1b [ 403.118319] [ 403.118319] -> #0 (&dev->mutex#3){+.+.+.}: [ 403.118324] [] check_prevs_add+0x746/0x9f0 [ 403.118329] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118333] [] __lock_acquire+0x4d3/0xd30 [ 403.118336] [] lock_acquire+0xa7/0x160 [ 403.118340] [] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118344] [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118349] [] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118354] [] mmap_region+0x3d0/0x5d0 [ 403.118359] [] do_mmap_pgoff+0x31d/0x400 [ 403.118363] [] vm_mmap_pgoff+0x90/0xc0 [ 403.118366] [] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118369] [] SyS_mmap+0x22/0x30 [ 403.118376] [] system_call_fastpath+0x16/0x1b [ 403.118381] [ 403.118381] other info that might help us debug this: [ 403.118381] [ 403.118383] Possible unsafe locking scenario: [ 403.118383] [ 403.118385] CPU0 CPU1 [ 403.118387] ---- ---- [ 403.118388] lock(&mm->mmap_sem); [ 403.118391] lock(&dev->mutex#3); [ 403.118394] lock(&mm->mmap_sem); [ 403.118397] lock(&dev->mutex#3); [ 403.118400] [ 403.118400] *** DEADLOCK *** [ 403.118400] [ 403.118403] 1 lock held by v4l2-ctl/15377: [ 403.118405] #0: (&mm->mmap_sem){++++++}, at: [] vm_mmap_pgoff+0x6f/0xc0 [ 403.118411] [ 403.118411] stack backtrace: [ 403.118415] CPU: 0 PID: 15377 Comm: v4l2-ctl Not tainted 3.16.0-rc6-test-media #961 [ 403.118418] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013 [ 403.118420] ffffffff82a6c9d0 ffff8800af37fb00 ffffffff819916a2 ffffffff82a6c9d0 [ 403.118425] ffff8800af37fb40 ffffffff810d5715 ffff8802308e4200 0000000000000000 [ 403.118429] ffff8802308e4a48 ffff8802308e4a48 ffff8802308e4200 0000000000000001 [ 403.118433] Call Trace: [ 403.118441] [] dump_stack+0x4e/0x7a [ 403.118445] [] print_circular_bug+0x1d5/0x2a0 [ 403.118449] [] check_prevs_add+0x746/0x9f0 [ 403.118455] [] ? find_vmap_area+0x42/0x70 [ 403.118459] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118463] [] __lock_acquire+0x4d3/0xd30 [ 403.118468] [] lock_acquire+0xa7/0x160 [ 403.118472] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118476] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118480] [] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118484] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118488] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118493] [] ? mark_held_locks+0x75/0xa0 [ 403.118497] [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118502] [] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118506] [] mmap_region+0x3d0/0x5d0 [ 403.118510] [] do_mmap_pgoff+0x31d/0x400 [ 403.118513] [] vm_mmap_pgoff+0x90/0xc0 [ 403.118517] [] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118521] [] SyS_mmap+0x22/0x30 [ 403.118525] [] system_call_fastpath+0x16/0x1b The reason is that vb2_fop_mmap and vb2_fop_get_unmapped_area take the core lock while they are called with the mmap_sem semaphore held. But elsewhere in the code the core lock is taken first but calls to copy_to/from_user() can take the mmap_sem semaphore as well, potentially causing a classical A-B/B-A deadlock. However, the mmap/get_unmapped_area calls really shouldn't take the core lock at all. So what would happen if they don't take the core lock anymore? There are two situations that need to be taken into account: calling mmap while new buffers are being added and calling mmap while buffers are being deleted. The first case works almost fine without a lock: in all cases mmap relies on correctly filled-in q->num_buffers/q->num_planes values and those are only updated by reqbufs and create_buffers *after* any new buffers have been initialized completely. Except in one case: if an error occurred while allocating the buffers it will increase num_buffers and rely on __vb2_queue_free to decrease it again. So there is a short period where the buffer information may be wrong. The second case definitely does pose a problem: buffers may be in the process of being deleted, without the internal structure being updated. In order to fix this a new mutex is added to vb2_queue that is taken when buffers are allocated or deleted, and in vb2_mmap. That way vb2_mmap won't get stale buffer data. Note that this is a problem only for MEMORY_MMAP, so even though __qbuf_userptr and __qbuf_dmabuf also mess around with buffers (mem_priv in particular), this doesn't clash with vb2_mmap or vb2_get_unmapped_area since those are MMAP specific. As an additional bonus the hack in __buf_prepare, the USERPTR case, can be removed as well since mmap() no longer takes the core lock. All in all a much cleaner solution. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 56 +++++++++++--------------------- include/media/videobuf2-core.h | 2 ++ 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index c359006074a8..eb86913349fc 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * We already have buffers allocated, so first check if they * are not in use and can be freed. */ + mutex_lock(&q->mmap_lock); if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { + mutex_unlock(&q->mmap_lock); dprintk(1, "memory in use, cannot free\n"); return -EBUSY; } @@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ __vb2_queue_cancel(q); ret = __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ } + mutex_lock(&q->mmap_lock); q->num_buffers = allocated_buffers; if (ret < 0) { @@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return ret; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers @@ -1061,6 +1067,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ } + mutex_lock(&q->mmap_lock); q->num_buffers += allocated_buffers; if (ret < 0) { @@ -1069,8 +1076,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return -ENOMEM; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers @@ -1582,7 +1591,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - struct rw_semaphore *mmap_sem; int ret; ret = __verify_length(vb, b); @@ -1619,26 +1627,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = __qbuf_mmap(vb, b); break; case V4L2_MEMORY_USERPTR: - /* - * In case of user pointer buffers vb2 allocators need to get - * direct access to userspace pages. This requires getting - * the mmap semaphore for read access in the current process - * structure. The same semaphore is taken before calling mmap - * operation, while both qbuf/prepare_buf and mmap are called - * by the driver or v4l2 core with the driver's lock held. - * To avoid an AB-BA deadlock (mmap_sem then driver's lock in - * mmap and driver's lock then mmap_sem in qbuf/prepare_buf), - * the videobuf2 core releases the driver's lock, takes - * mmap_sem and then takes the driver's lock again. - */ - mmap_sem = ¤t->mm->mmap_sem; - call_void_qop(q, wait_prepare, q); - down_read(mmap_sem); - call_void_qop(q, wait_finish, q); - ret = __qbuf_userptr(vb, b); - - up_read(mmap_sem); break; case V4L2_MEMORY_DMABUF: ret = __qbuf_dmabuf(vb, b); @@ -2485,7 +2474,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return -EINVAL; } + mutex_lock(&q->mmap_lock); ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -2504,6 +2495,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, unsigned long off = pgoff << PAGE_SHIFT; struct vb2_buffer *vb; unsigned int buffer, plane; + void *vaddr; int ret; if (q->memory != V4L2_MEMORY_MMAP) { @@ -2520,7 +2512,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, vb = q->bufs[buffer]; - return (unsigned long)vb2_plane_vaddr(vb, plane); + vaddr = vb2_plane_vaddr(vb, plane); + return vaddr ? (unsigned long)vaddr : -EINVAL; } EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); #endif @@ -2660,6 +2653,7 @@ int vb2_queue_init(struct vb2_queue *q) INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); + mutex_init(&q->mmap_lock); init_waitqueue_head(&q->done_wq); if (q->buf_struct_size == 0) @@ -2681,7 +2675,9 @@ void vb2_queue_release(struct vb2_queue *q) { __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); + mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_queue_release); @@ -3346,15 +3342,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int err; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - err = vb2_mmap(vdev->queue, vma); - if (lock) - mutex_unlock(lock); - return err; + return vb2_mmap(vdev->queue, vma); } EXPORT_SYMBOL_GPL(vb2_fop_mmap); @@ -3473,15 +3462,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int ret; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); - if (lock) - mutex_unlock(lock); - return ret; + return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); } EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area); #endif diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index fc910a622451..5a10d8d695b4 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -366,6 +366,7 @@ struct v4l2_fh; * cannot be started unless at least this number of buffers * have been queued into the driver. * + * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped * @memory: current memory type used * @bufs: videobuf buffer structures * @num_buffers: number of allocated/used buffers @@ -399,6 +400,7 @@ struct vb2_queue { u32 min_buffers_needed; /* private: internal use only */ + struct mutex mmap_lock; enum v4l2_memory memory; struct vb2_buffer *bufs[VIDEO_MAX_FRAME]; unsigned int num_buffers; -- cgit v1.2.3 From 83acb75d0dd37bd2eb24168f26d01c747ece3fc7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Aug 2014 04:38:09 -0300 Subject: [media] DocBook media: fix order of v4l2_edid fields The order of the last two fields in the G/S_EDID specification was swapped from what is in the actual struct. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-g-edid.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml index ce4563b87131..fa91651978e0 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml @@ -124,18 +124,18 @@ maximum number of blocks as defined by the standard). When you set the EDID and blocks is 0, then the EDID is disabled or erased. - - __u8 * - edid - Pointer to memory that contains the EDID. The minimum size is - blocks * 128. - __u32 reserved[5] Reserved for future extensions. Applications and drivers must set the array to zero. + + __u8 * + edid + Pointer to memory that contains the EDID. The minimum size is + blocks * 128. + -- cgit v1.2.3 From 0821344d9e805912f1971c58318547ea62984321 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Aug 2014 09:59:02 -0300 Subject: [media] vb2: use pr_info instead of pr_debug Modern kernels enable dynamic printk support, which is fine, except when it is combined with a debug module option. Enabling debug in videobuf2-core now produces no debugging unless it is also enabled through the dynamic printk support in debugfs. Either use a debug module option + pr_info, or use pr_debug without a debug module option. In this case the fact that you can set various debug levels is very useful, so I believe that for videobuf2-core.c we should use pr_info. The mix of the two is very confusing: I've spent too much time already trying to figure out why I am not seeing any debug output in the kernel log when I do: echo 1 >/sys/modules/videobuf2_core/parameters/debug Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index eb86913349fc..5b808e25fc09 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -36,7 +36,7 @@ module_param(debug, int, 0644); #define dprintk(level, fmt, arg...) \ do { \ if (debug >= level) \ - pr_debug("vb2: %s: " fmt, __func__, ## arg); \ + pr_info("vb2: %s: " fmt, __func__, ## arg); \ } while (0) #ifdef CONFIG_VIDEO_ADV_DEBUG -- cgit v1.2.3 From d720b7aff6481b99a42d484383d7e19d86323b5d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 12:19:12 -0300 Subject: [media] cx25840: Spelling s/compuations/computations/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index e6588ee5bdb0..4cf8f18bf097 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -224,7 +224,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { -- cgit v1.2.3 From 43e9d4ab0c14ccff3ed27f8e43274571e286f0ed Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 12:19:13 -0300 Subject: [media] cx23885: Spelling s/compuations/computations/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23888-ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 2c951dec2d33..c2ff5fc01157 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -263,7 +263,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { -- cgit v1.2.3 From 6af6e9c84fcc8f86b15be607a9ae8afd1d1686ea Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 10 Aug 2014 06:41:31 -0300 Subject: [media] saa6752hs: Convert to devm_kzalloc() Using the managed function the kfree() calls can be removed from the probe error path and the remove handler. Signed-off-by: Axel Lin Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa6752hs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 04e9e55018a5..4024ea6f1371 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -660,7 +660,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = { static int saa6752hs_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + struct saa6752hs_state *h; struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; u8 addr = 0x13; @@ -668,6 +668,8 @@ static int saa6752hs_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + + h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL); if (h == NULL) return -ENOMEM; sd = &h->sd; @@ -752,7 +754,6 @@ static int saa6752hs_probe(struct i2c_client *client, int err = hdl->error; v4l2_ctrl_handler_free(hdl); - kfree(h); return err; } v4l2_ctrl_cluster(3, &h->video_bitrate_mode); @@ -767,7 +768,6 @@ static int saa6752hs_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&to_state(sd)->hdl); - kfree(to_state(sd)); return 0; } -- cgit v1.2.3 From c8fa50549dc6e717e0941ee7092a973388253c7a Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Sun, 10 Aug 2014 17:30:18 -0300 Subject: [media] drivers: media: pci: Makefile: Remove duplicate subdirectory from obj-y In the list of subdirectories compiled, b2c2/ appears twice. This patch removes one of the appearances. Signed-off-by: Andreas Ruprecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index e5b53fb569ef..dc2ebbe27306 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -10,7 +10,6 @@ obj-y += ttpci/ \ mantis/ \ ngene/ \ ddbridge/ \ - b2c2/ \ saa7146/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -- cgit v1.2.3 From 63ddf68de52efaac40a9287e44266ac30e71dd36 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 11 Aug 2014 18:42:22 -0300 Subject: [media] usbtv: add audio support Add an ALSA handler inside usbtv module, in order to make audio to work with those devices. Signed-off-by: Federico Simoncelli Tested-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/Makefile | 3 +- drivers/media/usb/usbtv/usbtv-audio.c | 384 ++++++++++++++++++++++++++++++++++ drivers/media/usb/usbtv/usbtv-core.c | 16 +- drivers/media/usb/usbtv/usbtv-video.c | 9 +- drivers/media/usb/usbtv/usbtv.h | 21 +- 5 files changed, 423 insertions(+), 10 deletions(-) create mode 100644 drivers/media/usb/usbtv/usbtv-audio.c diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile index 775316a88ea6..f555cf8a3dd2 100644 --- a/drivers/media/usb/usbtv/Makefile +++ b/drivers/media/usb/usbtv/Makefile @@ -1,4 +1,5 @@ usbtv-y := usbtv-core.o \ - usbtv-video.o + usbtv-video.o \ + usbtv-audio.o obj-$(CONFIG_VIDEO_USBTV) += usbtv.o diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c new file mode 100644 index 000000000000..2d8795f683bf --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -0,0 +1,384 @@ +/* + * Fushicai USBTV007 Audio-Video Grabber Driver + * + * Product web site: + * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html + * + * Copyright (c) 2013 Federico Simoncelli + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + */ + +#include +#include +#include +#include + +#include "usbtv.h" + +static struct snd_pcm_hardware snd_usbtv_digital_hw = { + .info = SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 11059, + .period_bytes_max = 13516, + .periods_min = 2, + .periods_max = 98, + .buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */ +}; + +static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + chip->snd_substream = substream; + runtime->hw = snd_usbtv_digital_hw; + + return 0; +} + +static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + if (atomic_read(&chip->snd_stream)) { + atomic_set(&chip->snd_stream, 0); + schedule_work(&chip->snd_trigger); + } + + return 0; +} + +static int snd_usbtv_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int rv; + struct usbtv *chip = snd_pcm_substream_chip(substream); + + rv = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + if (rv < 0) { + dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n", + rv); + return rv; + } + + return 0; +} + +static int snd_usbtv_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + return 0; +} + +static int snd_usbtv_prepare(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + chip->snd_buffer_pos = 0; + chip->snd_period_pos = 0; + + return 0; +} + +static void usbtv_audio_urb_received(struct urb *urb) +{ + struct usbtv *chip = urb->context; + struct snd_pcm_substream *substream = chip->snd_substream; + struct snd_pcm_runtime *runtime = substream->runtime; + size_t i, frame_bytes, chunk_length, buffer_pos, period_pos; + int period_elapsed; + void *urb_current; + + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ENOENT: + case -EPROTO: + case -ECONNRESET: + case -ESHUTDOWN: + return; + default: + dev_warn(chip->dev, "unknown audio urb status %i\n", + urb->status); + } + + if (!atomic_read(&chip->snd_stream)) + return; + + frame_bytes = runtime->frame_bits >> 3; + chunk_length = USBTV_CHUNK / frame_bytes; + + buffer_pos = chip->snd_buffer_pos; + period_pos = chip->snd_period_pos; + period_elapsed = 0; + + for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) { + urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE; + + if (buffer_pos + chunk_length >= runtime->buffer_size) { + size_t cnt = (runtime->buffer_size - buffer_pos) * + frame_bytes; + memcpy(runtime->dma_area + buffer_pos * frame_bytes, + urb_current, cnt); + memcpy(runtime->dma_area, urb_current + cnt, + chunk_length * frame_bytes - cnt); + } else { + memcpy(runtime->dma_area + buffer_pos * frame_bytes, + urb_current, chunk_length * frame_bytes); + } + + buffer_pos += chunk_length; + period_pos += chunk_length; + + if (buffer_pos >= runtime->buffer_size) + buffer_pos -= runtime->buffer_size; + + if (period_pos >= runtime->period_size) { + period_pos -= runtime->period_size; + period_elapsed = 1; + } + } + + snd_pcm_stream_lock(substream); + + chip->snd_buffer_pos = buffer_pos; + chip->snd_period_pos = period_pos; + + snd_pcm_stream_unlock(substream); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int usbtv_audio_start(struct usbtv *chip) +{ + unsigned int pipe; + static const u16 setup[][2] = { + /* These seem to enable the device. */ + { USBTV_BASE + 0x0008, 0x0001 }, + { USBTV_BASE + 0x01d0, 0x00ff }, + { USBTV_BASE + 0x01d9, 0x0002 }, + + { USBTV_BASE + 0x01da, 0x0013 }, + { USBTV_BASE + 0x01db, 0x0012 }, + { USBTV_BASE + 0x01e9, 0x0002 }, + { USBTV_BASE + 0x01ec, 0x006c }, + { USBTV_BASE + 0x0294, 0x0020 }, + { USBTV_BASE + 0x0255, 0x00cf }, + { USBTV_BASE + 0x0256, 0x0020 }, + { USBTV_BASE + 0x01eb, 0x0030 }, + { USBTV_BASE + 0x027d, 0x00a6 }, + { USBTV_BASE + 0x0280, 0x0011 }, + { USBTV_BASE + 0x0281, 0x0040 }, + { USBTV_BASE + 0x0282, 0x0011 }, + { USBTV_BASE + 0x0283, 0x0040 }, + { 0xf891, 0x0010 }, + + /* this sets the input from composite */ + { USBTV_BASE + 0x0284, 0x00aa }, + }; + + chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (chip->snd_bulk_urb == NULL) + goto err_alloc_urb; + + pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP); + + chip->snd_bulk_urb->transfer_buffer = kzalloc( + USBTV_AUDIO_URBSIZE, GFP_KERNEL); + if (chip->snd_bulk_urb->transfer_buffer == NULL) + goto err_transfer_buffer; + + usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe, + chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE, + usbtv_audio_urb_received, chip); + + /* starting the stream */ + usbtv_set_regs(chip, setup, ARRAY_SIZE(setup)); + + usb_clear_halt(chip->udev, pipe); + usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC); + + return 0; + +err_transfer_buffer: + usb_free_urb(chip->snd_bulk_urb); + chip->snd_bulk_urb = NULL; + +err_alloc_urb: + return -ENOMEM; +} + +static int usbtv_audio_stop(struct usbtv *chip) +{ + static const u16 setup[][2] = { + /* The original windows driver sometimes sends also: + * { USBTV_BASE + 0x00a2, 0x0013 } + * but it seems useless and its real effects are untested at + * the moment. + */ + { USBTV_BASE + 0x027d, 0x0000 }, + { USBTV_BASE + 0x0280, 0x0010 }, + { USBTV_BASE + 0x0282, 0x0010 }, + }; + + if (chip->snd_bulk_urb) { + usb_kill_urb(chip->snd_bulk_urb); + kfree(chip->snd_bulk_urb->transfer_buffer); + usb_free_urb(chip->snd_bulk_urb); + chip->snd_bulk_urb = NULL; + } + + usbtv_set_regs(chip, setup, ARRAY_SIZE(setup)); + + return 0; +} + +void usbtv_audio_suspend(struct usbtv *usbtv) +{ + if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb) + usb_kill_urb(usbtv->snd_bulk_urb); +} + +void usbtv_audio_resume(struct usbtv *usbtv) +{ + if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb) + usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC); +} + +static void snd_usbtv_trigger(struct work_struct *work) +{ + struct usbtv *chip = container_of(work, struct usbtv, snd_trigger); + + if (atomic_read(&chip->snd_stream)) + usbtv_audio_start(chip); + else + usbtv_audio_stop(chip); +} + +static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + atomic_set(&chip->snd_stream, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + atomic_set(&chip->snd_stream, 0); + break; + default: + return -EINVAL; + } + + schedule_work(&chip->snd_trigger); + + return 0; +} + +static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + return chip->snd_buffer_pos; +} + +static struct snd_pcm_ops snd_usbtv_pcm_ops = { + .open = snd_usbtv_pcm_open, + .close = snd_usbtv_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_usbtv_hw_params, + .hw_free = snd_usbtv_hw_free, + .prepare = snd_usbtv_prepare, + .trigger = snd_usbtv_card_trigger, + .pointer = snd_usbtv_pointer, +}; + +int usbtv_audio_init(struct usbtv *usbtv) +{ + int rv; + struct snd_card *card; + struct snd_pcm *pcm; + + INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger); + atomic_set(&usbtv->snd_stream, 0); + + rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv", + THIS_MODULE, 0, &card); + if (rv < 0) + return rv; + + strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver)); + strlcpy(card->shortname, "usbtv", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum, + usbtv->udev->devnum); + + snd_card_set_dev(card, usbtv->dev); + + usbtv->snd = card; + + rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm); + if (rv < 0) + goto err; + + strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name)); + pcm->info_flags = 0; + pcm->private_data = usbtv; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER, + USBTV_AUDIO_BUFFER); + + rv = snd_card_register(card); + if (rv) + goto err; + + return 0; + +err: + usbtv->snd = NULL; + snd_card_free(card); + + return rv; +} + +void usbtv_audio_free(struct usbtv *usbtv) +{ + if (usbtv->snd && usbtv->udev) { + snd_card_free(usbtv->snd); + usbtv->snd = NULL; + } +} diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 473fab81b602..bf25ecf143a2 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Product web site: * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html @@ -84,12 +84,19 @@ static int usbtv_probe(struct usb_interface *intf, if (ret < 0) goto usbtv_video_fail; + ret = usbtv_audio_init(usbtv); + if (ret < 0) + goto usbtv_audio_fail; + /* for simplicity we exploit the v4l2_device reference counting */ v4l2_device_get(&usbtv->v4l2_dev); - dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); + dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n"); return 0; +usbtv_audio_fail: + usbtv_video_free(usbtv); + usbtv_video_fail: usb_set_intfdata(intf, NULL); usb_put_dev(usbtv->udev); @@ -106,6 +113,7 @@ static void usbtv_disconnect(struct usb_interface *intf) if (!usbtv) return; + usbtv_audio_free(usbtv); usbtv_video_free(usbtv); usb_put_dev(usbtv->udev); @@ -122,8 +130,8 @@ static struct usb_device_id usbtv_id_table[] = { }; MODULE_DEVICE_TABLE(usb, usbtv_id_table); -MODULE_AUTHOR("Lubomir Rintel"); -MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); +MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli"); +MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct usb_driver usbtv_usb_driver = { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 030c5854b4b3..692c7188a8a6 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Product web site: * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html @@ -79,7 +79,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input) { USBTV_BASE + 0x011f, 0x00f2 }, { USBTV_BASE + 0x0127, 0x0060 }, { USBTV_BASE + 0x00ae, 0x0010 }, - { USBTV_BASE + 0x0284, 0x00aa }, { USBTV_BASE + 0x0239, 0x0060 }, }; @@ -88,7 +87,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input) { USBTV_BASE + 0x011f, 0x00ff }, { USBTV_BASE + 0x0127, 0x0060 }, { USBTV_BASE + 0x00ae, 0x0030 }, - { USBTV_BASE + 0x0284, 0x0088 }, { USBTV_BASE + 0x0239, 0x0060 }, }; @@ -225,7 +223,6 @@ static int usbtv_setup_capture(struct usbtv *usbtv) { USBTV_BASE + 0x0159, 0x0006 }, { USBTV_BASE + 0x015d, 0x0000 }, - { USBTV_BASE + 0x0284, 0x0088 }, { USBTV_BASE + 0x0003, 0x0004 }, { USBTV_BASE + 0x0100, 0x00d3 }, { USBTV_BASE + 0x0115, 0x0015 }, @@ -434,6 +431,8 @@ static int usbtv_start(struct usbtv *usbtv) int i; int ret; + usbtv_audio_suspend(usbtv); + ret = usb_set_interface(usbtv->udev, 0, 0); if (ret < 0) return ret; @@ -446,6 +445,8 @@ static int usbtv_start(struct usbtv *usbtv) if (ret < 0) return ret; + usbtv_audio_resume(usbtv); + for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { struct urb *ip; diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h index cb1d388cc647..968119581fab 100644 --- a/drivers/media/usb/usbtv/usbtv.h +++ b/drivers/media/usb/usbtv/usbtv.h @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Copyright (c) 2013 Lubomir Rintel * All rights reserved. @@ -28,6 +28,7 @@ /* Hardware. */ #define USBTV_VIDEO_ENDP 0x81 +#define USBTV_AUDIO_ENDP 0x83 #define USBTV_BASE 0xc000 #define USBTV_REQUEST_REG 12 @@ -39,6 +40,10 @@ #define USBTV_CHUNK_SIZE 256 #define USBTV_CHUNK 240 +#define USBTV_AUDIO_URBSIZE 20480 +#define USBTV_AUDIO_HDRSIZE 4 +#define USBTV_AUDIO_BUFFER 65536 + /* Chunk header. */ #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ == 0x88000000) @@ -91,9 +96,23 @@ struct usbtv { int iso_size; unsigned int sequence; struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; + + /* audio */ + struct snd_card *snd; + struct snd_pcm_substream *snd_substream; + atomic_t snd_stream; + struct work_struct snd_trigger; + struct urb *snd_bulk_urb; + size_t snd_buffer_pos; + size_t snd_period_pos; }; int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size); int usbtv_video_init(struct usbtv *usbtv); void usbtv_video_free(struct usbtv *usbtv); + +int usbtv_audio_init(struct usbtv *usbtv); +void usbtv_audio_free(struct usbtv *usbtv); +void usbtv_audio_suspend(struct usbtv *usbtv); +void usbtv_audio_resume(struct usbtv *usbtv); -- cgit v1.2.3 From d4b32646468088323f27a7788ce3b07191015142 Mon Sep 17 00:00:00 2001 From: Vitaly Osipov Date: Thu, 5 Jun 2014 04:07:48 -0300 Subject: [media] staging: omap4iss: copy paste error in iss_get_clocks It makes more sense to return PTR_ERR(iss->iss_ctrlclk) here. The current code looks like an oversight in pasting the block just above this one. Signed-off-by: Vitaly Osipov Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index d548371db65a..8a23d164e847 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -1014,6 +1014,7 @@ static int iss_get_clocks(struct iss_device *iss) iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk"); if (IS_ERR(iss->iss_ctrlclk)) { dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); + iss_put_clocks(iss); return PTR_ERR(iss->iss_ctrlclk); } -- cgit v1.2.3 From 0d8053f2ace52c816800193d705ea82a2ffd6dc8 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 14:56:01 -0300 Subject: [media] imon: Define keytables per USB Device Id This patch defines the keytables per USB Device ID. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 266 +++++++++++++++++++++++++++++++----------------- 1 file changed, 173 insertions(+), 93 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7115e68ba697..3fc759537cc6 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -87,6 +87,18 @@ static ssize_t lcd_write(struct file *file, const char __user *buf, /*** G L O B A L S ***/ +struct imon_panel_key_table { + u64 hw_code; + u32 keycode; +}; + +struct imon_usb_dev_descr { + __u16 flags; +#define IMON_NO_FLAGS 0 +#define IMON_NEED_20MS_PKT_DELAY 1 + struct imon_panel_key_table key_table[]; +}; + struct imon_context { struct device *dev; /* Newer devices have two interfaces */ @@ -150,6 +162,8 @@ struct imon_context { struct timer_list ttimer; /* touch screen timer */ int touch_x; /* x coordinate on touchscreen */ int touch_y; /* y coordinate on touchscreen */ + struct imon_usb_dev_descr *dev_descr; /* device description with key + table for front panels */ }; #define TOUCH_TIMEOUT (HZ/30) @@ -186,8 +200,111 @@ enum { IMON_KEY_PANEL = 2, }; -enum { - IMON_NEED_20MS_PKT_DELAY = 1 +static struct usb_class_driver imon_vfd_class = { + .name = DEVICE_NAME, + .fops = &vfd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +static struct usb_class_driver imon_lcd_class = { + .name = DEVICE_NAME, + .fops = &lcd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +/* imon receiver front panel/knob key table */ +static const struct imon_usb_dev_descr imon_default_table = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002000ffeell, KEY_VIDEO }, + { 0x000000002100ffeell, KEY_CAMERA }, + { 0x000000002700ffeell, KEY_DVD }, + { 0x000000002300ffeell, KEY_TV }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } +}; + +static const struct imon_usb_dev_descr imon_OEM_VFD = { + .flags = IMON_NEED_20MS_PKT_DELAY, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } }; /* @@ -208,7 +325,8 @@ static struct usb_device_id imon_usb_id_table[] = { * SoundGraph iMON PAD (IR & LCD) * SoundGraph iMON Knob (IR only) */ - { USB_DEVICE(0x15c2, 0xffdc) }, + { USB_DEVICE(0x15c2, 0xffdc), + .driver_info = (unsigned long)&imon_default_table }, /* * Newer devices, all driven by the latest iMON Windows driver, full @@ -216,43 +334,62 @@ static struct usb_device_id imon_usb_id_table[] = { * Need user input to fill in details on unknown devices. */ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0034) }, + { USB_DEVICE(0x15c2, 0x0034), + .driver_info = (unsigned long)&imon_default_table }, /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0035) }, + { USB_DEVICE(0x15c2, 0x0035), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY }, + { USB_DEVICE(0x15c2, 0x0036), + .driver_info = (unsigned long)&imon_OEM_VFD }, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0037) }, + { USB_DEVICE(0x15c2, 0x0037), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM LCD (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0038) }, + { USB_DEVICE(0x15c2, 0x0038), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON UltraBay (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0039) }, + { USB_DEVICE(0x15c2, 0x0039), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003a) }, + { USB_DEVICE(0x15c2, 0x003a), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003b) }, + { USB_DEVICE(0x15c2, 0x003b), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM Inside (IR only) */ - { USB_DEVICE(0x15c2, 0x003c) }, + { USB_DEVICE(0x15c2, 0x003c), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003d) }, + { USB_DEVICE(0x15c2, 0x003d), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003e) }, + { USB_DEVICE(0x15c2, 0x003e), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003f) }, + { USB_DEVICE(0x15c2, 0x003f), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0040) }, + { USB_DEVICE(0x15c2, 0x0040), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON MINI (IR only) */ - { USB_DEVICE(0x15c2, 0x0041) }, + { USB_DEVICE(0x15c2, 0x0041), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station EZ External (IR only) */ - { USB_DEVICE(0x15c2, 0x0042) }, + { USB_DEVICE(0x15c2, 0x0042), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Basic Internal (IR only) */ - { USB_DEVICE(0x15c2, 0x0043) }, + { USB_DEVICE(0x15c2, 0x0043), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Elite (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0044) }, + { USB_DEVICE(0x15c2, 0x0044), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Premiere (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0045) }, + { USB_DEVICE(0x15c2, 0x0045), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0046) }, + { USB_DEVICE(0x15c2, 0x0046), + .driver_info = (unsigned long)&imon_default_table}, {} }; @@ -266,67 +403,6 @@ static struct usb_driver imon_driver = { .id_table = imon_usb_id_table, }; -static struct usb_class_driver imon_vfd_class = { - .name = DEVICE_NAME, - .fops = &vfd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -static struct usb_class_driver imon_lcd_class = { - .name = DEVICE_NAME, - .fops = &lcd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -/* imon receiver front panel/knob key table */ -static const struct { - u64 hw_code; - u32 keycode; -} imon_panel_key_table[] = { - { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ - { 0x000000001200ffeell, KEY_UP }, - { 0x000000001300ffeell, KEY_DOWN }, - { 0x000000001400ffeell, KEY_LEFT }, - { 0x000000001500ffeell, KEY_RIGHT }, - { 0x000000001600ffeell, KEY_ENTER }, - { 0x000000001700ffeell, KEY_ESC }, - { 0x000000001f00ffeell, KEY_AUDIO }, - { 0x000000002000ffeell, KEY_VIDEO }, - { 0x000000002100ffeell, KEY_CAMERA }, - { 0x000000002700ffeell, KEY_DVD }, - { 0x000000002300ffeell, KEY_TV }, - { 0x000000002b00ffeell, KEY_EXIT }, - { 0x000000002c00ffeell, KEY_SELECT }, - { 0x000000002d00ffeell, KEY_MENU }, - { 0x000000000500ffeell, KEY_PREVIOUS }, - { 0x000000000700ffeell, KEY_REWIND }, - { 0x000000000400ffeell, KEY_STOP }, - { 0x000000003c00ffeell, KEY_PLAYPAUSE }, - { 0x000000000800ffeell, KEY_FASTFORWARD }, - { 0x000000000600ffeell, KEY_NEXT }, - { 0x000000010000ffeell, KEY_RIGHT }, - { 0x000001000000ffeell, KEY_LEFT }, - { 0x000000003d00ffeell, KEY_SELECT }, - { 0x000100000000ffeell, KEY_VOLUMEUP }, - { 0x010000000000ffeell, KEY_VOLUMEDOWN }, - { 0x000000000100ffeell, KEY_MUTE }, - /* 0xffdc iMON MCE VFD */ - { 0x00010000ffffffeell, KEY_VOLUMEUP }, - { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, - { 0x00000001ffffffeell, KEY_MUTE }, - { 0x0000000fffffffeell, KEY_MEDIA }, - { 0x00000012ffffffeell, KEY_UP }, - { 0x00000013ffffffeell, KEY_DOWN }, - { 0x00000014ffffffeell, KEY_LEFT }, - { 0x00000015ffffffeell, KEY_RIGHT }, - { 0x00000016ffffffeell, KEY_ENTER }, - { 0x00000017ffffffeell, KEY_ESC }, - /* iMON Knob values */ - { 0x000100ffffffffeell, KEY_VOLUMEUP }, - { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, - { 0x000008ffffffffeell, KEY_MUTE }, -}; - /* to prevent races between open() and disconnect(), probing, etc */ static DEFINE_MUTEX(driver_lock); @@ -1210,18 +1286,19 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) return keycode; } -static u32 imon_panel_key_lookup(u64 code) +static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code) { int i; u32 keycode = KEY_RESERVED; + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - if (imon_panel_key_table[i].hw_code == (code | 0xffee)) { - keycode = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + if (key_table[i].hw_code == (code | 0xffee)) { + keycode = key_table[i].keycode; break; } } - + ictx->release_code = false; return keycode; } @@ -1511,7 +1588,7 @@ static void imon_incoming_packet(struct imon_context *ictx, if (len == 8 && buf[7] == 0xee) { scancode = be64_to_cpu(*((u64 *)buf)); ktype = IMON_KEY_PANEL; - kc = imon_panel_key_lookup(scancode); + kc = imon_panel_key_lookup(ictx, scancode); } else { scancode = be32_to_cpu(*((u32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { @@ -1908,6 +1985,7 @@ out: static struct input_dev *imon_init_idev(struct imon_context *ictx) { + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; struct input_dev *idev; int ret, i; @@ -1933,8 +2011,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) BIT_MASK(REL_WHEEL); /* panel and/or knob code support */ - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - u32 kc = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + u32 kc = key_table[i].keycode; __set_bit(kc, idev->keybit); } @@ -2135,9 +2213,11 @@ 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); + /* save drive info for later accessing the panel/knob key table */ + ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info; /* 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; + ictx->send_packet_delay = ictx->dev_descr->flags & + IMON_NEED_20MS_PKT_DELAY ? 20 : 5; ret = -ENODEV; iface_desc = intf->cur_altsetting; -- cgit v1.2.3 From 7b5fc0714976aec5db5c4f8c66f12b23f5049b97 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 14:59:07 -0300 Subject: [media] imon: Add internal key table for 15c2:0034 Add the key table for the Thermaltake DH-102 to the USB-Id 15c2:0034. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3fc759537cc6..c91e9709b47e 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -307,6 +307,27 @@ static const struct imon_usb_dev_descr imon_OEM_VFD = { } }; +/* imon receiver front panel/knob key table for DH102*/ +static const struct imon_usb_dev_descr imon_DH102 = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000010000ffeell, KEY_MUTE }, + { 0x0000000f0000ffeell, KEY_MEDIA }, + { 0x000000120000ffeell, KEY_UP }, + { 0x000000130000ffeell, KEY_DOWN }, + { 0x000000140000ffeell, KEY_LEFT }, + { 0x000000150000ffeell, KEY_RIGHT }, + { 0x000000160000ffeell, KEY_ENTER }, + { 0x000000170000ffeell, KEY_ESC }, + { 0x0000002b0000ffeell, KEY_EXIT }, + { 0x0000002c0000ffeell, KEY_SELECT }, + { 0x0000002d0000ffeell, KEY_MENU }, + { 0, KEY_RESERVED } + } +}; + /* * USB Device ID for iMON USB Control Boards * @@ -335,7 +356,7 @@ static struct usb_device_id imon_usb_id_table[] = { */ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0034), - .driver_info = (unsigned long)&imon_default_table }, + .driver_info = (unsigned long)&imon_DH102 }, /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0035), .driver_info = (unsigned long)&imon_default_table}, -- cgit v1.2.3 From 6ddc2be511a76e6c3f689f46155cb0f4c8f5876e Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 15:01:12 -0300 Subject: [media] imon: Fix not working front panel Make the front panel buttons working after another button on the remote was pressed. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index c91e9709b47e..3d8f515be3c1 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1610,6 +1610,7 @@ static void imon_incoming_packet(struct imon_context *ictx, scancode = be64_to_cpu(*((u64 *)buf)); ktype = IMON_KEY_PANEL; kc = imon_panel_key_lookup(ictx, scancode); + ictx->release_code = false; } else { scancode = be32_to_cpu(*((u32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { -- cgit v1.2.3 From 6e533c01a89fbb8b1a5c58808540e798e2dad645 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Aug 2014 03:52:08 -0300 Subject: [media] v4l: Event documentation fixes Constify event type constants and correct motion detection event number (it's 6, not 5). Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-dqevent.xml | 7 ++++--- Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index cb7732582f03..b036f8963353 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -76,21 +76,22 @@ &v4l2-event-vsync; vsync - Event data for event V4L2_EVENT_VSYNC. + Event data for event V4L2_EVENT_VSYNC. &v4l2-event-ctrl; ctrl - Event data for event V4L2_EVENT_CTRL. + Event data for event V4L2_EVENT_CTRL. &v4l2-event-frame-sync; frame_sync - Event data for event V4L2_EVENT_FRAME_SYNC. + Event data for event + V4L2_EVENT_FRAME_SYNC. diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 9f6095608837..d7c9365ecdbe 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -176,7 +176,7 @@ V4L2_EVENT_MOTION_DET - 5 + 6 Triggered whenever the motion detection state for one or more of the regions changes. This event has a &v4l2-event-motion-det; associated with it. -- cgit v1.2.3 From 4721b3eb662ca5ea60a636f0f190f2fd2ac5df14 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 02:58:40 -0300 Subject: [media] ov7670: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index cdd7c1b7259b..dd3db2458a4f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -19,6 +19,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jonathan Corbet "); @@ -29,19 +30,6 @@ static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -/* - * Basic window sizes. These probably belong somewhere more globally - * useful. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - /* * The 7670 sits on i2c with ID 0x42 */ -- cgit v1.2.3 From 37096b476b45e60b2b264d0b517089b47cb9374b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 02:59:44 -0300 Subject: [media] vs6624: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/vs6624.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 23f4f65fccd7..373f2df52492 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -30,22 +30,10 @@ #include #include #include +#include #include "vs6624_regs.h" -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define QQVGA_WIDTH 160 -#define QQVGA_HEIGHT 120 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 -#define QQCIF_WIDTH 88 -#define QQCIF_HEIGHT 72 - #define MAX_FRAME_RATE 30 struct vs6624 { -- cgit v1.2.3 From 665152a4fb9f60df1c28cee8ab2634a6533edb9c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:00:44 -0300 Subject: [media] soc_camera: mt9t112: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9t112.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 46f431a13782..996d7b4007a5 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -29,6 +29,7 @@ #include #include #include +#include /* you can check PLL/clock info */ /* #define EXT_CLOCK 24000000 */ @@ -42,9 +43,6 @@ #define MAX_WIDTH 2048 #define MAX_HEIGHT 1536 -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - /* * macro of read/write */ -- cgit v1.2.3 From a14e55190b8ac8305870ed9f7b5e1375ed870a34 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:01:39 -0300 Subject: [media] soc_camera: ov772x: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/ov772x.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 7f2b3c8926af..970a04e1e56e 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * register offset @@ -360,10 +361,6 @@ #define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ #define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 #define OV772X_MAX_WIDTH VGA_WIDTH #define OV772X_MAX_HEIGHT VGA_HEIGHT -- cgit v1.2.3 From 91ba0e59babdb3c7aca836a65f1095b3eaff7b06 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 8 Aug 2014 10:32:56 -0300 Subject: [media] tda7432: Fix setting TDA7432_MUTE bit for TDA7432_RF register Fix a copy-paste bug when converting to the control framework. Fixes: commit 5d478e0de871 ("[media] tda7432: convert to the control framework") Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 72af644fa051..cf93021a6500 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) if (t->mute->val) { lf |= TDA7432_MUTE; lr |= TDA7432_MUTE; - lf |= TDA7432_MUTE; + rf |= TDA7432_MUTE; rr |= TDA7432_MUTE; } /* Mute & update balance*/ -- cgit v1.2.3 From 7c5a62e1eee1f59a5d2c25bbd28f0929811ffefa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:19:20 -0300 Subject: [media] sh_veu: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 8dc279d4d561..be3b3bc71a0f 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #define VEU_STR 0x00 /* start register */ @@ -135,9 +136,6 @@ enum sh_veu_fmt_idx { SH_VEU_FMT_RGB24, }; -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - #define DEFAULT_IN_WIDTH VGA_WIDTH #define DEFAULT_IN_HEIGHT VGA_HEIGHT #define DEFAULT_IN_FMTIDX SH_VEU_FMT_NV12 -- cgit v1.2.3 From c0d04f4026c305eadeac6cfdffdbac5fcdf9bc60 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:20:01 -0300 Subject: [media] via-camera: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/via-camera.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index b4f9d03636e3..2ac870438493 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -48,14 +49,6 @@ MODULE_PARM_DESC(override_serial, "the XO 1.5 serial port is enabled. Set this option " "to force-enable the camera."); -/* - * Basic window sizes. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - /* * The structure describing our camera. */ -- cgit v1.2.3 From 627530c32a43283474e9dd3e954519410ffa033a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 9 Aug 2014 06:37:20 -0300 Subject: [media] em28xx-v4l: give back all active video buffers to the vb2 core properly on streaming stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a new video frame is started, the driver takes the next video buffer from the list of active buffers and moves it to dev->usb_ctl.vid_buf / dev->usb_ctl.vbi_buf for further processing. On streaming stop we currently only give back the pending buffers from the list but not the ones which are currently processed. This causes the following warning from the vb2 core since kernel 3.15: ... ------------[ cut here ]------------ WARNING: CPU: 1 PID: 2284 at drivers/media/v4l2-core/videobuf2-core.c:2115 __vb2_queue_cancel+0xed/0x150 [videobuf2_core]() [...] Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x79/0x90 [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] warn_slowpath_null+0x1d/0x20 [] __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] vb2_internal_streamoff+0x35/0x90 [videobuf2_core] [] vb2_streamoff+0x35/0x60 [videobuf2_core] [] vb2_ioctl_streamoff+0x37/0x40 [videobuf2_core] [] v4l_streamoff+0x15/0x20 [videodev] [] __video_do_ioctl+0x23d/0x2d0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] video_usercopy+0x203/0x5a0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? fsnotify+0x1e7/0x2b0 [] video_ioctl2+0x12/0x20 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] v4l2_ioctl+0xee/0x130 [videodev] [] ? v4l2_open+0xf0/0xf0 [videodev] [] do_vfs_ioctl+0x2e2/0x4d0 [] ? vfs_write+0x13c/0x1c0 [] ? vfs_writev+0x2f/0x50 [] SyS_ioctl+0x58/0x80 [] sysenter_do_call+0x12/0x12 ---[ end trace 5545f934409f13f4 ]--- ... Many thanks to Hans Verkuil, whose recently added check in the vb2 core unveiled this long standing issue and who has investigated it further. Cc: Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 90dec2955f1c..9db219d513db 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -994,13 +994,16 @@ static void em28xx_stop_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vid_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vid_buf = NULL; + } while (!list_empty(&vidq->active)) { struct em28xx_buffer *buf; buf = list_entry(vidq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vid_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); } @@ -1021,13 +1024,16 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vbi_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vbi_buf = NULL; + } while (!list_empty(&vbiq->active)) { struct em28xx_buffer *buf; buf = list_entry(vbiq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vbi_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); } -- cgit v1.2.3 From 662c97cf8f9e9d67d45d0a9f0c1565a1ede364c2 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 9 Aug 2014 06:37:21 -0300 Subject: [media] em28xx-v4l: fix video buffer field order reporting in progressive mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The correct field order in progressive mode is V4L2_FIELD_NONE, not V4L2_FIELD_INTERLACED. Cc: Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9db219d513db..f6cf99fa30b2 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -435,7 +435,10 @@ static inline void finish_buffer(struct em28xx *dev, em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++; - buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + if (dev->v4l2->progressive) + buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + else + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); -- cgit v1.2.3 From 66cae53024c4b73d40b4e78c557a73e082522aed Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 13 Aug 2014 15:52:39 -0300 Subject: [media] media: fix au0828 dvb suspend/resume to call dvb_frontend_suspend/resume au0828 doesn't resume correctly and TV tuning fails with xc_set_signal_source(0) failed message. Change au0828 dvb suspend and resume interfaces to suspend and resume frontend during suspend and resume respectively. dvb_frontend_suspend() suspends tuner and fe using tuner and fe ops. dvb_frontend_resume() resumes fe and tuner using fe and tuner ops ini before waking up the frontend. With this change HVR950Q suspend and resume work when system gets suspended when digital function is tuned to a channel and with active TV stream, and after resume it went right back to active TV stream. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 47 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 821f86e92cde..4bd9d687d2d6 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -620,34 +620,39 @@ int au0828_dvb_register(struct au0828_dev *dev) void au0828_dvb_suspend(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; + int rc; - if (dvb->frontend && dev->urb_streaming) { - pr_info("stopping DVB\n"); - - cancel_work_sync(&dev->restart_streaming); - - /* Stop transport */ - mutex_lock(&dvb->lock); - stop_urb_transfer(dev); - au0828_stop_transport(dev, 1); - mutex_unlock(&dvb->lock); - dev->need_urb_start = 1; + if (dvb->frontend) { + if (dev->urb_streaming) { + cancel_work_sync(&dev->restart_streaming); + /* Stop transport */ + mutex_lock(&dvb->lock); + stop_urb_transfer(dev); + au0828_stop_transport(dev, 1); + mutex_unlock(&dvb->lock); + dev->need_urb_start = 1; + } + /* suspend frontend - does tuner and fe to sleep */ + rc = dvb_frontend_suspend(dvb->frontend); + pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc); } } void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; + int rc; - if (dvb->frontend && dev->need_urb_start) { - pr_info("resuming DVB\n"); - - au0828_set_frontend(dvb->frontend); - - /* Start transport */ - mutex_lock(&dvb->lock); - au0828_start_transport(dev); - start_urb_transfer(dev); - mutex_unlock(&dvb->lock); + if (dvb->frontend) { + /* resume frontend - does fe and tuner init */ + rc = dvb_frontend_resume(dvb->frontend); + pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc); + if (dev->need_urb_start) { + /* Start transport */ + mutex_lock(&dvb->lock); + au0828_start_transport(dev); + start_urb_transfer(dev); + mutex_unlock(&dvb->lock); + } } } -- cgit v1.2.3 From 85c1abcb5251673d18325576f4923bb78af479de Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 15 Aug 2014 16:16:46 -0300 Subject: [media] usbtv: Make it dependent on ALSA Now that alsa code is part of the driver, it can be compiled only if alsa is enabled. drivers/built-in.o: In function `snd_usbtv_hw_free': >> usbtv-audio.c:(.text+0x21eb55): undefined reference to `snd_pcm_lib_free_pages' drivers/built-in.o: In function `snd_usbtv_hw_params': >> usbtv-audio.c:(.text+0x21eb72): undefined reference to `snd_pcm_lib_malloc_pages' drivers/built-in.o: In function `usbtv_audio_urb_received': >> usbtv-audio.c:(.text+0x21ed66): undefined reference to `snd_pcm_link_rwlock' >> usbtv-audio.c:(.text+0x21ed9f): undefined reference to `snd_pcm_link_rwlock' >> usbtv-audio.c:(.text+0x21edf5): undefined reference to `snd_pcm_period_elapsed' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f00a): undefined reference to `snd_card_new' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f0a2): undefined reference to `snd_pcm_new' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f0e5): undefined reference to `snd_pcm_set_ops' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f103): undefined reference to `snd_pcm_lib_preallocate_pages_for_all' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f10c): undefined reference to `snd_card_register' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f12a): undefined reference to `snd_card_free' drivers/built-in.o: In function `usbtv_audio_free': >> (.text+0x21f15c): undefined reference to `snd_card_free' >> drivers/built-in.o:(.data+0x43250): undefined reference to `snd_pcm_lib_ioctl' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 7c5b86006ee6..b833c5b9094e 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -1,6 +1,7 @@ config VIDEO_USBTV tristate "USBTV007 video capture support" - depends on VIDEO_V4L2 + depends on VIDEO_V4L2 && SND + select SND_PCM select VIDEOBUF2_VMALLOC ---help--- -- cgit v1.2.3 From b250392f7b5062cf026b1423e27265e278fd6b30 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Aug 2014 21:15:53 -0300 Subject: [media] media: ttpci: fix av7110 build to be compatible with CONFIG_INPUT_EVDEV Fix build when CONFIG_INPUT_EVDEV=m and DVB_AV7110=y. Only build av7110_ir.c when CONFIG_INPUT_EVDEV is compatible with CONFIG_DVB_AV7110. Fixes these build errors: drivers/built-in.o: In function `input_sync': av7110_ir.c:(.text+0x1223ac): undefined reference to `input_event' drivers/built-in.o: In function `av7110_emit_key': av7110_ir.c:(.text+0x12247c): undefined reference to `input_event' av7110_ir.c:(.text+0x122495): undefined reference to `input_event' av7110_ir.c:(.text+0x122569): undefined reference to `input_event' av7110_ir.c:(.text+0x1225a7): undefined reference to `input_event' drivers/built-in.o:av7110_ir.c:(.text+0x122629): more undefined references to `input_event' follow drivers/built-in.o: In function `av7110_ir_init': (.text+0x1227e4): undefined reference to `input_allocate_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12298f): undefined reference to `input_register_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12299e): undefined reference to `input_free_device' drivers/built-in.o: In function `av7110_ir_exit': (.text+0x122a94): undefined reference to `input_unregister_device' drivers/built-in.o: In function `av7110_detach': av7110.c:(.text+0x228d4a): undefined reference to `av7110_ir_exit' drivers/built-in.o: In function `arm_thread': av7110.c:(.text+0x22a404): undefined reference to `av7110_check_ir_config' av7110.c:(.text+0x22a626): undefined reference to `av7110_check_ir_config' drivers/built-in.o: In function `av7110_attach': av7110.c:(.text+0x22b08c): undefined reference to `av7110_ir_init' Signed-off-by: Randy Dunlap Reported-by: Randy Dunlap Reported-by: Jim Davis Reported-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/Kconfig | 4 ++++ drivers/media/pci/ttpci/Makefile | 2 +- drivers/media/pci/ttpci/av7110.c | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index 0dcb8cd77676..7b83151ed6c4 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,8 +1,12 @@ +config DVB_AV7110_IR + bool + config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV + select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index 98905963ff08..49f71b1eaf14 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile @@ -5,7 +5,7 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o -ifdef CONFIG_INPUT_EVDEV +ifdef CONFIG_DVB_AV7110_IR dvb-ttpci-objs += av7110_ir.o endif diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f38329d29daa..c1f0617a6973 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110) restart_feeds(av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, true); #endif } @@ -268,7 +268,7 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, false); #endif @@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->ioctl_mutex); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_init(av7110); #endif printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); @@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa) struct av7110 *av7110 = saa->ext_priv; dprintk(4, "%p\n", av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_exit(av7110); #endif if (budgetpatch || av7110->full_ts) { -- cgit v1.2.3 From a4f20e2fbc8e84a3aace35af353ca662b455fae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:46:46 -0500 Subject: [media] vpif_display: get rid of some unused vars drivers/media/platform/davinci/vpif_display.c: In function 'vpif_channel_isr': drivers/media/platform/davinci/vpif_display.c:363:18: warning: variable 'field' set but not used [-Wunused-but-set-variable] enum v4l2_field field; ^ drivers/media/platform/davinci/vpif_display.c: In function 'vpif_calculate_offs ets': drivers/media/platform/davinci/vpif_display.c:505:23: warning: variable 'vpitch ' set but not used [-Wunused-but-set-variable] unsigned int hpitch, vpitch, sizeimage; ^ drivers/media/platform/davinci/vpif_display.c: In function 'vpif_set_output': drivers/media/platform/davinci/vpif_display.c:816:27: warning: variable 'subdev _info' set but not used [-Wunused-but-set-variable] struct vpif_subdev_info *subdev_info = NULL; Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a03ec7381cfe..aaa9ec06630f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -360,7 +360,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) struct vpif_device *dev = &vpif_obj; struct channel_obj *ch; struct common_obj *common; - enum v4l2_field field; int fid = -1, i; int channel_id = 0; @@ -369,7 +368,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) return IRQ_NONE; ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; for (i = 0; i < VPIF_NUMOBJECTS; i++) { common = &ch->common[i]; /* If streaming is started in this channel */ @@ -502,7 +500,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch) struct vpif_params *vpifparams = &ch->vpifparams; enum v4l2_field field = common->fmt.fmt.pix.field; struct video_obj *vid_ch = &ch->video; - unsigned int hpitch, vpitch, sizeimage; + unsigned int hpitch, sizeimage; if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { if (ch->vpifparams.std_info.frm_fmt) @@ -516,7 +514,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch) sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); if ((V4L2_FIELD_NONE == vid_ch->buf_field) || (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { common->ytop_off = 0; @@ -813,17 +810,14 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg, { struct vpif_display_chan_config *chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - struct vpif_subdev_info *subdev_info = NULL; struct v4l2_subdev *sd = NULL; u32 input = 0, output = 0; int sd_index; int ret; sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index); - if (sd_index >= 0) { + if (sd_index >= 0) sd = vpif_obj.sd[sd_index]; - subdev_info = &vpif_cfg->subdevinfo[sd_index]; - } if (sd) { input = chan_cfg->outputs[index].input_route; -- cgit v1.2.3 From 24ab6338f3fc0f3fe9c541f5e7b29ae026dea0c2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:49:06 -0500 Subject: [media] vpif_capture: get rid of some unused vars drivers/media/platform/davinci/vpif_capture.c: In function 'vpif_channel_isr': drivers/media/platform/davinci/vpif_capture.c:376:18: warning: variable 'field' set but not used [-Wunused-but-set-variable] enum v4l2_field field; ^ drivers/media/platform/davinci/vpif_capture.c: In function 'vpif_calculate_offs ets': drivers/media/platform/davinci/vpif_capture.c:536:23: warning: variable 'vpitch ' set but not used [-Wunused-but-set-variable] unsigned int hpitch, vpitch, sizeimage; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index b054b7eec53d..cf15bb1962ef 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -373,7 +373,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) struct vpif_device *dev = &vpif_obj; struct common_obj *common; struct channel_obj *ch; - enum v4l2_field field; int channel_id = 0; int fid = -1, i; @@ -383,8 +382,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { common = &ch->common[i]; /* skip If streaming is not started in this channel */ @@ -533,7 +530,7 @@ static int vpif_update_std_info(struct channel_obj *ch) */ static void vpif_calculate_offsets(struct channel_obj *ch) { - unsigned int hpitch, vpitch, sizeimage; + unsigned int hpitch, sizeimage; struct video_obj *vid_ch = &(ch->video); struct vpif_params *vpifparams = &ch->vpifparams; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; @@ -552,7 +549,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch) sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); if ((V4L2_FIELD_NONE == vid_ch->buf_field) || (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { -- cgit v1.2.3 From f17513c9bf5650738d80cd82f716901b3562bf27 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:51:38 -0500 Subject: [media] dm644x_ccdc: declare some functions as static drivers/media/platform/davinci/dm644x_ccdc.c:133:6: warning: no previous protot ype for 'ccdc_setwin' [-Wmissing-prototypes] void ccdc_setwin(struct v4l2_rect *image_win, ^ drivers/media/platform/davinci/dm644x_ccdc.c:373:6: warning: no previous protot ype for 'ccdc_config_ycbcr' [-Wmissing-prototypes] void ccdc_config_ycbcr(void) ^ drivers/media/platform/davinci/dm644x_ccdc.c:526:6: warning: no previous protot ype for 'ccdc_config_raw' [-Wmissing-prototypes] void ccdc_config_raw(void) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 07e98df3d867..b0b9cd54e9e9 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -130,9 +130,9 @@ static void ccdc_enable_vport(int flag) * This function will configure the window size * to be capture in CCDC reg */ -void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, - int ppc) +static void ccdc_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, + int ppc) { int horz_start, horz_nr_pixels; int vert_start, vert_nr_lines; @@ -370,7 +370,7 @@ static int ccdc_set_params(void __user *params) * ccdc_config_ycbcr() * This function will configure CCDC for YCbCr video capture */ -void ccdc_config_ycbcr(void) +static void ccdc_config_ycbcr(void) { struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; u32 syn_mode; @@ -523,7 +523,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) * ccdc_config_raw() * This function will configure CCDC for Raw capture mode */ -void ccdc_config_raw(void) +static void ccdc_config_raw(void) { struct ccdc_params_raw *params = &ccdc_cfg.bayer; struct ccdc_config_params_raw *config_params = -- cgit v1.2.3 From 0448056c7e97f3d8aef6777ffc8ed18569f973e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:53:23 -0500 Subject: [media] dm355_ccdc: declare a function as static drivers/media/platform/davinci/dm355_ccdc.c:463:5: warning: no previous prototy pe for 'ccdc_write_dfc_entry' [-Wmissing-prototypes] int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 05f8fb7f7b70..3f44deb5b7a7 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -460,7 +460,7 @@ static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) * ccdc_write_dfc_entry() * write an entry in the dfc table. */ -int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) +static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) { /* TODO This is to be re-visited and adjusted */ #define DFC_WRITE_WAIT_COUNT 1000 -- cgit v1.2.3 From cff562137226d0f431e85733795edd271e946087 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:56:16 -0500 Subject: [media] gsc-core: Remove useless test drivers/media/platform/exynos-gsc/gsc-core.c: In function 'gsc_probe': drivers/media/platform/exynos-gsc/gsc-core.c:1089:2: warning: comparison is alw ays false due to limited range of data type [-Wtype-limits] if (gsc->id < 0 || gsc->id >= drv_data->num_entities) { ^ gsc->id is declared as u16, so it should always be a positive value. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9d0cc04d7ab7..8d8b3cff8212 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1086,7 +1086,7 @@ static int gsc_probe(struct platform_device *pdev) else gsc->id = pdev->id; - if (gsc->id < 0 || gsc->id >= drv_data->num_entities) { + if (gsc->id >= drv_data->num_entities) { dev_err(dev, "Invalid platform device id: %d\n", gsc->id); return -EINVAL; } -- cgit v1.2.3 From a6a632286865333651fcff3932fea2f945a4d501 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 16:05:39 -0500 Subject: [media] gsc-m2m: Remove an unused var. drivers/media/platform/exynos-gsc/gsc-m2m.c: In function 'gsc_m2m_reqbufs': drivers/media/platform/exynos-gsc/gsc-m2m.c:365:20: warning: variable 'frame' s et but not used [-Wunused-but-set-variable] struct gsc_frame *frame; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index e434f1f03d7b..74e1de637e8f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -362,7 +362,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, { struct gsc_ctx *ctx = fh_to_ctx(fh); struct gsc_dev *gsc = ctx->gsc_dev; - struct gsc_frame *frame; u32 max_cnt; max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? @@ -376,8 +375,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx); } - frame = ctx_get_frame(ctx, reqbufs->type); - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } -- cgit v1.2.3 From 78e100cb237389b816ef59ac40f17d2b9b88a930 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:41:56 -0500 Subject: [media] ti-vpe: use %pad for dma address drivers/media/platform/ti-vpe/vpdma.c: In function 'dump_dtd': include/linux/dynamic_debug.h:64:16: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t' [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro 'DEFINE_DYNAMIC_DEBUG_METADATA' DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:263:2: note: in expansion of macro 'dynamic_pr_debug' dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ >> drivers/media/platform/ti-vpe/vpdma.c:587:2: note: in expansion of macro 'pr_debug' pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index a51a01359805..6121a0b3c754 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -584,7 +584,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) pr_debug("word1: line_length = %d, xfer_height = %d\n", dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); - pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr); + pr_debug("word2: start_addr = %pad\n", &dtd->start_addr); pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, " "pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd), -- cgit v1.2.3 From 14bb9b0485caa2577925393efc04fab957a38b40 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:45:02 -0500 Subject: [media] ti-vpe: shut up a casting warning message drivers/media/platform/ti-vpe/vpdma.c: In function 'vpdma_alloc_desc_buf': >> drivers/media/platform/ti-vpe/vpdma.c:332:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 6121a0b3c754..684ba19bbedd 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -329,7 +329,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) if (!buf->addr) return -ENOMEM; - WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN); + WARN_ON(((u32) buf->addr & VPDMA_DESC_ALIGN) != 0); return 0; } -- cgit v1.2.3 From 8f05232f59ce53f421faf35122bc0e2dd141ea00 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:52:54 -0500 Subject: [media] atmel-isi: tag dma_addr_t as such Instead of using u32 for DMA address, use the proper Kernel type for it. drivers/media/platform/soc_camera/atmel-isi.c: In function 'atmel_isi_probe': >> drivers/media/platform/soc_camera/atmel-isi.c:981:26: warning: passing argument 3 of 'dma_alloc_attrs' from incompatible pointer type isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 3408b045b3f1..f87012b15b28 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -54,7 +54,7 @@ static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) struct isi_dma_desc { struct list_head list; struct fbd *p_fbd; - u32 fbd_phys; + dma_addr_t fbd_phys; }; /* Frame buffer data */ @@ -75,7 +75,7 @@ struct atmel_isi { /* Allocate descriptors for dma buffer use */ struct fbd *p_fb_descriptors; - u32 fb_descriptors_phys; + dma_addr_t fb_descriptors_phys; struct list_head dma_desc_head; struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; @@ -169,7 +169,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); isi_writel(isi, ISI_DMA_C_DSCR, - isi->active->p_dma_desc->fbd_phys); + (u32)isi->active->p_dma_desc->fbd_phys); isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); @@ -346,7 +346,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) return; } - isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys); isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); -- cgit v1.2.3 From 9842a417d46bf40f2d460120016b6392d3ac32c9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:53:27 -0500 Subject: [media] atmel-isi: Fix a truncate warning drivers/media/platform/soc_camera/atmel-isi.c: In function 'start_streaming': drivers/media/platform/soc_camera/atmel-isi.c:397:26: warning: large integer implicitly truncated to unsigned type [-Woverflow] isi_writel(isi, ISI_INTDIS, ~0UL); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index f87012b15b28..96a4b112e1ca 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -394,7 +394,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } /* Disable all interrupts */ - isi_writel(isi, ISI_INTDIS, ~0UL); + isi_writel(isi, ISI_INTDIS, (u32)~0UL); spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ -- cgit v1.2.3 From 139adba64cdde218e6a679f1d5b675fee937a8d8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 06:07:57 -0500 Subject: [media] s5p_mfc: don't use an external symbol called 'debug' The 'debug' name is known to cause conflicts with allyesconfig on several archs. So, localize its name. >> drivers/built-in.o:(.bss+0xc7ee2c): multiple definition of `debug' arch/x86/built-in.o:(.entry.text+0xf78): first defined here ld: Warning: size of symbol `debug' changed from 86 in arch/x86/built-in.o to 4 in drivers/built-in.o While here, fix a wrong file name reference Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_debug.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d35b0418ab37..89b5b4ad34d3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -37,8 +37,8 @@ #define S5P_MFC_DEC_NAME "s5p-mfc-dec" #define S5P_MFC_ENC_NAME "s5p-mfc-enc" -int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); +int mfc_debug_level; +module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); /* Helper functions for interrupt processing */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index 8e608f5aa0d7..5936923c631c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -1,5 +1,5 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h + * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h * * Header file for Samsung MFC (Multi Function Codec - FIMV) driver * This file contains debug macros @@ -18,11 +18,11 @@ #define DEBUG #ifdef DEBUG -extern int debug; +extern int mfc_debug_level; #define mfc_debug(level, fmt, args...) \ do { \ - if (debug >= level) \ + if (mfc_debug_level >= level) \ printk(KERN_DEBUG "%s:%d: " fmt, \ __func__, __LINE__, ##args); \ } while (0) -- cgit v1.2.3 From 212bdba38724f185344d8ea93f8db0eda1efc348 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 06:38:14 -0500 Subject: [media] vpif: don't cast pointers to int Shut up several warnings about invalid casting when printing the values of two pointers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- drivers/media/platform/davinci/vpif_display.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ea7661a27479..ed9dd27e3c63 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1914,7 +1914,7 @@ static int vpfe_probe(struct platform_device *pdev) v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "trying to register vpfe device.\n"); v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%x\n", (int)&vpfe_dev->video_dev); + "video_dev=%p\n", &vpfe_dev->video_dev); vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = video_register_device(vpfe_dev->video_dev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index aaa9ec06630f..2ce3ddfcca80 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1204,8 +1204,8 @@ static int vpif_probe_complete(void) INIT_LIST_HEAD(&common->dma_queue); /* register video device */ - vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", - (int)ch, (int)&ch->video_dev); + vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n", + ch, &ch->video_dev); /* Initialize the video_device structure */ vdev = ch->video_dev; -- cgit v1.2.3 From 8dece35daf098e5d086b50724119ffbb24ceca7f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 07:00:42 -0500 Subject: [media] dm644x_ccdc: use unsigned long for fpc_table_addr The fpc_table_addr is used as an unsigned integer that stores an address. At the Kernel, the proper type for such integers is unsigned long. This generates lots of warnings when compiling on 64 bits. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 4 ++-- include/media/davinci/dm644x_ccdc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index b0b9cd54e9e9..62a0ebb01056 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -291,7 +291,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); return -EFAULT; } - config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; + config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr; return 0; } @@ -506,7 +506,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) /* Configure Fault pixel if needed */ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%lx to FPC_ADDR...\n", (fpc->fpc_table_addr)); /* Write the FPC params with FPC disable */ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h index 852e96c4bb46..984fb79031de 100644 --- a/include/media/davinci/dm644x_ccdc.h +++ b/include/media/davinci/dm644x_ccdc.h @@ -114,7 +114,7 @@ struct ccdc_fault_pixel { /* Number of fault pixel */ unsigned short fp_num; /* Address of fault pixel table */ - unsigned int fpc_table_addr; + unsigned long fpc_table_addr; }; /* Structure for CCDC configuration parameters for raw capture mode passed -- cgit v1.2.3 From c623ed63167adcbc16edac22260e1bff150e60df Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 10:30:17 -0500 Subject: [media] dvb_frontend: estimate bandwidth also for DVB-S/S2/Turbo The needed bandwidth can be estimated using the symbol rate and the rolloff factor. This could be useful for the frontend drivers, as they don't need to calculate it themselves. Reported-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index a5810391af61..c862ad732d9e 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2072,6 +2072,23 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_DVBC_ANNEX_C: rolloff = 113; break; + case SYS_DVBS: + case SYS_TURBO: + rolloff = 135; + break; + case SYS_DVBS2: + switch (c->rolloff) { + case ROLLOFF_20: + rolloff = 120; + break; + case ROLLOFF_25: + rolloff = 125; + break; + default: + case ROLLOFF_35: + rolloff = 135; + } + break; default: break; } -- cgit v1.2.3 From 286da9902240ea8476af6afc02bc29e82508f63f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 10:57:21 -0500 Subject: [media] gsc: Use %pad for dma_addr_t drivers/media/platform/exynos-gsc/gsc-core.c:855:2: note: in expansion of macro 'pr_debug' pr_debug("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", ^ include/linux/dynamic_debug.h:64:16: warning: format '%X' expects argument of type 'unsigned int', but argument 4 has type 'dma _addr_t' [-Wformat=] static struct _ddebug __aligned(8) \ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++-- drivers/media/platform/exynos-gsc/gsc-regs.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 8d8b3cff8212..b4c9f1d08968 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -852,8 +852,8 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M)) swap(addr->cb, addr->cr); - pr_debug("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", - addr->y, addr->cb, addr->cr, ret); + pr_debug("ADDR: y= %pad cb= %pad cr= %pad ret= %d", + &addr->y, &addr->cb, &addr->cr, ret); return ret; } diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index e22d147a6940..ce12a1100511 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -90,8 +90,8 @@ void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift, void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index) { - pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index, - addr->y, addr->cb, addr->cr); + pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index, + &addr->y, &addr->cb, &addr->cr); writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index)); writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index)); writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index)); @@ -101,8 +101,8 @@ void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr, void gsc_hw_set_output_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index) { - pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", - index, addr->y, addr->cb, addr->cr); + pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad", + index, &addr->y, &addr->cb, &addr->cr); writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index)); writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index)); writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index)); -- cgit v1.2.3 From 92e3919a49c0ed683ebab8a992eaac331afce8b7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 11:11:06 -0500 Subject: [media] omap: fix compilation if !VIDEO_OMAP2_VOUT_VRFB When CONFIG_VIDEO_OMAP2_VOUT_VRFB is disabled, the compilation will fail, as the function stubs are wrong. Also, as they weren't declared as static inline, lots of warnings will be generated. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout_vrfb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h index ffde741e0590..4c2314839b48 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.h +++ b/drivers/media/platform/omap/omap_vout_vrfb.h @@ -23,18 +23,18 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct videobuf_buffer *vb); void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); #else -void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { } -int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, +static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; +static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, u32 static_vrfb_allocation) - { return 0; } -void omap_vout_release_vrfb(struct omap_vout_device *vout) { } -int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, + { return 0; }; +static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { }; +static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, unsigned int *count, unsigned int startindex) - { return 0; } -int omap_vout_prepare_vrfb(struct omap_vout_device *vout, + { return 0; }; +static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct videobuf_buffer *vb) - { return 0; } -void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { } + { return 0; }; +static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }; #endif #endif -- cgit v1.2.3 From 52334bb3df155e764dd1a9b084115a5a0fa485b6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:46:49 -0300 Subject: [media] omap_vout: Get rid of a few warnings drivers/media/platform/omap/omap_vout.c: In function 'omapvid_setup_overlay': drivers/media/platform/omap/omap_vout.c:372:29: warning: variable 'pixheight' set but not used [-Wunused-but-set-variable] int cropheight, cropwidth, pixheight, pixwidth; ^ drivers/media/platform/omap/omap_vout.c: In function 'vidioc_s_ctrl': drivers/media/platform/omap/omap_vout.c:1454:24: warning: variable 'ovl' set but not used [-Wunused-but-set-variable] struct omap_overlay *ovl; ^ drivers/media/platform/omap/omap_vout.c: In function 'vidioc_reqbufs': drivers/media/platform/omap/omap_vout.c:1492:55: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 2d177fa58471..d9258f3d0f8e 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -369,7 +369,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, { int ret = 0; struct omap_overlay_info info; - int cropheight, cropwidth, pixheight, pixwidth; + int cropheight, cropwidth, pixwidth; if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && (outw != vout->pix.width || outh != vout->pix.height)) { @@ -389,12 +389,10 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, if (is_rotation_90_or_270(vout)) { cropheight = vout->crop.width; cropwidth = vout->crop.height; - pixheight = vout->pix.width; pixwidth = vout->pix.height; } else { cropheight = vout->crop.height; cropwidth = vout->crop.width; - pixheight = vout->pix.height; pixwidth = vout->pix.width; } @@ -1451,12 +1449,10 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) } case V4L2_CID_VFLIP: { - struct omap_overlay *ovl; struct omapvideo_info *ovid; unsigned int mirror = a->value; ovid = &vout->vid_info; - ovl = ovid->overlays[0]; mutex_lock(&vout->lock); if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { @@ -1489,7 +1485,7 @@ static int vidioc_reqbufs(struct file *file, void *fh, struct omap_vout_device *vout = fh; struct videobuf_queue *q = &vout->vbq; - if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) + if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; /* if memory is not mmp or userptr return error */ -- cgit v1.2.3 From af425be8b51b02c9bb7bc2fdeb7b4c9ccb25fc5a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:50:23 -0300 Subject: [media] s5p-jpeg: get rid of some warnings Declare this as static: drivers/media/platform/s5p-jpeg/jpeg-core.c:732:6: warning: no previous prototype for 'exynos4_jpeg_set_huff_tbl' [-Wmissing-prototypes] void exynos4_jpeg_set_huff_tbl(void __iomem *base) ^ And don't compile this dead code, while not needed: drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c:236:14: warning: no previous prototype for 'exynos3250_jpeg_get_y' [-Wmissing-prototypes] unsigned int exynos3250_jpeg_get_y(void __iomem *regs) ^ drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c:241:14: warning: no previous prototype for 'exynos3250_jpeg_get_x' [-Wmissing-prototypes] unsigned int exynos3250_jpeg_get_x(void __iomem *regs) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 +- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index e66acbc2a82d..e525a7c8d885 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -729,7 +729,7 @@ static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality) ARRAY_SIZE(qtbl_chrominance[quality])); } -void exynos4_jpeg_set_huff_tbl(void __iomem *base) +static void exynos4_jpeg_set_huff_tbl(void __iomem *base) { exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL, ARRAY_SIZE(hdctbl0)); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c index d26e1f846553..e8c2cad93962 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c @@ -233,6 +233,7 @@ void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x) writel(reg, regs + EXYNOS3250_JPGX); } +#if 0 /* Currently unused */ unsigned int exynos3250_jpeg_get_y(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGY); @@ -242,6 +243,7 @@ unsigned int exynos3250_jpeg_get_x(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGX); } +#endif void exynos3250_jpeg_interrupts_enable(void __iomem *regs) { -- cgit v1.2.3 From dc916aa78aec95ce93d9e9e323ba3a5a88b1d516 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:52:56 -0300 Subject: [media] g2d: remove unused var drivers/media/platform/s5p-g2d/g2d.c: In function 'job_abort': drivers/media/platform/s5p-g2d/g2d.c:493:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] int ret; ^ The job_abort function returns void. No sense to get the returned argument, if this won't be used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-g2d/g2d.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 357af1ebaeda..d79e214ce8ce 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -490,14 +490,13 @@ static void job_abort(void *prv) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; - int ret; if (dev->curr == NULL) /* No job currently running */ return; - ret = wait_event_timeout(dev->irq_queue, - dev->curr == NULL, - msecs_to_jiffies(G2D_TIMEOUT)); + wait_event_timeout(dev->irq_queue, + dev->curr == NULL, + msecs_to_jiffies(G2D_TIMEOUT)); } static void device_run(void *prv) -- cgit v1.2.3 From 2ff1d4c13b2881e9276a00bd3032d9afe7d15ef1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:56:24 -0300 Subject: [media] fimc-is-param: get rid of warnings In file included from drivers/media/platform/exynos4-is/fimc-is-param.c:31:0: drivers/media/platform/exynos4-is/fimc-is-errno.h:245:20: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] const char * const fimc_is_strerr(unsigned int error); ^ drivers/media/platform/exynos4-is/fimc-is-errno.h:246:20: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] const char * const fimc_is_param_strerr(unsigned int error); ^ drivers/media/platform/exynos4-is/fimc-is-param.c: In function 'fimc_is_set_initial_params': drivers/media/platform/exynos4-is/fimc-is-param.c:670:23: warning: variable 'sensor' set but not used [-Wunused-but-set-variable] struct sensor_param *sensor; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-errno.c | 4 ++-- drivers/media/platform/exynos4-is/fimc-is-errno.h | 4 ++-- drivers/media/platform/exynos4-is/fimc-is-param.c | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c index e8519e151c1a..e050e63fe358 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.c +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c @@ -15,7 +15,7 @@ #include "fimc-is-errno.h" -const char * const fimc_is_param_strerr(unsigned int error) +const char *fimc_is_param_strerr(unsigned int error) { switch (error) { case ERROR_COMMON_CMD: @@ -146,7 +146,7 @@ const char * const fimc_is_param_strerr(unsigned int error) } } -const char * const fimc_is_strerr(unsigned int error) +const char *fimc_is_strerr(unsigned int error) { error &= ~IS_ERROR_TIME_OUT_FLAG; diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h index 3de6f6da6f87..ef981e74513a 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.h +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h @@ -242,7 +242,7 @@ enum fimc_is_error { ERROR_SCALER_FLIP = 521, }; -const char * const fimc_is_strerr(unsigned int error); -const char * const fimc_is_param_strerr(unsigned int error); +const char *fimc_is_strerr(unsigned int error); +const char *fimc_is_param_strerr(unsigned int error); #endif /* FIMC_IS_ERR_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index bf1465d1bf6d..72b9b436c5c0 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -667,7 +667,6 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val) 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; @@ -676,7 +675,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) 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; -- cgit v1.2.3 From b171e3d8514e80c8e01e59565010b1d7879ac019 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:58:23 -0300 Subject: [media] s5p_mfc_ctrl: add missing s5p_mfc_ctrl.h header That gets rid of the following warnings: drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:119:5: warning: no previous prototype for 's5p_mfc_release_firmware' [-Wmissing-prototypes] int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:132:5: warning: no previous prototype for 's5p_mfc_reset' [-Wmissing-prototypes] int s5p_mfc_reset(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:214:5: warning: no previous prototype for 's5p_mfc_init_hw' [-Wmissing-prototypes] int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:291:6: warning: no previous prototype for 's5p_mfc_deinit_hw' [-Wmissing-prototypes] void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:301:5: warning: no previous prototype for 's5p_mfc_sleep' [-Wmissing-prototypes] int s5p_mfc_sleep(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:330:5: warning: no previous prototype for 's5p_mfc_wakeup' [-Wmissing-prototypes] int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:378:5: warning: no previous prototype for 's5p_mfc_open_mfc_inst' [-Wmissing-prototypes] int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:420:6: warning: no previous prototype for 's5p_mfc_close_mfc_inst' [-Wmissing-prototypes] void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index ca9f78922832..5289b8696c1e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -21,6 +21,7 @@ #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" +#include "s5p_mfc_ctrl.h" /* Allocate memory for firmware */ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) -- cgit v1.2.3 From 8492ec69801ea039546fd27e84fa84f7a0612474 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:13:47 -0300 Subject: [media] s5p_mfc: get rid of several warnings drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:826:5: warning: no previous prototype for 'vidioc_decoder_cmd' [-Wmissing-prototypes] int vidioc_decoder_cmd(struct file *file, void *priv, ^ drivers/media/platform/s5p-mfc/s5p_mfc.c: In function 's5p_mfc_runtime_resume': drivers/media/platform/s5p-mfc/s5p_mfc.c:1314:6: warning: variable 'pre_power' set but not used [-Wunused-but-set-variable] int pre_power; ^ drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c:163:25: warning: no previous prototype for 's5p_mfc_init_hw_cmds_v5' [-Wmissing-prototypes] struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) ^ drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c:156:25: warning: no previous prototype for 's5p_mfc_init_hw_cmds_v6' [-Wmissing-prototypes] struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c: In function 's5p_mfc_run_dec_frame': drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:1189:15: warning: variable 'index' set but not used [-Wunused-but-set-variable] unsigned int index; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c: In function 'cleanup_ref_queue': drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:742:27: warning: variable 'mb_c_addr' set but not used [-Wunused-but-set-variable] unsigned long mb_y_addr, mb_c_addr; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:742:16: warning: variable 'mb_y_addr' set but not used [-Wunused-but-set-variable] unsigned long mb_y_addr, mb_c_addr; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c: At top level: drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1684:5: warning: no previous prototype for 'vidioc_encoder_cmd' [-Wmissing-prototypes] int vidioc_encoder_cmd(struct file *file, void *priv, ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 -- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 7 ++----- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 2 -- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 89b5b4ad34d3..d180440ac43e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1311,11 +1311,9 @@ static int s5p_mfc_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - int pre_power; if (!m_dev->alloc_ctx) return 0; - pre_power = atomic_read(&m_dev->pm.power); atomic_set(&m_dev->pm.power, 1); return 0; } 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 9a6efd6c1329..8c4739ca16d6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -14,6 +14,7 @@ #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" /* This function is used to send a command to the MFC */ static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, 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 ec1a5947ed7d..f17609669b96 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -16,6 +16,7 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd_v6.h" static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, struct s5p_mfc_cmd_args *args) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 9103258b7df3..fe4d21ccfd49 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -823,8 +823,8 @@ 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) +static 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; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index d26b2484ca10..41f3b7f512fa 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -739,14 +739,11 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_buf *mb_entry; - unsigned long mb_y_addr, mb_c_addr; /* move buffers in ref queue to src queue */ while (!list_empty(&ctx->ref_queue)) { mb_entry = list_entry((&ctx->ref_queue)->next, struct s5p_mfc_buf, list); - mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); - mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); list_del(&mb_entry->list); ctx->ref_queue_cnt--; list_add_tail(&mb_entry->list, &ctx->src_queue); @@ -1681,8 +1678,8 @@ static int vidioc_g_parm(struct file *file, void *priv, return 0; } -int vidioc_encoder_cmd(struct file *file, void *priv, - struct v4l2_encoder_cmd *cmd) +static int vidioc_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct s5p_mfc_dev *dev = ctx->dev; 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 58ec7bb26ebc..31688cddfead 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1186,7 +1186,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *temp_vb; unsigned long flags; - unsigned int index; if (ctx->state == MFCINST_FINISHING) { last_frame = MFC_DEC_LAST_FRAME; @@ -1211,7 +1210,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); - index = temp_vb->b->v4l2_buf.index; dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); if (temp_vb->b->v4l2_planes[0].bytesused == 0) { -- cgit v1.2.3 From 84ddba456e65a26d86c103aa0a4259197aac63fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:17:16 -0300 Subject: [media] mipi-csis: get rid of a warning drivers/media/platform/exynos4-is/mipi-csis.c: In function 's5pcsis_parse_dt': drivers/media/platform/exynos4-is/mipi-csis.c:756:2: warning: comparison is always false due to limited range of data type [-Wtype-limits] if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/mipi-csis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index ae54ef5f535d..8be8897bc6cd 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -752,7 +752,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, v4l2_of_parse_endpoint(node, &endpoint); state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; - if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) + if (state->index >= CSIS_MAX_ENTITIES) return -ENXIO; /* Get MIPI CSI-2 bus configration from the endpoint node. */ -- cgit v1.2.3 From cdf58a6f87a6c941527699c00443d186154f475c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:19:18 -0300 Subject: [media] exynos4-is/media-dev: get rid of a warning for a dead code drivers/media/platform/exynos4-is/media-dev.c: In function 'fimc_md_link_notify': drivers/media/platform/exynos4-is/media-dev.c:1102:4: warning: suggest braces around empty body in an 'else' statement [-Wempty-body] ; /* TODO: Link state change validation */ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 344718df5c62..54c49d5e7690 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1098,8 +1098,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags, if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) { if (!(flags & MEDIA_LNK_FL_ENABLED)) ret = __fimc_md_modify_pipelines(sink, false); +#if 0 else - ; /* TODO: Link state change validation */ + /* TODO: Link state change validation */ +#endif /* After link activation */ } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && (link->flags & MEDIA_LNK_FL_ENABLED)) { -- cgit v1.2.3 From 615f1bcb34317afc615043dd61ba54198f075629 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:20:42 -0300 Subject: [media] mx2_camera: get rid of a warning drivers/media/platform/soc_camera/mx2_camera.c: In function 'mx27_camera_emma_prp_reset': drivers/media/platform/soc_camera/mx2_camera.c:812:6: warning: variable 'cntl' set but not used [-Wunused-but-set-variable] u32 cntl; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx2_camera.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index b40bc2e5ba47..2d57c1d272b8 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -809,10 +809,9 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q, static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) { - u32 cntl; int count = 0; - cntl = readl(pcdev->base_emma + PRP_CNTL); + readl(pcdev->base_emma + PRP_CNTL); writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); while (count++ < 100) { if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) -- cgit v1.2.3 From b91677ad098b7452b03b7a21d195269520f3522d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:21:43 -0300 Subject: [media] atmel-isi: get rid of a warning drivers/media/platform/soc_camera/atmel-isi.c: In function 'start_streaming': drivers/media/platform/soc_camera/atmel-isi.c:387:6: warning: variable 'sr' set but not used [-Wunused-but-set-variable] u32 sr = 0; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 96a4b112e1ca..c5291b001057 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -384,7 +384,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct atmel_isi *isi = ici->priv; - u32 sr = 0; int ret; /* Reset ISI */ @@ -398,7 +397,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ - sr = isi_readl(isi, ISI_STATUS); + isi_readl(isi, ISI_STATUS); if (count) start_dma(isi, isi->active); -- cgit v1.2.3 From c438269948c420518101a836b526f71d389f80dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:23:58 -0300 Subject: [media] s5p-jpeg: Get rid of a warning drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c: In function 's5p_jpeg_clear_int': drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c:327:16: warning: variable 'reg' set but not used [-Wunused-but-set-variable] unsigned long reg; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index 52407d790726..0d37bed088df 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -326,7 +326,7 @@ void s5p_jpeg_clear_int(void __iomem *regs) { unsigned long reg; - reg = readl(regs + S5P_JPGINTST); + readl(regs + S5P_JPGINTST); writel(S5P_INT_RELEASE, regs + S5P_JPGCOM); reg = readl(regs + S5P_JPGOPR); } -- cgit v1.2.3 From 821ee47e0ef589c75c0c10411463c8cd795afafb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 15:04:34 -0300 Subject: Revert "[media] staging: omap4iss: copy paste error in iss_get_clocks" This patch readded a call to iss_put_clocks(), with was removed by changeset 1153be56a105, causing a compilation breakage. This reverts commit d4b32646468088323f27a7788ce3b07191015142. --- drivers/staging/media/omap4iss/iss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index 8a23d164e847..d548371db65a 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -1014,7 +1014,6 @@ static int iss_get_clocks(struct iss_device *iss) iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk"); if (IS_ERR(iss->iss_ctrlclk)) { dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); - iss_put_clocks(iss); return PTR_ERR(iss->iss_ctrlclk); } -- cgit v1.2.3 From 1c17d8c748b251071c61a4383490881a4071b003 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:35:22 -0600 Subject: [media] enable COMPILE_TEST for MX2 eMMa-PrP driver By allowing compilation on all archs, we can use static analysis tools to test this driver. In order to do that, replace asm/sizes.h by its generic name (linux/sizes.h), with should keep doing the right thing. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 3 ++- drivers/media/platform/mx2_emmaprp.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6d86646d9743..66566c920fe9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -185,7 +185,8 @@ config VIDEO_SAMSUNG_S5P_MFC config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" - depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27 + depends on VIDEO_DEV && VIDEO_V4L2 + depends on SOC_IMX27 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index fa8f7cabe364..4971ff21f82b 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp" -- cgit v1.2.3 From f3334180d4790856bae42fb2e7a3137f9a36aa18 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:41:56 -0600 Subject: [media] enable COMPILE_TEST for ti-vbe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowing COMPILE_TEST here is trivial, but there's one missing header to be added: drivers/media/platform/ti-vpe/vpe.c: In function ‘vpe_probe’: drivers/media/platform/ti-vpe/vpe.c:2266:56: error: ‘SZ_32K’ undeclared (first use in this function) dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K); ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 3 ++- drivers/media/platform/ti-vpe/vpe.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 66566c920fe9..6d0a0df6d818 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -223,7 +223,8 @@ config VIDEO_RENESAS_VSP1 config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" - depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX + depends on VIDEO_DEV && VIDEO_V4L2 + depends on SOC_DRA7XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 972f43f69206..773b1fbf3269 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From f2080e38813a3b04d4a6fde5a2697f47cfec4ee5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:50:03 -0600 Subject: [media] allow COMPILE_TEST for SAMSUNG_EXYNOS4_IS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That helps some static checks, so enable it. While there, it was noticed that linux/sizes.h was missing: drivers/media/platform/exynos4-is/mipi-csis.c: In function ‘s5pcsis_s_rx_buffer’: drivers/media/platform/exynos4-is/mipi-csis.c:114:31: error: ‘SZ_4K’ undeclared (first use in this function) #define S5PCSIS_PKTDATA_SIZE SZ_4K ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/platform/exynos4-is/mipi-csis.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 5dcaa0a80540..811872195f36 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on (PLAT_S5P || ARCH_EXYNOS) + depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) depends on OF && COMMON_CLK help Say Y here to enable camera host interface devices for diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 8be8897bc6cd..db6fd14d1936 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 1dbfacf2dd30100ea38181f9cc25feaaa9204630 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:56:21 -0600 Subject: [media] enable COMPILE_TEST for OMAP2 vout We don't need anything special to enable COMPILE_TEST for this driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 2 +- drivers/media/platform/omap/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 4ac4c91b4415..b598b3bb2645 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -49,6 +49,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ obj-y += davinci/ -obj-$(CONFIG_ARCH_OMAP) += omap/ +obj-y += omap/ ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 37ad446b35b3..2253bf102ed9 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP2 || ARCH_OMAP3 + depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS -- cgit v1.2.3 From 7155043c2d027c9c848c3d09badb5af2894ed652 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:21:35 -0600 Subject: [media] enable COMPILE_TEST for media drivers There are several arch-specific media drivers that don't require asm-specific includes and can be successfully compiled on x86. Add COMPILE_TEST dependency for them, in order to allow a broader test on those drivers. That helps static analysis tools like Coverity to discover eventual troubles there. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 21 ++++++++++++++------- drivers/media/platform/davinci/Kconfig | 12 ++++++++---- drivers/media/platform/s5p-tv/Kconfig | 3 ++- drivers/media/platform/soc_camera/Kconfig | 10 +++++++--- drivers/media/rc/Kconfig | 5 +++-- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6d0a0df6d818..a8ae457f8a02 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -56,7 +56,8 @@ config VIDEO_VIU config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" - depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES + depends on VIDEO_V4L2 && I2C && DMADEVICES + depends on MFD_TIMBERDALE || COMPILE_TEST select DMA_ENGINE select TIMB_DMA select VIDEO_ADV7180 @@ -74,7 +75,8 @@ config VIDEO_VINO config VIDEO_M32R_AR tristate "AR devices" - depends on M32R && VIDEO_V4L2 + depends on VIDEO_V4L2 + depends on M32R || COMPILE_TEST ---help--- This is a video4linux driver for the Renesas AR (Artificial Retina) camera module. @@ -109,7 +111,8 @@ config VIDEO_OMAP3_DEBUG config VIDEO_S3C_CAMIF tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on (ARCH_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME + depends on PM_RUNTIME + depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -158,7 +161,8 @@ config VIDEO_MEM2MEM_DEINTERLACE config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n @@ -168,7 +172,8 @@ config VIDEO_SAMSUNG_S5P_G2D config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- @@ -177,7 +182,8 @@ config VIDEO_SAMSUNG_S5P_JPEG config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG default n help @@ -196,7 +202,8 @@ config VIDEO_MX2_EMMAPRP config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" - depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5 + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_EXYNOS5 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index afb3aec1320e..35809278e349 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" - depends on VIDEO_DEV && ARCH_DAVINCI + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -14,7 +15,8 @@ config VIDEO_DAVINCI_VPIF_DISPLAY config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" - depends on VIDEO_DEV && ARCH_DAVINCI + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -26,7 +28,8 @@ config VIDEO_DAVINCI_VPIF_CAPTURE config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" - depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) + depends on VIDEO_V4L2 + depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -40,7 +43,8 @@ config VIDEO_DM6446_CCDC config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI + depends on VIDEO_V4L2 + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig index 369a4c191e18..9f38b3dbe0a8 100644 --- a/drivers/media/platform/s5p-tv/Kconfig +++ b/drivers/media/platform/s5p-tv/Kconfig @@ -8,7 +8,8 @@ config VIDEO_SAMSUNG_S5P_TV bool "Samsung TV driver for S5P platform" - depends on (PLAT_S5P || ARCH_EXYNOS) && PM_RUNTIME + depends on PM_RUNTIME + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST default n ---help--- Say Y here to enable selecting the TV output devices for diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 6540847f4e1d..c0d4c0f822ea 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -20,6 +20,7 @@ config SOC_CAMERA_PLATFORM config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA + depends on MX3_IPU || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -58,7 +59,8 @@ config VIDEO_SH_MOBILE_CEU config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" - depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA + depends on VIDEO_DEV && SOC_CAMERA + depends on ARCH_OMAP1 || COMPILE_TEST select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG ---help--- @@ -66,14 +68,16 @@ config VIDEO_OMAP1 config VIDEO_MX2 tristate "i.MX27 Camera Sensor Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27 + depends on VIDEO_DEV && SOC_CAMERA + depends on SOC_IMX27 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX27 Camera Sensor Interface config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" - depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91 + depends on VIDEO_DEV && SOC_CAMERA + depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 5e626af8e313..2b0cc4a98e88 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -333,7 +333,8 @@ config IR_GPIO_CIR config RC_ST tristate "ST remote control receiver" - depends on ARCH_STI && RC_CORE + depends on RC_CORE + depends on ARCH_STI || COMPILE_TEST help Say Y here if you want support for ST remote control driver which allows both IR and UHF RX. @@ -344,7 +345,7 @@ config RC_ST config IR_SUNXI tristate "SUNXI IR remote control" depends on RC_CORE - depends on ARCH_SUNXI + depends on ARCH_SUNXI || COMPILE_TEST ---help--- Say Y if you want to use sunXi internal IR Controller -- cgit v1.2.3 From 12bd88e62cf7c1557c7cd78f42a76d7c716b2283 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 16:45:39 -0300 Subject: [media] be sure that HAS_DMA is enabled for vb2-dma-contig vb2-dma-contig depends on HAS_DMA, but the Kbuild doesn't take it into account at select. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/Kconfig | 1 + drivers/media/pci/sta2x11/Kconfig | 1 + drivers/media/platform/Kconfig | 12 ++++++++++++ drivers/media/platform/blackfin/Kconfig | 1 + drivers/media/platform/davinci/Kconfig | 6 ++++++ drivers/media/platform/exynos4-is/Kconfig | 3 +++ drivers/media/platform/marvell-ccic/Kconfig | 2 ++ drivers/media/platform/s5p-tv/Kconfig | 1 + drivers/media/platform/soc_camera/Kconfig | 6 ++++++ drivers/staging/media/davinci_vpfe/Kconfig | 1 + drivers/staging/media/dt3155v4l/Kconfig | 1 + drivers/staging/media/omap4iss/Kconfig | 1 + 12 files changed, 36 insertions(+) diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig index d9e06a6bf1eb..0fb91dc7ca73 100644 --- a/drivers/media/pci/solo6x10/Kconfig +++ b/drivers/media/pci/solo6x10/Kconfig @@ -1,6 +1,7 @@ config VIDEO_SOLO6X10 tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)" depends on PCI && VIDEO_DEV && SND && I2C + depends on HAS_DMA select BITREVERSE select FONT_SUPPORT select FONT_8x16 diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 03130157db83..f6f30abc088b 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,6 +1,7 @@ config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" depends on STA2X11 + depends on HAS_DMA select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a8ae457f8a02..ae021faf7a42 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -96,6 +96,7 @@ config VIDEO_M32R_AR_M64278 config VIDEO_OMAP3 tristate "OMAP 3 Camera support" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + depends on HAS_DMA select ARM_DMA_USE_IOMMU select OMAP_IOMMU select VIDEOBUF2_DMA_CONTIG @@ -113,6 +114,7 @@ config VIDEO_S3C_CAMIF depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on PM_RUNTIME depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -143,6 +145,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_CODA tristate "Chips&Media Coda multi-standard codec IP" depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC + depends on HAS_DMA select SRAM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV @@ -154,6 +157,7 @@ config VIDEO_CODA config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -163,6 +167,7 @@ config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n @@ -174,6 +179,7 @@ config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- @@ -184,6 +190,7 @@ config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n help @@ -193,6 +200,7 @@ config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -204,6 +212,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_EXYNOS5 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -212,6 +221,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -221,6 +231,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. @@ -232,6 +243,7 @@ config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_DRA7XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig index cc239972fa2c..68fa90151b8f 100644 --- a/drivers/media/platform/blackfin/Kconfig +++ b/drivers/media/platform/blackfin/Kconfig @@ -1,6 +1,7 @@ config VIDEO_BLACKFIN_CAPTURE tristate "Blackfin Video Capture Driver" depends on VIDEO_V4L2 && BLACKFIN && I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help V4L2 bridge driver for Blackfin video capture device. diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 35809278e349..b04016e8532d 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -2,6 +2,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -17,6 +18,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -30,6 +32,7 @@ config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -45,6 +48,7 @@ config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces @@ -59,6 +63,7 @@ config VIDEO_DM355_CCDC config VIDEO_DM365_ISIF tristate "TI DM365 ISIF video capture driver" depends on VIDEO_V4L2 && ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables ISIF hw module. This is the hardware module for @@ -71,6 +76,7 @@ config VIDEO_DM365_ISIF config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPBE module used for display devices. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 811872195f36..77c951237744 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -16,6 +16,7 @@ config VIDEO_EXYNOS4_IS_COMMON config VIDEO_S5P_FIMC tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select MFD_SYSCON @@ -43,6 +44,7 @@ if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 config VIDEO_EXYNOS_FIMC_LITE tristate "EXYNOS FIMC-LITE camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_EXYNOS4_IS_COMMON help @@ -55,6 +57,7 @@ endif config VIDEO_EXYNOS4_FIMC_IS tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG depends on OF select FW_LOADER diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index bf739e3b3398..6265d36adceb 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on PCI && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -12,6 +13,7 @@ config VIDEO_CAFE_CCIC config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on ARCH_MMP && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig index 9f38b3dbe0a8..a9d56f8936b4 100644 --- a/drivers/media/platform/s5p-tv/Kconfig +++ b/drivers/media/platform/s5p-tv/Kconfig @@ -71,6 +71,7 @@ config VIDEO_SAMSUNG_S5P_MIXER tristate "Samsung Mixer and Video Processor Driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on VIDEO_SAMSUNG_S5P_TV + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Say Y here if you want support for the Mixer in Samsung S5P SoCs. diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index c0d4c0f822ea..6af6c6dccda8 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -21,6 +21,7 @@ config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA depends on MX3_IPU || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -36,6 +37,7 @@ config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_SHMOBILE || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -52,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -61,6 +64,7 @@ config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_OMAP1 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG ---help--- @@ -70,6 +74,7 @@ config VIDEO_MX2 tristate "i.MX27 Camera Sensor Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX27 Camera Sensor Interface @@ -78,6 +83,7 @@ config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_AT91 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig index 12f321dd2399..4de2f082491d 100644 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ b/drivers/staging/media/davinci_vpfe/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DM365_VPFE tristate "DM365 VPFE Media Controller Capture Driver" depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Support for DM365 VPFE based Media Controller Capture driver. diff --git a/drivers/staging/media/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig index 226a1ca90b3c..2d496001b6e8 100644 --- a/drivers/staging/media/dt3155v4l/Kconfig +++ b/drivers/staging/media/dt3155v4l/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DT3155 tristate "DT3155 frame grabber, Video4Linux interface" depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n ---help--- diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 8afc6fee40c5..b78643f907e7 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,6 +1,7 @@ config VIDEO_OMAP4 bool "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- Driver for an OMAP 4 ISS controller. -- cgit v1.2.3 From 38a0731165250a0a77eff7b90ea3156d44cc7d66 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 16:51:56 -0300 Subject: [media] omap: be sure that MMU is there for COMPILE_TEST COMPILE_TEST fail on (some) archs without MMU. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 2253bf102ed9..05de442d24e4 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST + depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU) select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS -- cgit v1.2.3 From 7a0af6ed97f2f08baecb452e719d9c961d117109 Mon Sep 17 00:00:00 2001 From: Changbing Xiong Date: Wed, 20 Aug 2014 23:04:25 -0300 Subject: [media] media: fix kernel deadlock due to tuner pull-out while playing Normally, ADAP_STREAMING bit is set in dvb_usb_start_feed and cleared in dvb_usb_stop_feed. But in exceptional cases, for example, when the tv is playing programs and the tuner is pulled out, then dvb_usbv2_disconnect is called. In such case, it will first call dvb_usbv2_adapter_frontend_exit to stop dvb_frontend_thread, and then call dvb_usbv2_adapter_dvb_exit to clear ADAP_STREAMING bit. At this point, if dvb_frontend_thread is sleeping and waiting for ADAP_STREAMING to be cleared to get out of sleep. then dvb_frontend_thread can never be stoped, because clearing ADAP_STREAMING bit is performed after dvb_frontend_thread is stopped (i.e. performed in dvb_usbv2_adapter_dvb_exit). So, deadlock: [ 240.822037] INFO: task khubd:497 blocked for more than 120 seconds. [ 240.822655] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 240.830493] khubd D c0013b3c 0 497 2 0x00000000 [ 240.836996] [] (__schedule+0x200/0x54c) from [] (schedule_timeout+0x14c/0x19c) [ 240.845940] [] (schedule_timeout+0x14c/0x19c) from [] (wait_for_common+0xac/0x150) [ 240.855234] [] (wait_for_common+0xac/0x150) from [] (kthread_stop+0x58/0x90) [ 240.864004] [] (kthread_stop+0x58/0x90) from [] (dvb_frontend_stop+0x3c/0x9c) [ 240.872849] [] (dvb_frontend_stop+0x3c/0x9c) from [] (dvb_unregister_frontend+0x20/0xd8) [ 240.882666] [] (dvb_unregister_frontend+0x20/0xd8) from [] (dvb_usbv2_exit+0x68/0xfc) [ 240.892204] [] (dvb_usbv2_exit+0x68/0xfc) from [] (dvb_usbv2_disconnect+0x4c/0x70) [ 240.901499] [] (dvb_usbv2_disconnect+0x4c/0x70) from [] (usb_unbind_interface+0x58/0x188) [ 240.911395] [] (usb_unbind_interface+0x58/0x188) from [] (__device_release_driver+0x74/0xd0) [ 240.921544] [] (__device_release_driver+0x74/0xd0) from [] (device_release_driver+0x1c/0x28) [ 240.931697] [] (device_release_driver+0x1c/0x28) from [] (bus_remove_device+0xc4/0xe4) [ 240.941332] [] (bus_remove_device+0xc4/0xe4) from [] (device_del+0xf4/0x178) [ 240.950106] [] (device_del+0xf4/0x178) from [] (usb_disable_device+0xa0/0x1c8) [ 240.959040] [] (usb_disable_device+0xa0/0x1c8) from [] (usb_disconnect+0x88/0x188) [ 240.968326] [] (usb_disconnect+0x88/0x188) from [] (hub_thread+0x4d0/0x1200) [ 240.977100] [] (hub_thread+0x4d0/0x1200) from [] (kthread+0xa4/0xb0) [ 240.985174] [] (kthread+0xa4/0xb0) from [] (ret_from_fork+0x14/0x3c) [ 240.993259] INFO: task kdvb-ad-0-fe-0:3256 blocked for more than 120 seconds. [ 241.000349] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 241.008162] kdvb-ad-0-fe-0 D c0013b3c 0 3256 2 0x00000000 [ 241.014507] [] (__schedule+0x200/0x54c) from [] (wait_schedule+0x8/0x10) [ 241.022924] [] (wait_schedule+0x8/0x10) from [] (__wait_on_bit+0x74/0xb8) [ 241.031434] [] (__wait_on_bit+0x74/0xb8) from [] (out_of_line_wait_on_bit+0x68/0x70) [ 241.040902] [] (out_of_line_wait_on_bit+0x68/0x70) from [] (dvb_usb_fe_sleep+0xf4/0xfc) [ 241.050618] [] (dvb_usb_fe_sleep+0xf4/0xfc) from [] (dvb_frontend_thread+0x124/0x4e8) [ 241.060164] [] (dvb_frontend_thread+0x124/0x4e8) from [] (kthread+0xa4/0xb0) [ 241.068929] [] (kthread+0xa4/0xb0) from [] (ret_from_fork+0x14/0x3c) Fix it by calling dvb_usbv2_adapter_frontend_exit() latter. Test enviroment: odroidx2 + Hauppauge(WinTV-Aero-M) Signed-off-by: Changbing Xiong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2e90310be2af..6c33d8525454 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -762,9 +762,9 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { if (d->adapter[i].props) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); } } -- cgit v1.2.3 From 236c9bfa4a133cbdfeeb3f7a1902950210549634 Mon Sep 17 00:00:00 2001 From: Changbing Xiong Date: Wed, 20 Aug 2014 23:05:07 -0300 Subject: [media] media: correct return value in dvb_demux_poll Data type of return value is unsigned int, but in function of dvb_demux_poll, when the pointer of dmxdevfilter equals NULL, it will return -EINVAL, which is invalid. Signed-off-by: Changbing Xiong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index c0363f1b6c90..7a5c07003c41 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1088,7 +1088,7 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) unsigned int mask = 0; if (!dmxdevfilter) - return -EINVAL; + return POLLERR; poll_wait(file, &dmxdevfilter->buffer.queue, wait); -- cgit v1.2.3 From d102cac8097c71bbbba41f4d0cdf5b509d4c64cf Mon Sep 17 00:00:00 2001 From: Changbing Xiong Date: Wed, 20 Aug 2014 23:05:40 -0300 Subject: [media] media: check status of dmxdev->exit in poll functions of demux&dvr when usb-type tuner is pulled out, user applications did not close device's FD, and go on polling the device, we should return POLLERR directly. Signed-off-by: Changbing Xiong Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 7a5c07003c41..42b5e70d5ca7 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1085,9 +1085,10 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd, static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; unsigned int mask = 0; - if (!dmxdevfilter) + if ((!dmxdevfilter) || (dmxdev->exit)) return POLLERR; poll_wait(file, &dmxdevfilter->buffer.queue, wait); @@ -1181,6 +1182,9 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) dprintk("function : %s\n", __func__); + if (dmxdev->exit) + return POLLERR; + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); if ((file->f_flags & O_ACCMODE) == O_RDONLY) { -- cgit v1.2.3 From 37b4e43d8b51163183fef32d6f3334c9f97f61c1 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Tue, 5 Aug 2014 08:54:08 -0300 Subject: [media] si2168: clean logging Same thing for si2168 as Antti did earlier for tda18212: There is no need to print module name nor function name as those are done by kernel logging system when dev_xxx logging is used and driver is proper I2C driver. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 70 +++++++++++++++++------------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 8f81d979de30..59a4218459da 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -55,8 +55,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) break; } - dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", - __func__, + dev_dbg(&s->client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -75,7 +74,7 @@ err_mutex_unlock: return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -150,12 +149,12 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } - dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n", - __func__, *status, cmd.rlen, cmd.args); + dev_dbg(&s->client->dev, "status=%02x args=%*ph\n", + *status, cmd.rlen, cmd.args); return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -168,8 +167,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) u8 bandwidth, delivery_system; dev_dbg(&s->client->dev, - "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n", - __func__, c->delivery_system, c->modulation, + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n", + c->delivery_system, c->modulation, c->frequency, c->bandwidth_hz, c->symbol_rate, c->inversion); @@ -343,7 +342,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -357,7 +356,7 @@ static int si2168_init(struct dvb_frontend *fe) struct si2168_cmd cmd; unsigned int chip_id; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); cmd.wlen = 13; @@ -400,16 +399,16 @@ static int si2168_init(struct dvb_frontend *fe) break; default: dev_err(&s->client->dev, - "%s: unkown chip version Si21%d-%c%c%c\n", - KBUILD_MODNAME, cmd.args[2], cmd.args[1], + "unknown chip version Si21%d-%c%c%c\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } /* cold state - try to download firmware */ - dev_info(&s->client->dev, "%s: found a '%s' in cold state\n", - KBUILD_MODNAME, si2168_ops.info.name); + dev_info(&s->client->dev, "found a '%s' in cold state\n", + si2168_ops.info.name); /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &s->client->dev); @@ -422,18 +421,18 @@ static int si2168_init(struct dvb_frontend *fe) if (ret == 0) { dev_notice(&s->client->dev, - "%s: please install firmware file '%s'\n", - KBUILD_MODNAME, SI2168_B40_FIRMWARE); + "please install firmware file '%s'\n", + SI2168_B40_FIRMWARE); } else { dev_err(&s->client->dev, - "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + "firmware file '%s' not found\n", + fw_file); goto err; } } - dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, fw_file); + dev_info(&s->client->dev, "downloading firmware from file '%s'\n", + fw_file); for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { len = remaining; @@ -446,8 +445,8 @@ static int si2168_init(struct dvb_frontend *fe) ret = si2168_cmd_execute(s, &cmd); if (ret) { dev_err(&s->client->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + "firmware download failed=%d\n", + ret); goto err; } } @@ -462,8 +461,8 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; - dev_info(&s->client->dev, "%s: found a '%s' in warm state\n", - KBUILD_MODNAME, si2168_ops.info.name); + dev_info(&s->client->dev, "found a '%s' in warm state\n", + si2168_ops.info.name); s->active = true; @@ -472,7 +471,7 @@ err: if (fw) release_firmware(fw); - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -482,7 +481,7 @@ static int si2168_sleep(struct dvb_frontend *fe) int ret; struct si2168_cmd cmd; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; @@ -495,7 +494,7 @@ static int si2168_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -528,8 +527,7 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) /* open tuner I2C gate */ ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { @@ -553,8 +551,7 @@ static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) /* close tuner I2C gate */ ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { @@ -607,12 +604,12 @@ static int si2168_probe(struct i2c_client *client, struct si2168 *s; int ret; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); s = kzalloc(sizeof(struct si2168), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -637,12 +634,11 @@ static int si2168_probe(struct i2c_client *client, i2c_set_clientdata(client, s); dev_info(&s->client->dev, - "%s: Silicon Labs Si2168 successfully attached\n", - KBUILD_MODNAME); + "Silicon Labs Si2168 successfully attached\n"); return 0; err: kfree(s); - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -650,7 +646,7 @@ static int si2168_remove(struct i2c_client *client) { struct si2168 *s = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); i2c_del_mux_adapter(s->adapter); -- cgit v1.2.3 From 67d0113a224f0fb1be784f7553fdeafd82cadc6c Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Tue, 5 Aug 2014 09:03:54 -0300 Subject: [media] si2157: clean logging Same thing for si2157 as Antti did earlier for tda18212: There is no need to print module name nor function name as those are done by kernel logging system when dev_xxx logging is used and driver is proper I2C driver. While here, fix a typo ("unknown") in si2157_init. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 52 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 6c53edb73a63..2281b7d1f1b5 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -55,8 +55,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) break; } - dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", - __func__, + dev_dbg(&s->client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -75,7 +74,7 @@ err_mutex_unlock: return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -88,7 +87,7 @@ static int si2157_init(struct dvb_frontend *fe) u8 *fw_file; unsigned int chip_id; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); /* configure? */ memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); @@ -121,35 +120,35 @@ static int si2157_init(struct dvb_frontend *fe) break; default: dev_err(&s->client->dev, - "%s: unkown chip version Si21%d-%c%c%c\n", - KBUILD_MODNAME, cmd.args[2], cmd.args[1], + "unknown chip version Si21%d-%c%c%c\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } /* cold state - try to download firmware */ - dev_info(&s->client->dev, "%s: found a '%s' in cold state\n", - KBUILD_MODNAME, si2157_ops.info.name); + dev_info(&s->client->dev, "found a '%s' in cold state\n", + si2157_ops.info.name); /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &s->client->dev); if (ret) { - dev_err(&s->client->dev, "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + dev_err(&s->client->dev, "firmware file '%s' not found\n", + fw_file); goto err; } /* firmware should be n chunks of 17 bytes */ if (fw->size % 17 != 0) { - dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n", - KBUILD_MODNAME, fw_file); + dev_err(&s->client->dev, "firmware file '%s' is invalid\n", + fw_file); ret = -EINVAL; goto err; } - dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, fw_file); + dev_info(&s->client->dev, "downloading firmware from file '%s'\n", + fw_file); for (remaining = fw->size; remaining > 0; remaining -= 17) { len = fw->data[fw->size - remaining]; @@ -159,8 +158,8 @@ static int si2157_init(struct dvb_frontend *fe) ret = si2157_cmd_execute(s, &cmd); if (ret) { dev_err(&s->client->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + "firmware download failed=%d\n", + ret); goto err; } } @@ -184,7 +183,7 @@ err: if (fw) release_firmware(fw); - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -194,7 +193,7 @@ static int si2157_sleep(struct dvb_frontend *fe) int ret; struct si2157_cmd cmd; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; @@ -207,7 +206,7 @@ static int si2157_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -220,8 +219,8 @@ static int si2157_set_params(struct dvb_frontend *fe) u8 bandwidth, delivery_system; dev_dbg(&s->client->dev, - "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", - __func__, c->delivery_system, c->frequency, + "delivery_system=%d frequency=%u bandwidth_hz=%u\n", + c->delivery_system, c->frequency, c->bandwidth_hz); if (!s->active) { @@ -275,7 +274,7 @@ static int si2157_set_params(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -310,7 +309,7 @@ static int si2157_probe(struct i2c_client *client, s = kzalloc(sizeof(struct si2157), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -333,11 +332,10 @@ static int si2157_probe(struct i2c_client *client, i2c_set_clientdata(client, s); dev_info(&s->client->dev, - "%s: Silicon Labs Si2157/Si2158 successfully attached\n", - KBUILD_MODNAME); + "Silicon Labs Si2157/Si2158 successfully attached\n"); return 0; err: - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(s); return ret; @@ -348,7 +346,7 @@ static int si2157_remove(struct i2c_client *client) struct si2157 *s = i2c_get_clientdata(client); struct dvb_frontend *fe = s->fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; -- cgit v1.2.3 From 79d0933032d657e8f80e916b14b47b03731d6bea Mon Sep 17 00:00:00 2001 From: "nibble.max" Date: Mon, 11 Aug 2014 01:22:45 -0300 Subject: [media] m88ds3103: implement set voltage and TS clock Implement set voltage operation. Separate TS clock as a own configuration parameter. Add TS clock polarity parameter. [crope@iki.fi: merge em28xx driver m88ds3103 config change patch to that one, in order to keep build unbroken] Signed-off-by: Nibble Max Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 72 ++++++++++++++++++++------------- drivers/media/dvb-frontends/m88ds3103.h | 35 +++++++++++++--- drivers/media/usb/em28xx/em28xx-dvb.c | 4 +- 3 files changed, 78 insertions(+), 33 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index dfe0c2f7f1ef..238b04eb1f5a 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -247,7 +247,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u8 u8tmp, u8tmp1, u8tmp2; u8 buf[2]; u16 u16tmp, divide_ratio; - u32 tuner_frequency, target_mclk, ts_clk; + u32 tuner_frequency, target_mclk; s32 s32tmp; dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", @@ -316,9 +316,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) target_mclk = 144000; break; case M88DS3103_TS_PARALLEL: - case M88DS3103_TS_PARALLEL_12: - case M88DS3103_TS_PARALLEL_16: - case M88DS3103_TS_PARALLEL_19_2: case M88DS3103_TS_CI: if (c->symbol_rate < 18000000) target_mclk = 96000; @@ -352,33 +349,17 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) switch (priv->cfg->ts_mode) { case M88DS3103_TS_SERIAL: u8tmp1 = 0x00; - ts_clk = 0; - u8tmp = 0x46; + u8tmp = 0x06; break; case M88DS3103_TS_SERIAL_D7: u8tmp1 = 0x20; - ts_clk = 0; - u8tmp = 0x46; + u8tmp = 0x06; break; case M88DS3103_TS_PARALLEL: - ts_clk = 24000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_12: - ts_clk = 12000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_16: - ts_clk = 16000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_19_2: - ts_clk = 19200; - u8tmp = 0x42; + u8tmp = 0x02; break; case M88DS3103_TS_CI: - ts_clk = 6000; - u8tmp = 0x43; + u8tmp = 0x03; break; default: dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__); @@ -386,6 +367,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } + if (priv->cfg->ts_clk_pol) + u8tmp |= 0x40; + /* TS mode */ ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp); if (ret) @@ -399,8 +383,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } - if (ts_clk) { - divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk); + if (priv->cfg->ts_clk) { + divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk); u8tmp1 = divide_ratio / 2; u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); } else { @@ -411,7 +395,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) dev_dbg(&priv->i2c->dev, "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n", - __func__, target_mclk, ts_clk, divide_ratio); + __func__, target_mclk, priv->cfg->ts_clk, divide_ratio); u8tmp1--; u8tmp2--; @@ -1053,6 +1037,39 @@ err: return ret; } +static int m88ds3103_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct m88ds3103_priv *priv = fe->demodulator_priv; + u8 data; + + m88ds3103_rd_reg(priv, 0xa2, &data); + + data &= ~0x03; /* bit0 V/H, bit1 off/on */ + if (priv->cfg->lnb_en_pol) + data |= 0x02; + + switch (voltage) { + case SEC_VOLTAGE_18: + if (priv->cfg->lnb_hv_pol == 0) + data |= 0x01; + break; + case SEC_VOLTAGE_13: + if (priv->cfg->lnb_hv_pol) + data |= 0x01; + break; + case SEC_VOLTAGE_OFF: + if (priv->cfg->lnb_en_pol) + data &= ~0x02; + else + data |= 0x02; + break; + } + m88ds3103_wr_reg(priv, 0xa2, data); + + return 0; +} + static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *diseqc_cmd) { @@ -1370,6 +1387,7 @@ static struct dvb_frontend_ops m88ds3103_ops = { .diseqc_send_burst = m88ds3103_diseqc_send_burst, .set_tone = m88ds3103_set_tone, + .set_voltage = m88ds3103_set_voltage, }; MODULE_AUTHOR("Antti Palosaari "); diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h index bbb7e3aa5675..9b3b4962da7c 100644 --- a/drivers/media/dvb-frontends/m88ds3103.h +++ b/drivers/media/dvb-frontends/m88ds3103.h @@ -47,13 +47,22 @@ struct m88ds3103_config { */ #define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */ #define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */ -#define M88DS3103_TS_PARALLEL 2 /* 24 MHz, normal */ -#define M88DS3103_TS_PARALLEL_12 3 /* 12 MHz */ -#define M88DS3103_TS_PARALLEL_16 4 /* 16 MHz */ -#define M88DS3103_TS_PARALLEL_19_2 5 /* 19.2 MHz */ -#define M88DS3103_TS_CI 6 /* 6 MHz */ +#define M88DS3103_TS_PARALLEL 2 /* TS Parallel mode */ +#define M88DS3103_TS_CI 3 /* TS CI Mode */ u8 ts_mode; + /* + * TS clk in KHz + * Default: 0. + */ + u32 ts_clk; + + /* + * TS clk polarity. + * Default: 0. 1-active at falling edge; 0-active at rising edge. + */ + u8 ts_clk_pol:1; + /* * spectrum inversion * Default: 0 @@ -86,6 +95,22 @@ struct m88ds3103_config { * Default: none, must set */ u8 agc; + + /* + * LNB H/V pin polarity + * Default: 0. + * 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18. + * 0: pin high set to VOLTAGE_18, pin low to set VOLTAGE_13. + */ + u8 lnb_hv_pol:1; + + /* + * LNB enable pin polarity + * Default: 0. + * 1: pin high to enable, pin low to disable. + * 0: pin high to disable, pin low to enable. + */ + u8 lnb_en_pol:1; }; /* diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 3a3e243edf89..d8e9760717de 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -856,7 +856,9 @@ static const struct m88ds3103_config pctv_461e_m88ds3103_config = { .clock = 27000000, .i2c_wr_max = 33, .clock_out = 0, - .ts_mode = M88DS3103_TS_PARALLEL_16, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, .agc = 0x99, }; -- cgit v1.2.3 From 389ce3984b337690ed5124f2379fc8c3f3975c53 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:10 -0300 Subject: [media] si2168: add ts_mode setting and move to si2168_init Luis Alves submitted a TS mode patch to si2168 earlier, but the patch was rejected due to a small issue. Here is a working version. Also, setting of TS mode is moved from si2168_set_frontend to si2168_init. This patch adds the TS mode as a config option for the si2168 demod: - ts_mode added to config struct. - Possible (interesting) values are * Parallel mode = 0x06 * Serial mode = 0x03 Currently the modules using this demod only use parallel mode. Patches for these modules later in this patch series. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 17 ++++++++++------- drivers/media/dvb-frontends/si2168.h | 6 ++++++ drivers/media/dvb-frontends/si2168_priv.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 59a4218459da..97614db4d9b3 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -296,13 +296,6 @@ static int si2168_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); - if (ret) - goto err; - memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6); cmd.wlen = 6; cmd.rlen = 4; @@ -464,6 +457,15 @@ static int si2168_init(struct dvb_frontend *fe) dev_info(&s->client->dev, "found a '%s' in warm state\n", si2168_ops.info.name); + /* set ts mode */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + cmd.args[4] |= s->ts_mode; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + s->active = true; return 0; @@ -630,6 +632,7 @@ static int si2168_probe(struct i2c_client *client, *config->i2c_adapter = s->adapter; *config->fe = &s->fe; + s->ts_mode = config->ts_mode; i2c_set_clientdata(client, s); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3c5b5ab01796..e086d6719451 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -34,6 +34,12 @@ struct si2168_config { * returned by driver */ struct i2c_adapter **i2c_adapter; + + /* TS mode */ + u8 ts_mode; }; +#define SI2168_TS_PARALLEL 0x06 +#define SI2168_TS_SERIAL 0x03 + #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index ebbf502ec313..0f832844b831 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -36,6 +36,7 @@ struct si2168 { fe_delivery_system_t delivery_system; fe_status_t fe_status; bool active; + u8 ts_mode; }; /* firmare command struct */ -- cgit v1.2.3 From 6fd2f44a000b514f7ad67e15efaccf9502e29883 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:11 -0300 Subject: [media] em28xx: add ts mode setting for PCTV 292e TS mode must be set in the existing PCTV 292e driver. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index d8e9760717de..06457934a48c 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1535,6 +1535,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demod */ si2168_config.i2c_adapter = &adapter; si2168_config.fe = &dvb->fe[0]; + si2168_config.ts_mode = SI2168_TS_PARALLEL; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE); info.addr = 0x64; -- cgit v1.2.3 From 9b9beb1bf5eab918d2d54e42360dd1803b00dbfd Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:12 -0300 Subject: [media] cxusb: add ts mode setting for TechnoTrend CT2-4400 TS mode must be set in the existing TechnoTrend CT2-4400 driver. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 16bc579d1404..87842e9cdb49 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1369,6 +1369,7 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) /* attach frontend */ si2168_config.i2c_adapter = &adapter; si2168_config.fe = &adap->fe_adap[0].fe; + si2168_config.ts_mode = SI2168_TS_PARALLEL; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE); info.addr = 0x64; -- cgit v1.2.3 From 868736ad3404b205794bc04233eca58293818dea Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Fri, 8 Aug 2014 04:06:35 -0300 Subject: [media] sp2: Add I2C driver for CIMaX SP2 common interface module Driver for the CIMaX SP2 common interface chip. It is very much based on the existing cimax2 driver for cx23885, but should be more reusable. The product has been sold with name Atmel T90FJR as well and the data sheets for that chip seem to be publicly available. It seems that the USB device that I have and the cx23885 based devices will need to interact differently with the chip for the CAM operations. Thus there is one callback function that is passed on to the sp2 driver (see function sp2_ci_op_cam for that one). IRQ functionality is not included currently (not needed by USB devices and I don't have a PCIe device for development). Signed-off-by: Olli Salonen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 7 + drivers/media/dvb-frontends/Makefile | 1 + drivers/media/dvb-frontends/sp2.c | 441 +++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/sp2.h | 53 ++++ drivers/media/dvb-frontends/sp2_priv.h | 50 ++++ 5 files changed, 552 insertions(+) create mode 100644 drivers/media/dvb-frontends/sp2.c create mode 100644 drivers/media/dvb-frontends/sp2.h create mode 100644 drivers/media/dvb-frontends/sp2_priv.h diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index aa5ae224626a..704403f892d5 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -725,6 +725,13 @@ config DVB_A8293 depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT +config DVB_SP2 + tristate "CIMaX SP2" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + CIMaX SP2/SP2HF Common Interface module. + config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index fc4e689d4b67..1e19a74d1f60 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o obj-$(CONFIG_DVB_SI2165) += si2165.o obj-$(CONFIG_DVB_A8293) += a8293.o +obj-$(CONFIG_DVB_SP2) += sp2.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o obj-$(CONFIG_DVB_RTL2830) += rtl2830.o obj-$(CONFIG_DVB_RTL2832) += rtl2832.o diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c new file mode 100644 index 000000000000..9b684d5c8f91 --- /dev/null +++ b/drivers/media/dvb-frontends/sp2.c @@ -0,0 +1,441 @@ +/* + * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver + * + * Copyright (C) 2014 Olli Salonen + * + * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual + * DVB-S2 CI card (cimax2) with following copyrights: + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin + * Copyright (C) 2009 Abylay Ospan + * + * 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 "sp2_priv.h" + +static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) +{ + int ret; + struct i2c_client *client = s->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1 + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len + } + }; + + ret = i2c_transfer(adap, msg, 2); + + if (ret != 2) { + dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n", + reg, ret); + if (ret < 0) + return ret; + else + return -EIO; + } + + dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n", + client->addr, reg, buf[0]); + + return 0; +} + +static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) +{ + int ret; + u8 buffer[35]; + struct i2c_client *client = s->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .buf = &buffer[0], + .len = len + 1 + }; + + if ((len + 1) > sizeof(buffer)) { + dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n", + reg, len); + return -EINVAL; + } + + buffer[0] = reg; + memcpy(&buffer[1], buf, len); + + ret = i2c_transfer(adap, &msg, 1); + + if (ret != 1) { + dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n", + reg, ret); + if (ret < 0) + return ret; + else + return -EIO; + } + + return 0; +} + +static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, + u8 read, int addr, u8 data) +{ + struct sp2 *s = en50221->data; + u8 store; + int mem, ret; + int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control; + + dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x", + slot, acs, addr, data); + + if (slot != 0) + return -EINVAL; + + /* + * change module access type between IO space and attribute memory + * when needed + */ + if (s->module_access_type != acs) { + ret = sp2_read_i2c(s, 0x00, &store, 1); + + if (ret) + return ret; + + store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0); + store |= acs; + + ret = sp2_write_i2c(s, 0x00, &store, 1); + if (ret) + return ret; + } + + s->module_access_type = acs; + + /* implementation of ci_op_cam is device specific */ + if (ci_op_cam) { + ret = ci_op_cam(s->priv, read, addr, data, &mem); + } else { + dev_err(&s->client->dev, "callback not defined"); + return -EINVAL; + } + + if (ret) + return ret; + + if (read) { + dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x", + addr, mem); + return mem; + } else { + return 0; + } +} + +int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, + SP2_CI_RD, addr, 0); +} + +int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, + SP2_CI_WR, addr, data); +} + +int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, + SP2_CI_RD, addr, 0); +} + +int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr, u8 data) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, + SP2_CI_WR, addr, data); +} + +int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + u8 buf; + int ret; + + dev_dbg(&s->client->dev, "slot: %d\n", slot); + + if (slot != 0) + return -EINVAL; + + /* RST on */ + buf = SP2_MOD_CTL_RST; + ret = sp2_write_i2c(s, 0x00, &buf, 1); + + if (ret) + return ret; + + usleep_range(500, 600); + + /* RST off */ + buf = 0x00; + ret = sp2_write_i2c(s, 0x00, &buf, 1); + + if (ret) + return ret; + + msleep(1000); + + return 0; +} + +int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + + dev_dbg(&s->client->dev, "slot:%d\n", slot); + + /* not implemented */ + return 0; +} + +int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + u8 buf; + + dev_dbg(&s->client->dev, "slot:%d\n", slot); + + if (slot != 0) + return -EINVAL; + + sp2_read_i2c(s, 0x00, &buf, 1); + + /* disable bypass and enable TS */ + buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN); + return sp2_write_i2c(s, 0, &buf, 1); +} + +int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open) +{ + struct sp2 *s = en50221->data; + u8 buf[2]; + int ret; + + dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open); + + /* + * CAM module INSERT/REMOVE processing. Slow operation because of i2c + * transfers. Throttle read to one per sec. + */ + if (time_after(jiffies, s->next_status_checked_time)) { + ret = sp2_read_i2c(s, 0x00, buf, 1); + s->next_status_checked_time = jiffies + msecs_to_jiffies(1000); + + if (ret) + return 0; + + if (buf[0] & SP2_MOD_CTL_DET) + s->status = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + else + s->status = 0; + } + + return s->status; +} + +int sp2_init(struct sp2 *s) +{ + int ret = 0; + u8 buf; + u8 cimax_init[34] = { + 0x00, /* module A control*/ + 0x00, /* auto select mask high A */ + 0x00, /* auto select mask low A */ + 0x00, /* auto select pattern high A */ + 0x00, /* auto select pattern low A */ + 0x44, /* memory access time A, 600 ns */ + 0x00, /* invert input A */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* module B control*/ + 0x00, /* auto select mask high B */ + 0x00, /* auto select mask low B */ + 0x00, /* auto select pattern high B */ + 0x00, /* auto select pattern low B */ + 0x44, /* memory access time B, 600 ns */ + 0x00, /* invert input B */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* auto select mask high Ext */ + 0x00, /* auto select mask low Ext */ + 0x00, /* auto select pattern high Ext */ + 0x00, /* auto select pattern low Ext */ + 0x00, /* RFU */ + 0x02, /* destination - module A */ + 0x01, /* power control reg, VCC power on */ + 0x00, /* RFU */ + 0x00, /* int status read only */ + 0x00, /* Interrupt Mask Register */ + 0x05, /* EXTINT=active-high, INT=push-pull */ + 0x00, /* USCG1 */ + 0x04, /* ack active low */ + 0x00, /* LOCK = 0 */ + 0x22, /* unknown */ + 0x00, /* synchronization? */ + }; + + dev_dbg(&s->client->dev, "\n"); + + s->ca.owner = THIS_MODULE; + s->ca.read_attribute_mem = sp2_ci_read_attribute_mem; + s->ca.write_attribute_mem = sp2_ci_write_attribute_mem; + s->ca.read_cam_control = sp2_ci_read_cam_control; + s->ca.write_cam_control = sp2_ci_write_cam_control; + s->ca.slot_reset = sp2_ci_slot_reset; + s->ca.slot_shutdown = sp2_ci_slot_shutdown; + s->ca.slot_ts_enable = sp2_ci_slot_ts_enable; + s->ca.poll_slot_status = sp2_ci_poll_slot_status; + s->ca.data = s; + s->module_access_type = 0; + + /* initialize all regs */ + ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34); + if (ret) + goto err; + + /* lock registers */ + buf = 1; + ret = sp2_write_i2c(s, 0x1f, &buf, 1); + if (ret) + goto err; + + /* power on slots */ + ret = sp2_write_i2c(s, 0x18, &buf, 1); + if (ret) + goto err; + + ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1); + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&s->client->dev, "init failed=%d\n", ret); + return ret; +} + +int sp2_exit(struct i2c_client *client) +{ + struct sp2 *s; + + dev_dbg(&client->dev, "\n"); + + if (client == NULL) + return 0; + + s = i2c_get_clientdata(client); + if (s == NULL) + return 0; + + if (s->ca.data == NULL) + return 0; + + dvb_ca_en50221_release(&s->ca); + + return 0; +} + +static int sp2_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sp2_config *cfg = client->dev.platform_data; + struct sp2 *s; + int ret; + + dev_dbg(&client->dev, "\n"); + + s = kzalloc(sizeof(struct sp2), GFP_KERNEL); + if (!s) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; + } + + s->client = client; + s->dvb_adap = cfg->dvb_adap; + s->priv = cfg->priv; + s->ci_control = cfg->ci_control; + + i2c_set_clientdata(client, s); + + ret = sp2_init(s); + if (ret) + goto err; + + dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n"); + return 0; +err: + dev_dbg(&client->dev, "init failed=%d\n", ret); + kfree(s); + + return ret; +} + +static int sp2_remove(struct i2c_client *client) +{ + struct si2157 *s = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + sp2_exit(client); + if (s != NULL) + kfree(s); + + return 0; +} + +static const struct i2c_device_id sp2_id[] = { + {"sp2", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, sp2_id); + +static struct i2c_driver sp2_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sp2", + }, + .probe = sp2_probe, + .remove = sp2_remove, + .id_table = sp2_id, +}; + +module_i2c_driver(sp2_driver); + +MODULE_DESCRIPTION("CIMaX SP2/HF CI driver"); +MODULE_AUTHOR("Olli Salonen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/sp2.h b/drivers/media/dvb-frontends/sp2.h new file mode 100644 index 000000000000..6cceea022d49 --- /dev/null +++ b/drivers/media/dvb-frontends/sp2.h @@ -0,0 +1,53 @@ +/* + * CIMaX SP2/HF CI driver + * + * Copyright (C) 2014 Olli Salonen + * + * 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. + */ + +#ifndef SP2_H +#define SP2_H + +#include +#include "dvb_ca_en50221.h" + +/* + * I2C address + * 0x40 (port 0) + * 0x41 (port 1) + */ +struct sp2_config { + /* dvb_adapter to attach the ci to */ + struct dvb_adapter *dvb_adap; + + /* function ci_control handles the device specific ci ops */ + void *ci_control; + + /* priv is passed back to function ci_control */ + void *priv; +}; + +extern int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr); +extern int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data); +extern int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr); +extern int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr, u8 data); +extern int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open); + +#endif diff --git a/drivers/media/dvb-frontends/sp2_priv.h b/drivers/media/dvb-frontends/sp2_priv.h new file mode 100644 index 000000000000..37fef7bcd63f --- /dev/null +++ b/drivers/media/dvb-frontends/sp2_priv.h @@ -0,0 +1,50 @@ +/* + * CIMaX SP2/HF CI driver + * + * Copyright (C) 2014 Olli Salonen + * + * 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. + */ + +#ifndef SP2_PRIV_H +#define SP2_PRIV_H + +#include "sp2.h" +#include "dvb_frontend.h" + +/* state struct */ +struct sp2 { + int status; + struct i2c_client *client; + struct dvb_adapter *dvb_adap; + struct dvb_ca_en50221 ca; + int module_access_type; + unsigned long next_status_checked_time; + void *priv; + void *ci_control; +}; + +#define SP2_CI_ATTR_ACS 0x00 +#define SP2_CI_IO_ACS 0x04 +#define SP2_CI_WR 0 +#define SP2_CI_RD 1 + +/* Module control register (0x00 module A, 0x09 module B) bits */ +#define SP2_MOD_CTL_DET 0x01 +#define SP2_MOD_CTL_AUTO 0x02 +#define SP2_MOD_CTL_ACS0 0x04 +#define SP2_MOD_CTL_ACS1 0x08 +#define SP2_MOD_CTL_HAD 0x10 +#define SP2_MOD_CTL_TSIEN 0x20 +#define SP2_MOD_CTL_TSOEN 0x40 +#define SP2_MOD_CTL_RST 0x80 + +#endif -- cgit v1.2.3 From 6832d11edde3e47ef54e0da5d61380de9043b704 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Fri, 8 Aug 2014 04:06:37 -0300 Subject: [media] cxusb: Add support for TechnoTrend TT-connect CT2-4650 CI TechnoTrend TT-connect CT2-4650 CI (0b48:3012) is an USB DVB-T2/C tuner with the following components: USB interface: Cypress CY7C68013A-56LTXC Demodulator: Silicon Labs Si2168-A20 Tuner: Silicon Labs Si2158-A20 CI chip: CIMaX SP2HF The firmware for the tuner is the same as for TechnoTrend TT-TVStick CT2-4400. See https://www.mail-archive.com/linux-media@vger.kernel.org/msg76944.html The demodulator needs a firmware that can be extracted from the Windows drivers. File ttConnect4650_64.sys should be extracted from http://www.tt-downloads.de/bda-treiber_4.1.0.4.zip (MD5 sum below). 3464bfc37a47b4032568718bacba23fb ttConnect4650_64.sys Then the firmware can be extracted: dd if=ttConnect4650_64.sys ibs=1 skip=273376 count=6424 of=dvb-demod-si2168-a20-01.fw The SP2 CI module requires a definition of a function cxusb_tt_ct2_4650_ci_ctrl that is passed on to the SP2 driver and called back for CAM operations. [crope@iki.fi: meld USB ID define patch to this] Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb-usb-ids.h | 1 + drivers/media/usb/dvb-usb/Kconfig | 2 +- drivers/media/usb/dvb-usb/cxusb.c | 92 +++++++++++++++++++++++++++++++++++- drivers/media/usb/dvb-usb/cxusb.h | 4 ++ 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 5135a096bfa6..b7a9b98db414 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -244,6 +244,7 @@ #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d +#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 10aef2188fbe..41d3eb922a00 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -130,7 +130,7 @@ config DVB_USB_CXUSB Medion MD95700 hybrid USB2.0 device. DViCO FusionHDTV (Bluebird) USB2.0 devices - TechnoTrend TVStick CT2-4400 + TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 87842e9cdb49..4ab34590c2c7 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -44,6 +44,7 @@ #include "atbm8830.h" #include "si2168.h" #include "si2157.h" +#include "sp2.h" /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 80 @@ -672,6 +673,37 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { { 0x0025, KEY_POWER }, }; +static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr, + u8 data, int *mem) +{ + struct dvb_usb_device *d = priv; + u8 wbuf[3]; + u8 rbuf[2]; + int ret; + + wbuf[0] = (addr >> 8) & 0xff; + wbuf[1] = addr & 0xff; + + if (read) { + ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2); + } else { + wbuf[2] = data; + ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1); + } + + if (ret) + goto err; + + if (read) + *mem = rbuf[1]; + + return 0; +err: + deb_info("%s: ci usb write returned %d\n", __func__, ret); + return ret; + +} + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -1350,9 +1382,12 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *adapter; struct i2c_client *client_demod; struct i2c_client *client_tuner; + struct i2c_client *client_ci; struct i2c_board_info info; struct si2168_config si2168_config; struct si2157_config si2157_config; + struct sp2_config sp2_config; + u8 o[2], i; /* reset the tuner */ if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) { @@ -1409,6 +1444,48 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) st->i2c_client_tuner = client_tuner; + /* initialize CI */ + if (d->udev->descriptor.idProduct == + USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) { + + memcpy(o, "\xc0\x01", 2); + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + msleep(100); + + memcpy(o, "\xc0\x00", 2); + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + msleep(100); + + memset(&sp2_config, 0, sizeof(sp2_config)); + sp2_config.dvb_adap = &adap->dvb_adap; + sp2_config.priv = d; + sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "sp2", I2C_NAME_SIZE); + info.addr = 0x40; + info.platform_data = &sp2_config; + request_module(info.type); + client_ci = i2c_new_device(&d->i2c_adap, &info); + if (client_ci == NULL || client_ci->dev.driver == NULL) { + module_put(client_tuner->dev.driver->owner); + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + if (!try_module_get(client_ci->dev.driver->owner)) { + i2c_unregister_device(client_ci); + module_put(client_tuner->dev.driver->owner); + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + + st->i2c_client_ci = client_ci; + + } + return 0; } @@ -1538,6 +1615,13 @@ static void cxusb_disconnect(struct usb_interface *intf) struct cxusb_state *st = d->priv; struct i2c_client *client; + /* remove I2C client for CI */ + client = st->i2c_client_ci; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + /* remove I2C client for tuner */ client = st->i2c_client_tuner; if (client) { @@ -1577,6 +1661,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) }, + { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -2266,13 +2351,18 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = { .rc_interval = 150, }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "TechnoTrend TVStick CT2-4400", { NULL }, { &cxusb_table[20], NULL }, }, + { + "TechnoTrend TT-connect CT2-4650 CI", + { NULL }, + { &cxusb_table[21], NULL }, + }, } }; diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 527ff7905e15..29f3e2ea2476 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -28,10 +28,14 @@ #define CMD_ANALOG 0x50 #define CMD_DIGITAL 0x51 +#define CMD_SP2_CI_WRITE 0x70 +#define CMD_SP2_CI_READ 0x71 + struct cxusb_state { u8 gpio_write_state[3]; struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; + struct i2c_client *i2c_client_ci; }; #endif -- cgit v1.2.3 From a45c2994d5980ad53234589935df15e4f6682704 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Thu, 21 Aug 2014 09:05:01 -0300 Subject: [media] cxusb: Add read_mac_address for TT CT2-4400 and CT2-4650 Read MAC address from the EEPROM. This version two corrects a flaw in the result code returning that did exist in the first version. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 4ab34590c2c7..187d52942ebb 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -673,6 +673,39 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { { 0x0025, KEY_POWER }, }; +static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + u8 wbuf[2]; + u8 rbuf[6]; + int ret; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = wbuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = rbuf, + .len = 6, + } + }; + + wbuf[0] = 0x1e; + wbuf[1] = 0x00; + ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2); + + if (ret == 2) { + memcpy(mac, rbuf, 6); + return 0; + } else { + if (ret < 0) + return ret; + return -EIO; + } +} + static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr, u8 data, int *mem) { @@ -2316,6 +2349,8 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = { .size_of_priv = sizeof(struct cxusb_state), .num_adapters = 1, + .read_mac_address = cxusb_tt_ct2_4400_read_mac_address, + .adapter = { { .num_frontends = 1, -- cgit v1.2.3 From e395e573b3ca028271fb2ee7edf614d45913d948 Mon Sep 17 00:00:00 2001 From: CrazyCat Date: Sat, 16 Aug 2014 18:33:14 -0300 Subject: [media] si2168: DVB-T2 PLP selection implemented DVB-T2 PLP selection implemented for Si2168 demod. Tested with PCTV 292e. Signed-off-by: Evgeny Plehov Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 97614db4d9b3..55a4212aea75 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -167,10 +167,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe) u8 bandwidth, delivery_system; dev_dbg(&s->client->dev, - "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n", + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n", c->delivery_system, c->modulation, c->frequency, c->bandwidth_hz, c->symbol_rate, - c->inversion); + c->inversion, c->stream_id); if (!s->active) { ret = -EAGAIN; @@ -234,6 +234,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe) if (ret) goto err; + if (c->delivery_system == SYS_DVBT2) { + /* select PLP */ + cmd.args[0] = 0x52; + cmd.args[1] = c->stream_id & 0xff; + cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1; + cmd.wlen = 3; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + } + memcpy(cmd.args, "\x51\x03", 2); cmd.wlen = 2; cmd.rlen = 12; -- cgit v1.2.3 From 5cd62db71dcf3a4722959d9f90ca4c5ca09502cb Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Sun, 17 Aug 2014 02:24:49 -0300 Subject: [media] si2157: Add support for delivery system SYS_ATSC Set the property for delivery system also in case of SYS_ATSC. This behaviour is observed in the sniffs taken with Hauppauge HVR-955Q Windows driver. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 2281b7d1f1b5..efb5cced30a5 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -238,6 +238,9 @@ static int si2157_set_params(struct dvb_frontend *fe) bandwidth = 0x0f; switch (c->delivery_system) { + case SYS_ATSC: + delivery_system = 0x00; + break; case SYS_DVBT: case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */ delivery_system = 0x20; -- cgit v1.2.3 From 206ace2288449008742c8ca65f1865e51e83e442 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 11:19:13 -0300 Subject: [media] dvb-usb-v2: remove dvb_usb_device NULL check Reported by Dan Carpenter: The patch d10d1b9ac97b: "[media] dvb_usb_v2: use dev_* logging macros" from Jun 26, 2012, leads to the following Smatch complaint: drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c:31 dvb_usb_v2_generic_io() error: we previously assumed 'd' could be null (see line 29) ... Remove whole check as it must not happen in any case. Driver is totally broken if it does not have valid pointer to device. Reported-by: Dan Carpenter Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 33ff97e708e3..22bdce15ecf3 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -26,7 +26,7 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, { int ret, actual_length; - if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || + if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || !d->props->generic_bulk_ctrl_endpoint_response) { dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); return -EINVAL; -- cgit v1.2.3 From de3f2e2e0ac94c1369722a33e7d7b2ca121ba083 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 12:03:58 -0300 Subject: [media] msi2500: remove unneeded local pointer on msi2500_isoc_init() There is no need to keep local copy of usb_device pointer as we have same pointer stored and available easily from device state. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 26b133414032..71e0960b46c0 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -501,14 +501,12 @@ static void msi2500_isoc_cleanup(struct msi2500_state *s) /* Both v4l2_lock and vb_queue_lock should be locked when calling this */ static int msi2500_isoc_init(struct msi2500_state *s) { - struct usb_device *udev; struct urb *urb; int i, j, ret; dev_dbg(&s->udev->dev, "%s:\n", __func__); s->isoc_errors = 0; - udev = s->udev; ret = usb_set_interface(s->udev, 0, 1); if (ret) @@ -527,10 +525,11 @@ static int msi2500_isoc_init(struct msi2500_state *s) dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb); urb->interval = 1; - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, 0x81); + urb->dev = s->udev; + urb->pipe = usb_rcvisocpipe(s->udev, 0x81); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer = usb_alloc_coherent(udev, ISO_BUFFER_SIZE, + urb->transfer_buffer = usb_alloc_coherent(s->udev, + ISO_BUFFER_SIZE, GFP_KERNEL, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { dev_err(&s->udev->dev, -- cgit v1.2.3 From f538e085138e519e25ae0828bd6c6e7492ce8ca4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 14:02:27 -0300 Subject: [media] m88ts2022: fix 32bit overflow on filter calc Maximum satellite symbol rate used is 45000000Sps which overflows when multiplied by 135. As final calculation result is fraction, we could use mult_frac macro in order to keep calculation inside 32 bit number limits and prevent overflow. Original bug and fix was provided by Nibble Max. I decided to implement it differently as it is now. Reported-by: Nibble Max Tested-by: Nibble Max Cc: Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/m88ts2022.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 40c42dec721b..7a62097aa9ea 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -314,7 +314,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) div_min = gdiv28 * 78 / 100; div_max = clamp_val(div_max, 0U, 63U); - f_3db_hz = c->symbol_rate * 135UL / 200UL; + f_3db_hz = mult_frac(c->symbol_rate, 135, 200); f_3db_hz += 2000000U + (frequency_offset_khz * 1000U); f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U); -- cgit v1.2.3 From 6380b975b76478ee0fd7c43d8833a52dfb5b57eb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 16:22:02 -0300 Subject: [media] m88ts2022: fix coding style issues Fix coding style issues pointed out by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/m88ts2022.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 7a62097aa9ea..f51b107ddf29 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -176,6 +176,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28; u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; u16 u16tmp; + dev_dbg(&priv->client->dev, "%s: frequency=%d symbol_rate=%d rolloff=%d\n", __func__, c->frequency, c->symbol_rate, c->rolloff); @@ -393,6 +394,7 @@ static int m88ts2022_init(struct dvb_frontend *fe) {0x24, 0x02}, {0x12, 0xa0}, }; + dev_dbg(&priv->client->dev, "%s:\n", __func__); ret = m88ts2022_wr_reg(priv, 0x00, 0x01); @@ -448,6 +450,7 @@ static int m88ts2022_sleep(struct dvb_frontend *fe) { struct m88ts2022_priv *priv = fe->tuner_priv; int ret; + dev_dbg(&priv->client->dev, "%s:\n", __func__); ret = m88ts2022_wr_reg(priv, 0x00, 0x00); @@ -462,6 +465,7 @@ err: static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct m88ts2022_priv *priv = fe->tuner_priv; + dev_dbg(&priv->client->dev, "%s:\n", __func__); *frequency = priv->frequency_khz; @@ -471,6 +475,7 @@ static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct m88ts2022_priv *priv = fe->tuner_priv; + dev_dbg(&priv->client->dev, "%s:\n", __func__); *frequency = 0; /* Zero-IF */ @@ -642,6 +647,7 @@ static int m88ts2022_remove(struct i2c_client *client) { struct m88ts2022_priv *priv = i2c_get_clientdata(client); struct dvb_frontend *fe = priv->cfg.fe; + dev_dbg(&client->dev, "%s:\n", __func__); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); -- cgit v1.2.3 From d28677ffbc8443d9a97a50b15989ebbbf00a729e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 21:06:13 -0300 Subject: [media] m88ds3103: change .set_voltage() implementation Add some error checking and implement functionality a little bit differently. Cc: Nibble Max Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 50 ++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 238b04eb1f5a..25d9d979c07c 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1038,36 +1038,54 @@ err: } static int m88ds3103_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + fe_sec_voltage_t fe_sec_voltage) { struct m88ds3103_priv *priv = fe->demodulator_priv; - u8 data; + int ret; + u8 u8tmp; + bool voltage_sel, voltage_dis; - m88ds3103_rd_reg(priv, 0xa2, &data); + dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__, + fe_sec_voltage); - data &= ~0x03; /* bit0 V/H, bit1 off/on */ - if (priv->cfg->lnb_en_pol) - data |= 0x02; + if (!priv->warm) { + ret = -EAGAIN; + goto err; + } - switch (voltage) { + switch (fe_sec_voltage) { case SEC_VOLTAGE_18: - if (priv->cfg->lnb_hv_pol == 0) - data |= 0x01; + voltage_sel = 1; + voltage_dis = 0; break; case SEC_VOLTAGE_13: - if (priv->cfg->lnb_hv_pol) - data |= 0x01; + voltage_sel = 0; + voltage_dis = 0; break; case SEC_VOLTAGE_OFF: - if (priv->cfg->lnb_en_pol) - data &= ~0x02; - else - data |= 0x02; + voltage_sel = 0; + voltage_dis = 1; break; + default: + dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n", + __func__); + ret = -EINVAL; + goto err; } - m88ds3103_wr_reg(priv, 0xa2, data); + + /* output pin polarity */ + voltage_sel ^= priv->cfg->lnb_hv_pol; + voltage_dis ^= priv->cfg->lnb_en_pol; + + u8tmp = voltage_dis << 1 | voltage_sel << 0; + ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03); + if (ret) + goto err; return 0; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + return ret; } static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, -- cgit v1.2.3 From 41b9aa0040526d13e08e2ad79970377afe1d622d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 21:38:29 -0300 Subject: [media] m88ds3103: fix coding style issues Fix coding style issues pointed out by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 25d9d979c07c..6eae2c619843 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -159,6 +159,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, { int ret, i, j; u8 buf[83]; + dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); if (tab_len > 83) { @@ -249,6 +250,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u16 u16tmp, divide_ratio; u32 tuner_frequency, target_mclk; s32 s32tmp; + dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", __func__, c->delivery_system, @@ -520,6 +522,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) const struct firmware *fw = NULL; u8 *fw_file = M88DS3103_FIRMWARE; u8 u8tmp; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); /* set cold state by default */ @@ -632,6 +635,7 @@ static int m88ds3103_sleep(struct dvb_frontend *fe) { struct m88ds3103_priv *priv = fe->demodulator_priv; int ret; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); priv->delivery_system = SYS_UNDEFINED; @@ -666,6 +670,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[3]; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { @@ -841,6 +846,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) u8 buf[3]; u16 noise, signal; u32 noise_tot, signal_tot; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); /* reports SNR in resolution of 0.1 dB */ @@ -917,6 +923,7 @@ static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber) int ret; unsigned int utmp; u8 buf[3], u8tmp; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); switch (c->delivery_system) { @@ -997,6 +1004,7 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe, struct m88ds3103_priv *priv = fe->demodulator_priv; int ret; u8 u8tmp, tone, reg_a1_mask; + dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__, fe_sec_tone_mode); @@ -1094,6 +1102,7 @@ static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, struct m88ds3103_priv *priv = fe->demodulator_priv; int ret, i; u8 u8tmp; + dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__, diseqc_cmd->msg_len, diseqc_cmd->msg); @@ -1165,6 +1174,7 @@ static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, struct m88ds3103_priv *priv = fe->demodulator_priv; int ret, i; u8 u8tmp, burst; + dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__, fe_sec_mini_cmd); @@ -1237,6 +1247,7 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe, static void m88ds3103_release(struct dvb_frontend *fe) { struct m88ds3103_priv *priv = fe->demodulator_priv; + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } -- cgit v1.2.3 From 529a53c6087b3e8648185dfa4491043ec43554d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 25 Jul 2014 06:08:36 -0300 Subject: [media] vb2: fix multiplanar read() with non-zero data_offset If this is a multiplanar buf_type and the plane we want to read has a non-zero data_offset, then that data_offset was not taken into account. Note that read() or write() for formats with more than one plane is currently not allowed, hence the use of 'planes[0]' since this is only relevant for a single-plane format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 5b808e25fc09..7e6aff673a5a 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2955,6 +2955,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ buf->queued = 0; buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) : vb2_plane_size(q->bufs[index], 0); + /* Compensate for data_offset on read in the multiplanar case. */ + if (is_multiplanar && read && + fileio->b.m.planes[0].data_offset < buf->size) { + buf->pos = fileio->b.m.planes[0].data_offset; + buf->size -= buf->pos; + } } else { buf = &fileio->bufs[index]; } -- cgit v1.2.3 From 6a683493e07b2dde304b5c23797abab6e9180a1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 07:52:44 -0300 Subject: [media] vivid.txt: add documentation for the vivid driver The vivid Virtual Video Test Driver helps testing V4L2 applications and can emulate V4L2 hardware. Add the documentation for this driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/vivid.txt | 1109 +++++++++++++++++++++++++++++++++++ 1 file changed, 1109 insertions(+) create mode 100644 Documentation/video4linux/vivid.txt diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt new file mode 100644 index 000000000000..4f1d4424f563 --- /dev/null +++ b/Documentation/video4linux/vivid.txt @@ -0,0 +1,1109 @@ +vivid: Virtual Video Test Driver +================================ + +This driver emulates video4linux hardware of various types: video capture, video +output, vbi capture and output, radio receivers and transmitters and a software +defined radio receiver. In addition a simple framebuffer device is available for +testing capture and output overlays. + +Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs. + +Each input can be a webcam, TV capture device, S-Video capture device or an HDMI +capture device. Each output can be an S-Video output device or an HDMI output +device. + +These inputs and outputs act exactly as a real hardware device would behave. This +allows you to use this driver as a test input for application development, since +you can test the various features without requiring special hardware. + +This document describes the features implemented by this driver: + +- Support for read()/write(), MMAP, USERPTR and DMABUF streaming I/O. +- A large list of test patterns and variations thereof +- Working brightness, contrast, saturation and hue controls +- Support for the alpha color component +- Full colorspace support, including limited/full RGB range +- All possible control types are present +- Support for various pixel aspect ratios and video aspect ratios +- Error injection to test what happens if errors occur +- Supports crop/compose/scale in any combination for both input and output +- Can emulate up to 4K resolutions +- All Field settings are supported for testing interlaced capturing +- Supports all standard YUV and RGB formats, including two multiplanar YUV formats +- Raw and Sliced VBI capture and output support +- Radio receiver and transmitter support, including RDS support +- Software defined radio (SDR) support +- Capture and output overlay support + +These features will be described in more detail below. + + +Table of Contents +----------------- + +Section 1: Configuring the driver +Section 2: Video Capture +Section 2.1: Webcam Input +Section 2.2: TV and S-Video Inputs +Section 2.3: HDMI Input +Section 3: Video Output +Section 3.1: S-Video Output +Section 3.2: HDMI Output +Section 4: VBI Capture +Section 5: VBI Output +Section 6: Radio Receiver +Section 7: Radio Transmitter +Section 8: Software Defined Radio Receiver +Section 9: Controls +Section 9.1: User Controls - Test Controls +Section 9.2: User Controls - Video Capture +Section 9.3: User Controls - Audio +Section 9.4: Vivid Controls +Section 9.4.1: Test Pattern Controls +Section 9.4.2: Capture Feature Selection Controls +Section 9.4.3: Output Feature Selection Controls +Section 9.4.4: Error Injection Controls +Section 9.4.5: VBI Raw Capture Controls +Section 9.5: Digital Video Controls +Section 9.6: FM Radio Receiver Controls +Section 9.7: FM Radio Modulator +Section 10: Video, VBI and RDS Looping +Section 10.1: Video and Sliced VBI looping +Section 10.2: Radio & RDS Looping +Section 11: Cropping, Composing, Scaling +Section 12: Formats +Section 13: Capture Overlay +Section 14: Output Overlay +Section 15: Some Future Improvements + + +Section 1: Configuring the driver +--------------------------------- + +By default the driver will create a single instance that has a video capture +device with webcam, TV, S-Video and HDMI inputs, a video output device with +S-Video and HDMI outputs, one vbi capture device, one vbi output device, one +radio receiver device, one radio transmitter device and one SDR device. + +The number of instances, devices, video inputs and outputs and their types are +all configurable using the following module options: + +n_devs: number of driver instances to create. By default set to 1. Up to 64 + instances can be created. + +node_types: which devices should each driver instance create. An array of + hexadecimal values, one for each instance. The default is 0x1d3d. + Each value is a bitmask with the following meaning: + bit 0: Video Capture node + bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both + bit 4: Radio Receiver node + bit 5: Software Defined Radio Receiver node + bit 8: Video Output node + bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both + bit 12: Radio Transmitter node + bit 16: Framebuffer for testing overlays + + So to create four instances, the first two with just one video capture + device, the second two with just one video output device you would pass + these module options to vivid: + + n_devs=4 node_types=0x1,0x1,0x100,0x100 + +num_inputs: the number of inputs, one for each instance. By default 4 inputs + are created for each video capture device. At most 16 inputs can be created, + and there must be at least one. + +input_types: the input types for each instance, the default is 0xe4. This defines + what the type of each input is when the inputs are created for each driver + instance. This is a hexadecimal value with up to 16 pairs of bits, each + pair gives the type and bits 0-1 map to input 0, bits 2-3 map to input 1, + 30-31 map to input 15. Each pair of bits has the following meaning: + + 00: this is a webcam input + 01: this is a TV tuner input + 10: this is an S-Video input + 11: this is an HDMI input + + So to create a video capture device with 8 inputs where input 0 is a TV + tuner, inputs 1-3 are S-Video inputs and inputs 4-7 are HDMI inputs you + would use the following module options: + + num_inputs=8 input_types=0xffa9 + +num_outputs: the number of outputs, one for each instance. By default 2 outputs + are created for each video output device. At most 16 outputs can be + created, and there must be at least one. + +output_types: the output types for each instance, the default is 0x02. This defines + what the type of each output is when the outputs are created for each + driver instance. This is a hexadecimal value with up to 16 bits, each bit + gives the type and bit 0 maps to output 0, bit 1 maps to output 1, bit + 15 maps to output 15. The meaning of each bit is as follows: + + 0: this is an S-Video output + 1: this is an HDMI output + + So to create a video output device with 8 outputs where outputs 0-3 are + S-Video outputs and outputs 4-7 are HDMI outputs you would use the + following module options: + + num_outputs=8 output_types=0xf0 + +vid_cap_nr: give the desired videoX start number for each video capture device. + The default is -1 which will just take the first free number. This allows + you to map capture video nodes to specific videoX device nodes. Example: + + n_devs=4 vid_cap_nr=2,4,6,8 + + This will attempt to assign /dev/video2 for the video capture device of + the first vivid instance, video4 for the next up to video8 for the last + instance. If it can't succeed, then it will just take the next free + number. + +vid_out_nr: give the desired videoX start number for each video output device. + The default is -1 which will just take the first free number. + +vbi_cap_nr: give the desired vbiX start number for each vbi capture device. + The default is -1 which will just take the first free number. + +vbi_out_nr: give the desired vbiX start number for each vbi output device. + The default is -1 which will just take the first free number. + +radio_rx_nr: give the desired radioX start number for each radio receiver device. + The default is -1 which will just take the first free number. + +radio_tx_nr: give the desired radioX start number for each radio transmitter + device. The default is -1 which will just take the first free number. + +sdr_cap_nr: give the desired swradioX start number for each SDR capture device. + The default is -1 which will just take the first free number. + +ccs_cap_mode: specify the allowed video capture crop/compose/scaling combination + for each driver instance. Video capture devices can have any combination + of cropping, composing and scaling capabilities and this will tell the + vivid driver which of those is should emulate. By default the user can + select this through controls. + + The value is either -1 (controlled by the user) or a set of three bits, + each enabling (1) or disabling (0) one of the features: + + bit 0: Enable crop support. Cropping will take only part of the + incoming picture. + bit 1: Enable compose support. Composing will copy the incoming + picture into a larger buffer. + bit 2: Enable scaling support. Scaling can scale the incoming + picture. The scaler of the vivid driver can enlarge up + or down to four times the original size. The scaler is + very simple and low-quality. Simplicity and speed were + key, not quality. + + Note that this value is ignored by webcam inputs: those enumerate + discrete framesizes and that is incompatible with cropping, composing + or scaling. + +ccs_out_mode: specify the allowed video output crop/compose/scaling combination + for each driver instance. Video output devices can have any combination + of cropping, composing and scaling capabilities and this will tell the + vivid driver which of those is should emulate. By default the user can + select this through controls. + + The value is either -1 (controlled by the user) or a set of three bits, + each enabling (1) or disabling (0) one of the features: + + bit 0: Enable crop support. Cropping will take only part of the + outgoing buffer. + bit 1: Enable compose support. Composing will copy the incoming + buffer into a larger picture frame. + bit 2: Enable scaling support. Scaling can scale the incoming + buffer. The scaler of the vivid driver can enlarge up + or down to four times the original size. The scaler is + very simple and low-quality. Simplicity and speed were + key, not quality. + +multiplanar: select whether each device instance supports multi-planar formats, + and thus the V4L2 multi-planar API. By default the first device instance + is single-planar, the second multi-planar, and it keeps alternating. + + This module option can override that for each instance. Values are: + + 0: use alternating single and multi-planar devices. + 1: this is a single-planar instance. + 2: this is a multi-planar instance. + +vivid_debug: enable driver debugging info + +no_error_inj: if set disable the error injecting controls. This option is + needed in order to run a tool like v4l2-compliance. Tools like that + exercise all controls including a control like 'Disconnect' which + emulates a USB disconnect, making the device inaccessible and so + all tests that v4l2-compliance is doing will fail afterwards. + + There may be other situations as well where you want to disable the + error injection support of vivid. When this option is set, then the + controls that select crop, compose and scale behavior are also + removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the + will default to enabling crop, compose and scaling. + +Taken together, all these module options allow you to precisely customize +the driver behavior and test your application with all sorts of permutations. +It is also very suitable to emulate hardware that is not yet available, e.g. +when developing software for a new upcoming device. + + +Section 2: Video Capture +------------------------ + +This is probably the most frequently used feature. The video capture device +can be configured by using the module options num_inputs, input_types and +ccs_cap_mode (see section 1 for more detailed information), but by default +four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI +input, one input for each input type. Those are described in more detail +below. + +Special attention has been given to the rate at which new frames become +available. The jitter will be around 1 jiffie (that depends on the HZ +configuration of your kernel, so usually 1/100, 1/250 or 1/1000 of a second), +but the long-term behavior is exactly following the framerate. So a +framerate of 59.94 Hz is really different from 60 Hz. If the framerate +exceeds your kernel's HZ value, then you will get dropped frames, but the +frame/field sequence counting will keep track of that so the sequence +count will skip whenever frames are dropped. + + +Section 2.1: Webcam Input +------------------------- + +The webcam input supports three framesizes: 320x180, 640x360 and 1280x720. It +supports frames per second settings of 10, 15, 25, 30, 50 and 60 fps. Which ones +are available depends on the chosen framesize: the larger the framesize, the +lower the maximum frames per second. + +The initially selected colorspace when you switch to the webcam input will be +sRGB. + + +Section 2.2: TV and S-Video Inputs +---------------------------------- + +The only difference between the TV and S-Video input is that the TV has a +tuner. Otherwise they behave identically. + +These inputs support audio inputs as well: one TV and one Line-In. They +both support all TV standards. If the standard is queried, then the Vivid +controls 'Standard Signal Mode' and 'Standard' determine what +the result will be. + +These inputs support all combinations of the field setting. Special care has +been taken to faithfully reproduce how fields are handled for the different +TV standards. This is particularly noticable when generating a horizontally +moving image so the temporal effect of using interlaced formats becomes clearly +visible. For 50 Hz standards the top field is the oldest and the bottom field +is the newest in time. For 60 Hz standards that is reversed: the bottom field +is the oldest and the top field is the newest in time. + +When you start capturing in V4L2_FIELD_ALTERNATE mode the first buffer will +contain the top field for 50 Hz standards and the bottom field for 60 Hz +standards. This is what capture hardware does as well. + +Finally, for PAL/SECAM standards the first half of the top line contains noise. +This simulates the Wide Screen Signal that is commonly placed there. + +The initially selected colorspace when you switch to the TV or S-Video input +will be SMPTE-170M. + +The pixel aspect ratio will depend on the TV standard. The video aspect ratio +can be selected through the 'Standard Aspect Ratio' Vivid control. +Choices are '4x3', '16x9' which will give letterboxed widescreen video and +'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen +video that will need to be scaled accordingly. + +The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available +every 6 MHz, starting from 49.25 MHz. For each channel the generated image +will be in color for the +/- 0.25 MHz around it, and in grayscale for ++/- 1 MHz around the channel. Beyond that it is just noise. The VIDIOC_G_TUNER +ioctl will return 100% signal strength for +/- 0.25 MHz and 50% for +/- 1 MHz. +It will also return correct afc values to show whether the frequency is too +low or too high. + +The audio subchannels that are returned are MONO for the +/- 1 MHz range around +a valid channel frequency. When the frequency is within +/- 0.25 MHz of the +channel it will return either MONO, STEREO, either MONO | SAP (for NTSC) or +LANG1 | LANG2 (for others), or STEREO | SAP. + +Which one is returned depends on the chosen channel, each next valid channel +will cycle through the possible audio subchannel combinations. This allows +you to test the various combinations by just switching channels.. + +Finally, for these inputs the v4l2_timecode struct is filled in in the +dequeued v4l2_buffer struct. + + +Section 2.3: HDMI Input +----------------------- + +The HDMI inputs supports all CEA-861 and DMT timings, both progressive and +interlaced, for pixelclock frequencies between 25 and 600 MHz. The field +mode for interlaced formats is always V4L2_FIELD_ALTERNATE. For HDMI the +field order is always top field first, and when you start capturing an +interlaced format you will receive the top field first. + +The initially selected colorspace when you switch to the HDMI input or +select an HDMI timing is based on the format resolution: for resolutions +less than or equal to 720x576 the colorspace is set to SMPTE-170M, for +others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings). + +The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it +set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV +standard, and for all others a 1:1 pixel aspect ratio is returned. + +The video aspect ratio can be selected through the 'DV Timings Aspect Ratio' +Vivid control. Choices are 'Source Width x Height' (just use the +same ratio as the chosen format), '4x3' or '16x9', either of which can +result in pillarboxed or letterboxed video. + +For HDMI inputs it is possible to set the EDID. By default a simple EDID +is provided. You can only set the EDID for HDMI inputs. Internally, however, +the EDID is shared between all HDMI inputs. + +No interpretation is done of the EDID data. + + +Section 3: Video Output +----------------------- + +The video output device can be configured by using the module options +num_outputs, output_types and ccs_out_mode (see section 1 for more detailed +information), but by default two outputs are configured: an S-Video and an +HDMI input, one output for each output type. Those are described in more detail +below. + +Like with video capture the framerate is also exact in the long term. + + +Section 3.1: S-Video Output +--------------------------- + +This output supports audio outputs as well: "Line-Out 1" and "Line-Out 2". +The S-Video output supports all TV standards. + +This output supports all combinations of the field setting. + +The initially selected colorspace when you switch to the TV or S-Video input +will be SMPTE-170M. + + +Section 3.2: HDMI Output +------------------------ + +The HDMI output supports all CEA-861 and DMT timings, both progressive and +interlaced, for pixelclock frequencies between 25 and 600 MHz. The field +mode for interlaced formats is always V4L2_FIELD_ALTERNATE. + +The initially selected colorspace when you switch to the HDMI output or +select an HDMI timing is based on the format resolution: for resolutions +less than or equal to 720x576 the colorspace is set to SMPTE-170M, for +others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings). + +The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it +set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV +standard, and for all others a 1:1 pixel aspect ratio is returned. + +An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID. + + +Section 4: VBI Capture +---------------------- + +There are three types of VBI capture devices: those that only support raw +(undecoded) VBI, those that only support sliced (decoded) VBI and those that +support both. This is determined by the node_types module option. In all +cases the driver will generate valid VBI data: for 60 Hz standards it will +generate Closed Caption and XDS data. The closed caption stream will +alternate between "Hello world!" and "Closed captions test" every second. +The XDS stream will give the current time once a minute. For 50 Hz standards +it will generate the Wide Screen Signal which is based on the actual Video +Aspect Ratio control setting. + +The VBI device will only work for the S-Video and TV inputs, it will give +back an error if the current input is a webcam or HDMI. + + +Section 5: VBI Output +--------------------- + +There are three types of VBI output devices: those that only support raw +(undecoded) VBI, those that only support sliced (decoded) VBI and those that +support both. This is determined by the node_types module option. + +The sliced VBI output supports the Wide Screen Signal for 50 Hz standards +and Closed Captioning + XDS for 60 Hz standards. + +The VBI device will only work for the S-Video output, it will give +back an error if the current output is HDMI. + + +Section 6: Radio Receiver +------------------------- + +The radio receiver emulates an FM/AM/SW receiver. The FM band also supports RDS. +The frequency ranges are: + + FM: 64 MHz - 108 MHz + AM: 520 kHz - 1710 kHz + SW: 2300 kHz - 26.1 MHz + +Valid channels are emulated every 1 MHz for FM and every 100 kHz for AM and SW. +The signal strength decreases the further the frequency is from the valid +frequency until it becomes 0% at +/- 50 kHz (FM) or 5 kHz (AM/SW) from the +ideal frequency. The initial frequency when the driver is loaded is set to +95 MHz. + +The FM receiver supports RDS as well, both using 'Block I/O' and 'Controls' +modes. In the 'Controls' mode the RDS information is stored in read-only +controls. These controls are updated every time the frequency is changed, +or when the tuner status is requested. The Block I/O method uses the read() +interface to pass the RDS blocks on to the application for decoding. + +The RDS signal is 'detected' for +/- 12.5 kHz around the channel frequency, +and the further the frequency is away from the valid frequency the more RDS +errors are randomly introduced into the block I/O stream, up to 50% of all +blocks if you are +/- 12.5 kHz from the channel frequency. All four errors +can occur in equal proportions: blocks marked 'CORRECTED', blocks marked +'ERROR', blocks marked 'INVALID' and dropped blocks. + +The generated RDS stream contains all the standard fields contained in a +0B group, and also radio text and the current time. + +The receiver supports HW frequency seek, either in Bounded mode, Wrap Around +mode or both, which is configurable with the "Radio HW Seek Mode" control. + + +Section 7: Radio Transmitter +---------------------------- + +The radio transmitter emulates an FM/AM/SW transmitter. The FM band also supports RDS. +The frequency ranges are: + + FM: 64 MHz - 108 MHz + AM: 520 kHz - 1710 kHz + SW: 2300 kHz - 26.1 MHz + +The initial frequency when the driver is loaded is 95.5 MHz. + +The FM transmitter supports RDS as well, both using 'Block I/O' and 'Controls' +modes. In the 'Controls' mode the transmitted RDS information is configured +using controls, and in 'Block I/O' mode the blocks are passed to the driver +using write(). + + +Section 8: Software Defined Radio Receiver +------------------------------------------ + +The SDR receiver has three frequency bands for the ADC tuner: + + - 300 kHz + - 900 kHz - 2800 kHz + - 3200 kHz + +The RF tuner supports 50 MHz - 2000 MHz. + +The generated data contains the In-phase and Quadrature components of a +1 kHz tone that has an amplitude of sqrt(2). + + +Section 9: Controls +------------------- + +Different devices support different controls. The sections below will describe +each control and which devices support them. + + +Section 9.1: User Controls - Test Controls +------------------------------------------ + +The Button, Boolean, Integer 32 Bits, Integer 64 Bits, Menu, String, Bitmask and +Integer Menu are controls that represent all possible control types. The Menu +control and the Integer Menu control both have 'holes' in their menu list, +meaning that one or more menu items return EINVAL when VIDIOC_QUERYMENU is called. +Both menu controls also have a non-zero minimum control value. These features +allow you to check if your application can handle such things correctly. +These controls are supported for every device type. + + +Section 9.2: User Controls - Video Capture +------------------------------------------ + +The following controls are specific to video capture. + +The Brightness, Contrast, Saturation and Hue controls actually work and are +standard. There is one special feature with the Brightness control: each +video input has its own brightness value, so changing input will restore +the brightness for that input. In addition, each video input uses a different +brightness range (minimum and maximum control values). Switching inputs will +cause a control event to be sent with the V4L2_EVENT_CTRL_CH_RANGE flag set. +This allows you to test controls that can change their range. + +The 'Gain, Automatic' and Gain controls can be used to test volatile controls: +if 'Gain, Automatic' is set, then the Gain control is volatile and changes +constantly. If 'Gain, Automatic' is cleared, then the Gain control is a normal +control. + +The 'Horizontal Flip' and 'Vertical Flip' controls can be used to flip the +image. These combine with the 'Sensor Flipped Horizontally/Vertically' Vivid +controls. + +The 'Alpha Component' control can be used to set the alpha component for +formats containing an alpha channel. + + +Section 9.3: User Controls - Audio +---------------------------------- + +The following controls are specific to video capture and output and radio +receivers and transmitters. + +The 'Volume' and 'Mute' audio controls are typical for such devices to +control the volume and mute the audio. They don't actually do anything in +the vivid driver. + + +Section 9.4: Vivid Controls +--------------------------- + +These vivid custom controls control the image generation, error injection, etc. + + +Section 9.4.1: Test Pattern Controls +------------------------------------ + +The Test Pattern Controls are all specific to video capture. + +Test Pattern: selects which test pattern to use. Use the CSC Colorbar for + testing colorspace conversions: the colors used in that test pattern + map to valid colors in all colorspaces. The colorspace conversion + is disabled for the other test patterns. + +OSD Text Mode: selects whether the text superimposed on the + test pattern should be shown, and if so, whether only counters should + be displayed or the full text. + +Horizontal Movement: selects whether the test pattern should + move to the left or right and at what speed. + +Vertical Movement: does the same for the vertical direction. + +Show Border: show a two-pixel wide border at the edge of the actual image, + excluding letter or pillarboxing. + +Show Square: show a square in the middle of the image. If the image is + displayed with the correct pixel and image aspect ratio corrections, + then the width and height of the square on the monitor should be + the same. + +Insert SAV Code in Image: adds a SAV (Start of Active Video) code to the image. + This can be used to check if such codes in the image are inadvertently + interpreted instead of being ignored. + +Insert EAV Code in Image: does the same for the EAV (End of Active Video) code. + + +Section 9.4.2: Capture Feature Selection Controls +------------------------------------------------- + +These controls are all specific to video capture. + +Sensor Flipped Horizontally: the image is flipped horizontally and the + V4L2_IN_ST_HFLIP input status flag is set. This emulates the case where + a sensor is for example mounted upside down. + +Sensor Flipped Vertically: the image is flipped vertically and the + V4L2_IN_ST_VFLIP input status flag is set. This emulates the case where + a sensor is for example mounted upside down. + +Standard Aspect Ratio: selects if the image aspect ratio as used for the TV or + S-Video input should be 4x3, 16x9 or anamorphic widescreen. This may + introduce letterboxing. + +DV Timings Aspect Ratio: selects if the image aspect ratio as used for the HDMI + input should be the same as the source width and height ratio, or if + it should be 4x3 or 16x9. This may introduce letter or pillarboxing. + +Timestamp Source: selects when the timestamp for each buffer is taken. + +Colorspace: selects which colorspace should be used when generating the image. + This only applies if the CSC Colorbar test pattern is selected, + otherwise the test pattern will go through unconverted (except for + the so-called 'Transfer Function' corrections and the R'G'B' to Y'CbCr + conversion). This behavior is also what you want, since a 75% Colorbar + should really have 75% signal intensity and should not be affected + by colorspace conversions. + + Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a detected colorspace change. + +Limited RGB Range (16-235): selects if the RGB range of the HDMI source should + be limited or full range. This combines with the Digital Video 'Rx RGB + Quantization Range' control and can be used to test what happens if + a source provides you with the wrong quantization range information. + See the description of that control for more details. + +Apply Alpha To Red Only: apply the alpha channel as set by the 'Alpha Component' + user control to the red color of the test pattern only. + +Enable Capture Cropping: enables crop support. This control is only present if + the ccs_cap_mode module option is set to the default value of -1 and if + the no_error_inj module option is set to 0 (the default). + +Enable Capture Composing: enables composing support. This control is only + present if the ccs_cap_mode module option is set to the default value of + -1 and if the no_error_inj module option is set to 0 (the default). + +Enable Capture Scaler: enables support for a scaler (maximum 4 times upscaling + and downscaling). This control is only present if the ccs_cap_mode + module option is set to the default value of -1 and if the no_error_inj + module option is set to 0 (the default). + +Maximum EDID Blocks: determines how many EDID blocks the driver supports. + Note that the vivid driver does not actually interpret new EDID + data, it just stores it. It allows for up to 256 EDID blocks + which is the maximum supported by the standard. + +Fill Percentage of Frame: can be used to draw only the top X percent + of the image. Since each frame has to be drawn by the driver, this + demands a lot of the CPU. For large resolutions this becomes + problematic. By drawing only part of the image this CPU load can + be reduced. + + +Section 9.4.3: Output Feature Selection Controls +------------------------------------------------ + +These controls are all specific to video output. + +Enable Output Cropping: enables crop support. This control is only present if + the ccs_out_mode module option is set to the default value of -1 and if + the no_error_inj module option is set to 0 (the default). + +Enable Output Composing: enables composing support. This control is only + present if the ccs_out_mode module option is set to the default value of + -1 and if the no_error_inj module option is set to 0 (the default). + +Enable Output Scaler: enables support for a scaler (maximum 4 times upscaling + and downscaling). This control is only present if the ccs_out_mode + module option is set to the default value of -1 and if the no_error_inj + module option is set to 0 (the default). + + +Section 9.4.4: Error Injection Controls +--------------------------------------- + +The following two controls are only valid for video and vbi capture. + +Standard Signal Mode: selects the behavior of VIDIOC_QUERYSTD: what should + it return? + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input condition (e.g. a cable + was plugged in or out). + +Standard: selects the standard that VIDIOC_QUERYSTD should return if the + previous control is set to "Selected Standard". + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input standard. + + +The following two controls are only valid for video capture. + +DV Timings Signal Mode: selects the behavior of VIDIOC_QUERY_DV_TIMINGS: what + should it return? + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input condition (e.g. a cable + was plugged in or out). + +DV Timings: selects the timings the VIDIOC_QUERY_DV_TIMINGS should return + if the previous control is set to "Selected DV Timings". + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates changed input timings. + + +The following controls are only present if the no_error_inj module option +is set to 0 (the default). These controls are valid for video and vbi +capture and output streams and for the SDR capture device except for the +Disconnect control which is valid for all devices. + +Wrap Sequence Number: test what happens when you wrap the sequence number in + struct v4l2_buffer around. + +Wrap Timestamp: test what happens when you wrap the timestamp in struct + v4l2_buffer around. + +Percentage of Dropped Buffers: sets the percentage of buffers that + are never returned by the driver (i.e., they are dropped). + +Disconnect: emulates a USB disconnect. The device will act as if it has + been disconnected. Only after all open filehandles to the device + node have been closed will the device become 'connected' again. + +Inject V4L2_BUF_FLAG_ERROR: when pressed, the next frame returned by + the driver will have the error flag set (i.e. the frame is marked + corrupt). + +Inject VIDIOC_REQBUFS Error: when pressed, the next REQBUFS or CREATE_BUFS + ioctl call will fail with an error. To be precise: the videobuf2 + queue_setup() op will return -EINVAL. + +Inject VIDIOC_QBUF Error: when pressed, the next VIDIOC_QBUF or + VIDIOC_PREPARE_BUFFER ioctl call will fail with an error. To be + precise: the videobuf2 buf_prepare() op will return -EINVAL. + +Inject VIDIOC_STREAMON Error: when pressed, the next VIDIOC_STREAMON ioctl + call will fail with an error. To be precise: the videobuf2 + start_streaming() op will return -EINVAL. + +Inject Fatal Streaming Error: when pressed, the streaming core will be + marked as having suffered a fatal error, the only way to recover + from that is to stop streaming. To be precise: the videobuf2 + vb2_queue_error() function is called. + + +Section 9.4.5: VBI Raw Capture Controls +--------------------------------------- + +Interlaced VBI Format: if set, then the raw VBI data will be interlaced instead + of providing it grouped by field. + + +Section 9.5: Digital Video Controls +----------------------------------- + +Rx RGB Quantization Range: sets the RGB quantization detection of the HDMI + input. This combines with the Vivid 'Limited RGB Range (16-235)' + control and can be used to test what happens if a source provides + you with the wrong quantization range information. This can be tested + by selecting an HDMI input, setting this control to Full or Limited + range and selecting the opposite in the 'Limited RGB Range (16-235)' + control. The effect is easy to see if the 'Gray Ramp' test pattern + is selected. + +Tx RGB Quantization Range: sets the RGB quantization detection of the HDMI + output. It is currently not used for anything in vivid, but most HDMI + transmitters would typically have this control. + +Transmit Mode: sets the transmit mode of the HDMI output to HDMI or DVI-D. This + affects the reported colorspace since DVI_D outputs will always use + sRGB. + + +Section 9.6: FM Radio Receiver Controls +--------------------------------------- + +RDS Reception: set if the RDS receiver should be enabled. + +RDS Program Type: +RDS PS Name: +RDS Radio Text: +RDS Traffic Announcement: +RDS Traffic Program: +RDS Music: these are all read-only controls. If RDS Rx I/O Mode is set to + "Block I/O", then they are inactive as well. If RDS Rx I/O Mode is set + to "Controls", then these controls report the received RDS data. Note + that the vivid implementation of this is pretty basic: they are only + updated when you set a new frequency or when you get the tuner status + (VIDIOC_G_TUNER). + +Radio HW Seek Mode: can be one of "Bounded", "Wrap Around" or "Both". This + determines if VIDIOC_S_HW_FREQ_SEEK will be bounded by the frequency + range or wrap-around or if it is selectable by the user. + +Radio Programmable HW Seek: if set, then the user can provide the lower and + upper bound of the HW Seek. Otherwise the frequency range boundaries + will be used. + +Generate RBDS Instead of RDS: if set, then generate RBDS (the US variant of + RDS) data instead of RDS (European-style RDS). This affects only the + PICODE and PTY codes. + +RDS Rx I/O Mode: this can be "Block I/O" where the RDS blocks have to be read() + by the application, or "Controls" where the RDS data is provided by + the RDS controls mentioned above. + + +Section 9.7: FM Radio Modulator Controls +---------------------------------------- + +RDS Program ID: +RDS Program Type: +RDS PS Name: +RDS Radio Text: +RDS Stereo: +RDS Artificial Head: +RDS Compressed: +RDS Dymanic PTY: +RDS Traffic Announcement: +RDS Traffic Program: +RDS Music: these are all controls that set the RDS data that is transmitted by + the FM modulator. + +RDS Tx I/O Mode: this can be "Block I/O" where the application has to use write() + to pass the RDS blocks to the driver, or "Controls" where the RDS data is + provided by the RDS controls mentioned above. + + +Section 10: Video, VBI and RDS Looping +-------------------------------------- + +The vivid driver supports looping of video output to video input, VBI output +to VBI input and RDS output to RDS input. For video/VBI looping this emulates +as if a cable was hooked up between the output and input connector. So video +and VBI looping is only supported between S-Video and HDMI inputs and outputs. +VBI is only valid for S-Video as it makes no sense for HDMI. + +Since radio is wireless this looping always happens if the radio receiver +frequency is close to the radio transmitter frequency. In that case the radio +transmitter will 'override' the emulated radio stations. + +Looping is currently supported only between devices created by the same +vivid driver instance. + + +Section 10.1: Video and Sliced VBI looping +------------------------------------------ + +The way to enable video/VBI looping is currently fairly crude. A 'Loop Video' +control is available in the "Vivid" control class of the video +output and VBI output devices. When checked the video looping will be enabled. +Once enabled any video S-Video or HDMI input will show a static test pattern +until the video output has started. At that time the video output will be +looped to the video input provided that: + +- the input type matches the output type. So the HDMI input cannot receive + video from the S-Video output. + +- the video resolution of the video input must match that of the video output. + So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz + (720x480) S-Video input, or a 720p60 HDMI output to a 1080p30 input. + +- the pixel formats must be identical on both sides. Otherwise the driver would + have to do pixel format conversion as well, and that's taking things too far. + +- the field settings must be identical on both sides. Same reason as above: + requiring the driver to convert from one field format to another complicated + matters too much. This also prohibits capturing with 'Field Top' or 'Field + Bottom' when the output video is set to 'Field Alternate'. This combination, + while legal, became too complicated to support. Both sides have to be 'Field + Alternate' for this to work. Also note that for this specific case the + sequence and field counting in struct v4l2_buffer on the capture side may not + be 100% accurate. + +- on the input side the "Standard Signal Mode" for the S-Video input or the + "DV Timings Signal Mode" for the HDMI input should be configured so that a + valid signal is passed to the video input. + +The framerates do not have to match, although this might change in the future. + +By default you will see the OSD text superimposed on top of the looped video. +This can be turned off by changing the "OSD Text Mode" control of the video +capture device. + +For VBI looping to work all of the above must be valid and in addition the vbi +output must be configured for sliced VBI. The VBI capture side can be configured +for either raw or sliced VBI. + + +Section 10.2: Radio & RDS Looping +--------------------------------- + +As mentioned in section 6 the radio receiver emulates stations are regular +frequency intervals. Depending on the frequency of the radio receiver a +signal strength value is calculated (this is returned by VIDIOC_G_TUNER). +However, it will also look at the frequency set by the radio transmitter and +if that results in a higher signal strength than the settings of the radio +transmitter will be used as if it was a valid station. This also includes +the RDS data (if any) that the transmitter 'transmits'. This is received +faithfully on the receiver side. Note that when the driver is loaded the +frequencies of the radio receiver and transmitter are not identical, so +initially no looping takes place. + + +Section 11: Cropping, Composing, Scaling +---------------------------------------- + +This driver supports cropping, composing and scaling in any combination. Normally +which features are supported can be selected through the Vivid controls, +but it is also possible to hardcode it when the module is loaded through the +ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of +these module options. + +This allows you to test your application for all these variations. + +Note that the webcam input never supports cropping, composing or scaling. That +only applies to the TV/S-Video/HDMI inputs and outputs. The reason is that +webcams, including this virtual implementation, normally use +VIDIOC_ENUM_FRAMESIZES to list a set of discrete framesizes that it supports. +And that does not combine with cropping, composing or scaling. This is +primarily a limitation of the V4L2 API which is carefully reproduced here. + +The minimum and maximum resolutions that the scaler can achieve are 16x16 and +(4096 * 4) x (2160 x 4), but it can only scale up or down by a factor of 4 or +less. So for a source resolution of 1280x720 the minimum the scaler can do is +320x180 and the maximum is 5120x2880. You can play around with this using the +qv4l2 test tool and you will see these dependencies. + +This driver also supports larger 'bytesperline' settings, something that +VIDIOC_S_FMT allows but that few drivers implement. + +The scaler is a simple scaler that uses the Coarse Bresenham algorithm. It's +designed for speed and simplicity, not quality. + +If the combination of crop, compose and scaling allows it, then it is possible +to change crop and compose rectangles on the fly. + + +Section 12: Formats +------------------- + +The driver supports all the regular packed YUYV formats, 16, 24 and 32 RGB +packed formats and two multiplanar formats (one luma and one chroma plane). + +The alpha component can be set through the 'Alpha Component' User control +for those formats that support it. If the 'Apply Alpha To Red Only' control +is set, then the alpha component is only used for the color red and set to +0 otherwise. + +The driver has to be configured to support the multiplanar formats. By default +the first driver instance is single-planar, the second is multi-planar, and it +keeps alternating. This can be changed by setting the multiplanar module option, +see section 1 for more details on that option. + +If the driver instance is using the multiplanar formats/API, then the first +single planar format (YUYV) and the multiplanar NV16M and NV61M formats the +will have a plane that has a non-zero data_offset of 128 bytes. It is rare for +data_offset to be non-zero, so this is a useful feature for testing applications. + +Video output will also honor any data_offset that the application set. + + +Section 13: Capture Overlay +--------------------------- + +Note: capture overlay support is implemented primarily to test the existing +V4L2 capture overlay API. In practice few if any GPUs support such overlays +anymore, and neither are they generally needed anymore since modern hardware +is so much more capable. By setting flag 0x10000 in the node_types module +option the vivid driver will create a simple framebuffer device that can be +used for testing this API. Whether this API should be used for new drivers is +questionable. + +This driver has support for a destructive capture overlay with bitmap clipping +and list clipping (up to 16 rectangles) capabilities. Overlays are not +supported for multiplanar formats. It also honors the struct v4l2_window field +setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is +FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay. + +The overlay only works if you are also capturing at that same time. This is a +vivid limitation since it copies from a buffer to the overlay instead of +filling the overlay directly. And if you are not capturing, then no buffers +are available to fill. + +In addition, the pixelformat of the capture format and that of the framebuffer +must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return +an error. + +In order to really see what it going on you will need to create two vivid +instances: the first with a framebuffer enabled. You configure the capture +overlay of the second instance to use the framebuffer of the first, then +you start capturing in the second instance. For the first instance you setup +the output overlay for the video output, turn on video looping and capture +to see the blended framebuffer overlay that's being written to by the second +instance. This setup would require the following commands: + + $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1 multiplanar=1,1 + $ v4l2-ctl -d1 --find-fb + /dev/fb1 is the framebuffer associated with base address 0x12800000 + $ sudo v4l2-ctl -d2 --set-fbuf fb=1 + $ v4l2-ctl -d1 --set-fbuf fb=1 + $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15' + $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15' + $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15' + $ v4l2-ctl -d0 -i2 + $ v4l2-ctl -d2 -i2 + $ v4l2-ctl -d2 -c horizontal_movement=4 + $ v4l2-ctl -d1 --overlay=1 + $ v4l2-ctl -d1 -c loop_video=1 + $ v4l2-ctl -d2 --stream-mmap --overlay=1 + +And from another console: + + $ v4l2-ctl -d1 --stream-out-mmap + +And yet another console: + + $ qv4l2 + +and start streaming. + +As you can see, this is not for the faint of heart... + + +Section 14: Output Overlay +-------------------------- + +Note: output overlays are primarily implemented in order to test the existing +V4L2 output overlay API. Whether this API should be used for new drivers is +questionable. + +This driver has support for an output overlay and is capable of: + + - bitmap clipping, + - list clipping (up to 16 rectangles) + - chromakey + - source chromakey + - global alpha + - local alpha + - local inverse alpha + +Output overlays are not supported for multiplanar formats. In addition, the +pixelformat of the capture format and that of the framebuffer must be the +same for the overlay to work. Otherwise VIDIOC_OVERLAY will return an error. + +Output overlays only work if the driver has been configured to create a +framebuffer by setting flag 0x10000 in the node_types module option. The +created framebuffer has a size of 720x576 and supports ARGB 1:5:5:5 and +RGB 5:6:5. + +In order to see the effects of the various clipping, chromakeying or alpha +processing capabilities you need to turn on video looping and see the results +on the capture side. The use of the clipping, chromakeying or alpha processing +capabilities will slow down the video loop considerably as a lot of checks have +to be done per pixel. + + +Section 15: Some Future Improvements +------------------------------------ + +Just as a reminder and in no particular order: + +- Add a virtual alsa driver to test audio +- Add virtual sub-devices and media controller support +- Some support for testing compressed video +- Add support to loop raw VBI output to raw VBI input +- Fix sequence/field numbering when looping of video with alternate fields +- Add support for V4L2_CID_BG_COLOR for video outputs +- Add ARGB888 overlay support: better testing of the alpha channel +- Add custom DV timings support +- Add support for V4L2_DV_FL_REDUCED_FPS +- Improve pixel aspect support in the tpg code by passing a real v4l2_fract +- Use per-queue locks and/or per-device locks to improve throughput +- Add support to loop from a specific output to a specific input across + vivid instances +- Add support for VIDIOC_EXPBUF once support for that has been added to vb2 +- The SDR radio should use the same 'frequencies' for stations as the normal + radio receiver, and give back noise if the frequency doesn't match up with + a station frequency +- Improve the sine generation of the SDR radio. +- Make a thread for the RDS generation, that would help in particular for the + "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated + in real-time. -- cgit v1.2.3 From c88a96b023d8239b2019f93dac42c02e6fd0dff0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 07:54:46 -0300 Subject: [media] vivid: add core driver code This is the core driver code that creates all the driver instances and all the configured devices. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 1390 +++++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-core.h | 520 +++++++++++ 2 files changed, 1910 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-core.c create mode 100644 drivers/media/platform/vivid/vivid-core.h diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c new file mode 100644 index 000000000000..708b0530d9cf --- /dev/null +++ b/drivers/media/platform/vivid/vivid-core.c @@ -0,0 +1,1390 @@ +/* + * vivid-core.c - A Virtual Video Test Driver, core initialization + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" + +#define VIVID_MODULE_NAME "vivid" + +/* The maximum number of vivid devices */ +#define VIVID_MAX_DEVS 64 + +MODULE_DESCRIPTION("Virtual Video Test Driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned n_devs = 1; +module_param(n_devs, uint, 0444); +MODULE_PARM_DESC(n_devs, " number of driver instances to create"); + +static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vid_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect"); + +static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vid_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect"); + +static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vbi_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect"); + +static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vbi_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect"); + +static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(sdr_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect"); + +static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(radio_rx_nr, int, NULL, 0444); +MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect"); + +static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(radio_tx_nr, int, NULL, 0444); +MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); + +static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(ccs_cap_mode, int, NULL, 0444); +MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n" + "\t\t bit 0=crop, 1=compose, 2=scale,\n" + "\t\t -1=user-controlled (default)"); + +static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(ccs_out_mode, int, NULL, 0444); +MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n" + "\t\t bit 0=crop, 1=compose, 2=scale,\n" + "\t\t -1=user-controlled (default)"); + +static unsigned multiplanar[VIVID_MAX_DEVS]; +module_param_array(multiplanar, uint, NULL, 0444); +MODULE_PARM_DESC(multiplanar, " 0 (default) is alternating single and multiplanar devices,\n" + "\t\t 1 is single planar devices,\n" + "\t\t 2 is multiplanar devices"); + +/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */ +static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d }; +module_param_array(node_types, uint, NULL, 0444); +MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n" + "\t\t bit 0: Video Capture node\n" + "\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" + "\t\t bit 4: Radio Receiver node\n" + "\t\t bit 5: Software Defined Radio Receiver node\n" + "\t\t bit 8: Video Output node\n" + "\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" + "\t\t bit 12: Radio Transmitter node\n" + "\t\t bit 16: Framebuffer for testing overlays"); + +/* Default: 4 inputs */ +static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; +module_param_array(num_inputs, uint, NULL, 0444); +MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4"); + +/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */ +static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 }; +module_param_array(input_types, uint, NULL, 0444); +MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n" + "\t\t bits 0-1 == input 0, bits 31-30 == input 15.\n" + "\t\t Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI"); + +/* Default: 2 outputs */ +static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; +module_param_array(num_outputs, uint, NULL, 0444); +MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2"); + +/* Default: output 0 = SVID, 1 = HDMI */ +static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; +module_param_array(output_types, uint, NULL, 0444); +MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n" + "\t\t bit 0 == output 0, bit 15 == output 15.\n" + "\t\t Type 0 == S-Video, 1 == HDMI"); + +unsigned vivid_debug; +module_param(vivid_debug, uint, 0644); +MODULE_PARM_DESC(vivid_debug, " activates debug info"); + +static bool no_error_inj; +module_param(no_error_inj, bool, 0444); +MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); + +static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; + +const struct v4l2_rect vivid_min_rect = { + 0, 0, MIN_WIDTH, MIN_HEIGHT +}; + +const struct v4l2_rect vivid_max_rect = { + 0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM +}; + +static const u8 vivid_hdmi_edid[256] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x63, 0x3a, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x18, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, + 0x0e, 0x00, 0xb2, 0xa0, 0x57, 0x49, 0x9b, 0x26, + 0x10, 0x48, 0x4f, 0x2f, 0xcf, 0x00, 0x31, 0x59, + 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, + 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a, + 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, + 0x46, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, + 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 'v', + '4', 'l', '2', '-', 'h', 'd', 'm', 'i', + 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, + + 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04, + 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07, + 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2, + 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0, + 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, + 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 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, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 +}; + +void vivid_lock(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + mutex_lock(&dev->mutex); +} + +void vivid_unlock(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + mutex_unlock(&dev->mutex); +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + strcpy(cap->driver, "vivid"); + strcpy(cap->card, "vivid"); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev->v4l2_dev.name); + + if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX) + cap->device_caps = dev->vid_cap_caps; + if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX) + cap->device_caps = dev->vid_out_caps; + else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX) + cap->device_caps = dev->vbi_cap_caps; + else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX) + cap->device_caps = dev->vbi_out_caps; + else if (vdev->vfl_type == VFL_TYPE_SDR) + cap->device_caps = dev->sdr_cap_caps; + else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX) + cap->device_caps = dev->radio_rx_caps; + else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX) + cap->device_caps = dev->radio_tx_caps; + cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | + dev->vbi_cap_caps | dev->vbi_out_caps | + dev->radio_rx_caps | dev->radio_tx_caps | + dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_s_hw_freq_seek(file, fh, a); + return -ENOTTY; +} + +static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_enum_freq_bands(file, fh, band); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_enum_freq_bands(file, fh, band); + return -ENOTTY; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_g_tuner(file, fh, vt); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_g_tuner(file, fh, vt); + return vivid_video_g_tuner(file, fh, vt); +} + +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_s_tuner(file, fh, vt); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_s_tuner(file, fh, vt); + return vivid_video_s_tuner(file, fh, vt); +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_g_frequency(file, + vdev->vfl_dir == VFL_DIR_RX ? + &dev->radio_rx_freq : &dev->radio_tx_freq, vf); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_g_frequency(file, fh, vf); + return vivid_video_g_frequency(file, fh, vf); +} + +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_s_frequency(file, + vdev->vfl_dir == VFL_DIR_RX ? + &dev->radio_rx_freq : &dev->radio_tx_freq, vf); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_s_frequency(file, fh, vf); + return vivid_video_s_frequency(file, fh, vf); +} + +static int vidioc_overlay(struct file *file, void *fh, unsigned i) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_overlay(file, fh, i); + return vivid_vid_out_overlay(file, fh, i); +} + +static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_fbuf(file, fh, a); + return vivid_vid_out_g_fbuf(file, fh, a); +} + +static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_fbuf(file, fh, a); + return vivid_vid_out_s_fbuf(file, fh, a); +} + +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_std(file, fh, id); + return vivid_vid_out_s_std(file, fh, id); +} + +static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_dv_timings(file, fh, timings); + return vivid_vid_out_s_dv_timings(file, fh, timings); +} + +static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_cropcap(file, fh, cc); + return vivid_vid_out_cropcap(file, fh, cc); +} + +static int vidioc_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_selection(file, fh, sel); + return vivid_vid_out_g_selection(file, fh, sel); +} + +static int vidioc_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_selection(file, fh, sel); + return vivid_vid_out_s_selection(file, fh, sel); +} + +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_parm(file, fh, parm); + return vivid_vid_out_g_parm(file, fh, parm); +} + +static int vidioc_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_parm(file, fh, parm); + return vivid_vid_out_g_parm(file, fh, parm); +} + +static ssize_t vivid_radio_read(struct file *file, char __user *buf, + size_t size, loff_t *offset) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_TX) + return -EINVAL; + return vivid_radio_rx_read(file, buf, size, offset); +} + +static ssize_t vivid_radio_write(struct file *file, const char __user *buf, + size_t size, loff_t *offset) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return -EINVAL; + return vivid_radio_tx_write(file, buf, size, offset); +} + +static unsigned int vivid_radio_poll(struct file *file, struct poll_table_struct *wait) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_radio_rx_poll(file, wait); + return vivid_radio_tx_poll(file, wait); +} + +static bool vivid_is_in_use(struct video_device *vdev) +{ + unsigned long flags; + bool res; + + spin_lock_irqsave(&vdev->fh_lock, flags); + res = !list_empty(&vdev->fh_list); + spin_unlock_irqrestore(&vdev->fh_lock, flags); + return res; +} + +static bool vivid_is_last_user(struct vivid_dev *dev) +{ + unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) + + vivid_is_in_use(&dev->vid_out_dev) + + vivid_is_in_use(&dev->vbi_cap_dev) + + vivid_is_in_use(&dev->vbi_out_dev) + + vivid_is_in_use(&dev->sdr_cap_dev) + + vivid_is_in_use(&dev->radio_rx_dev) + + vivid_is_in_use(&dev->radio_tx_dev); + + return uses == 1; +} + +static int vivid_fop_release(struct file *file) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + mutex_lock(&dev->mutex); + if (!no_error_inj && v4l2_fh_is_singular_file(file) && + !video_is_registered(vdev) && vivid_is_last_user(dev)) { + /* + * I am the last user of this driver, and a disconnect + * was forced (since this video_device is unregistered), + * so re-register all video_device's again. + */ + v4l2_info(&dev->v4l2_dev, "reconnect\n"); + set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + } + mutex_unlock(&dev->mutex); + if (file->private_data == dev->overlay_cap_owner) + dev->overlay_cap_owner = NULL; + if (file->private_data == dev->radio_rx_rds_owner) { + dev->radio_rx_rds_last_block = 0; + dev->radio_rx_rds_owner = NULL; + } + if (file->private_data == dev->radio_tx_rds_owner) { + dev->radio_tx_rds_last_block = 0; + dev->radio_tx_rds_owner = NULL; + } + if (vdev->queue) + return vb2_fop_release(file); + return v4l2_fh_release(file); +} + +static const struct v4l2_file_operations vivid_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vivid_fop_release, + .read = vb2_fop_read, + .write = vb2_fop_write, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_file_operations vivid_radio_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vivid_fop_release, + .read = vivid_radio_read, + .write = vivid_radio_write, + .poll = vivid_radio_poll, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops vivid_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid, + .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_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + .vidioc_cropcap = vidioc_cropcap, + + .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_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_fmt_sliced_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = vidioc_s_fmt_sliced_vbi_cap, + .vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap, + + .vidioc_g_fmt_vbi_out = vidioc_g_fmt_vbi_out, + .vidioc_try_fmt_vbi_out = vidioc_g_fmt_vbi_out, + .vidioc_s_fmt_vbi_out = vidioc_s_fmt_vbi_out, + + .vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out, + .vidioc_try_fmt_sliced_vbi_out = vidioc_try_fmt_sliced_vbi_out, + .vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out, + + .vidioc_enum_fmt_sdr_cap = vidioc_enum_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, + + .vidioc_overlay = vidioc_overlay, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, + + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, + .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_out_overlay, + .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay, + .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_out_overlay, + .vidioc_overlay = vidioc_overlay, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, +/* Not yet .vidioc_expbuf = vb2_ioctl_expbuf,*/ + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_enumaudio = vidioc_enumaudio, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_modulator = vidioc_s_modulator, + .vidioc_g_modulator = vidioc_g_modulator, + .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, + .vidioc_enum_freq_bands = vidioc_enum_freq_bands, + + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_s_audout = vidioc_s_audout, + .vidioc_g_audout = vidioc_g_audout, + .vidioc_enumaudout = vidioc_enumaudout, + + .vidioc_querystd = vidioc_querystd, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .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_g_edid = vidioc_g_edid, + .vidioc_s_edid = vidioc_s_edid, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* ----------------------------------------------------------------- + Initialization and module stuff + ------------------------------------------------------------------*/ + +static int __init vivid_create_instance(int inst) +{ + static const struct v4l2_dv_timings def_dv_timings = + V4L2_DV_BT_CEA_1280X720P60; + unsigned in_type_counter[4] = { 0, 0, 0, 0 }; + unsigned out_type_counter[4] = { 0, 0, 0, 0 }; + int ccs_cap = ccs_cap_mode[inst]; + int ccs_out = ccs_out_mode[inst]; + bool has_tuner; + bool has_modulator; + struct vivid_dev *dev; + struct video_device *vfd; + struct vb2_queue *q; + unsigned node_type = node_types[inst]; + v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; + int ret; + int i; + + /* allocate main vivid state structure */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->inst = inst; + + /* register v4l2_device */ + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), + "%s-%03d", VIVID_MODULE_NAME, inst); + ret = v4l2_device_register(NULL, &dev->v4l2_dev); + if (ret) + goto free_dev; + + /* start detecting feature set */ + + /* do we use single- or multi-planar? */ + if (multiplanar[inst] == 0) + dev->multiplanar = inst & 1; + else + dev->multiplanar = multiplanar[inst] > 1; + v4l2_info(&dev->v4l2_dev, "using %splanar format API\n", + dev->multiplanar ? "multi" : "single "); + + /* how many inputs do we have and of what type? */ + dev->num_inputs = num_inputs[inst]; + if (dev->num_inputs < 1) + dev->num_inputs = 1; + if (dev->num_inputs >= MAX_INPUTS) + dev->num_inputs = MAX_INPUTS; + for (i = 0; i < dev->num_inputs; i++) { + dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3; + dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++; + } + dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID]; + + /* how many outputs do we have and of what type? */ + dev->num_outputs = num_outputs[inst]; + if (dev->num_outputs < 1) + dev->num_outputs = 1; + if (dev->num_outputs >= MAX_OUTPUTS) + dev->num_outputs = MAX_OUTPUTS; + for (i = 0; i < dev->num_outputs; i++) { + dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID; + dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++; + } + dev->has_audio_outputs = out_type_counter[SVID]; + + /* do we create a video capture device? */ + dev->has_vid_cap = node_type & 0x0001; + + /* do we create a vbi capture device? */ + if (in_type_counter[TV] || in_type_counter[SVID]) { + dev->has_raw_vbi_cap = node_type & 0x0004; + dev->has_sliced_vbi_cap = node_type & 0x0008; + dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap; + } + + /* do we create a video output device? */ + dev->has_vid_out = node_type & 0x0100; + + /* do we create a vbi output device? */ + if (out_type_counter[SVID]) { + dev->has_raw_vbi_out = node_type & 0x0400; + dev->has_sliced_vbi_out = node_type & 0x0800; + dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out; + } + + /* do we create a radio receiver device? */ + dev->has_radio_rx = node_type & 0x0010; + + /* do we create a radio transmitter device? */ + dev->has_radio_tx = node_type & 0x1000; + + /* do we create a software defined radio capture device? */ + dev->has_sdr_cap = node_type & 0x0020; + + /* do we have a tuner? */ + has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) || + dev->has_radio_rx || dev->has_sdr_cap; + + /* do we have a modulator? */ + has_modulator = dev->has_radio_tx; + + if (dev->has_vid_cap) + /* do we have a framebuffer for overlay testing? */ + dev->has_fb = node_type & 0x10000; + + /* can we do crop/compose/scaling while capturing? */ + if (no_error_inj && ccs_cap == -1) + ccs_cap = 7; + + /* if ccs_cap == -1, then the use can select it using controls */ + if (ccs_cap != -1) { + dev->has_crop_cap = ccs_cap & 1; + dev->has_compose_cap = ccs_cap & 2; + dev->has_scaler_cap = ccs_cap & 4; + v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n", + dev->has_crop_cap ? 'Y' : 'N', + dev->has_compose_cap ? 'Y' : 'N', + dev->has_scaler_cap ? 'Y' : 'N'); + } + + /* can we do crop/compose/scaling with video output? */ + if (no_error_inj && ccs_out == -1) + ccs_out = 7; + + /* if ccs_out == -1, then the use can select it using controls */ + if (ccs_out != -1) { + dev->has_crop_out = ccs_out & 1; + dev->has_compose_out = ccs_out & 2; + dev->has_scaler_out = ccs_out & 4; + v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n", + dev->has_crop_out ? 'Y' : 'N', + dev->has_compose_out ? 'Y' : 'N', + dev->has_scaler_out ? 'Y' : 'N'); + } + + /* end detecting feature set */ + + if (dev->has_vid_cap) { + /* set up the capabilities of the video capture device */ + dev->vid_cap_caps = dev->multiplanar ? + V4L2_CAP_VIDEO_CAPTURE_MPLANE : + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY; + dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->vid_cap_caps |= V4L2_CAP_AUDIO; + if (in_type_counter[TV]) + dev->vid_cap_caps |= V4L2_CAP_TUNER; + } + if (dev->has_vid_out) { + /* set up the capabilities of the video output device */ + dev->vid_out_caps = dev->multiplanar ? + V4L2_CAP_VIDEO_OUTPUT_MPLANE : + V4L2_CAP_VIDEO_OUTPUT; + if (dev->has_fb) + dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->vid_out_caps |= V4L2_CAP_AUDIO; + } + if (dev->has_vbi_cap) { + /* set up the capabilities of the vbi capture device */ + dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) | + (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0); + dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->vbi_cap_caps |= V4L2_CAP_AUDIO; + if (in_type_counter[TV]) + dev->vbi_cap_caps |= V4L2_CAP_TUNER; + } + if (dev->has_vbi_out) { + /* set up the capabilities of the vbi output device */ + dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) | + (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0); + dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->vbi_out_caps |= V4L2_CAP_AUDIO; + } + if (dev->has_sdr_cap) { + /* set up the capabilities of the sdr capture device */ + dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; + dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + } + /* set up the capabilities of the radio receiver device */ + if (dev->has_radio_rx) + dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE | + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE; + /* set up the capabilities of the radio transmitter device */ + if (dev->has_radio_tx) + dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | + V4L2_CAP_READWRITE; + + /* initialize the test pattern generator */ + tpg_init(&dev->tpg, 640, 360); + if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) + goto free_dev; + dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH); + if (!dev->scaled_line) + goto free_dev; + dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH); + if (!dev->blended_line) + goto free_dev; + + /* load the edid */ + dev->edid = vmalloc(256 * 128); + if (!dev->edid) + goto free_dev; + + /* create a string array containing the names of all the preset timings */ + while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) + dev->query_dv_timings_size++; + dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size * + (sizeof(void *) + 32), GFP_KERNEL); + if (dev->query_dv_timings_qmenu == NULL) + goto free_dev; + for (i = 0; i < dev->query_dv_timings_size; i++) { + const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; + char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size]; + u32 htot, vtot; + + p += i * 32; + dev->query_dv_timings_qmenu[i] = p; + + htot = V4L2_DV_BT_FRAME_WIDTH(bt); + vtot = V4L2_DV_BT_FRAME_HEIGHT(bt); + snprintf(p, 32, "%ux%u%s%u", + bt->width, bt->height, bt->interlaced ? "i" : "p", + (u32)bt->pixelclock / (htot * vtot)); + } + + /* disable invalid ioctls based on the feature set */ + if (!dev->has_audio_inputs) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); + } + if (!dev->has_audio_outputs) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT); + } + if (!in_type_counter[TV] && !in_type_counter[SVID]) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD); + } + if (!out_type_counter[SVID]) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD); + } + if (!has_tuner && !has_modulator) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY); + } + if (!has_tuner) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER); + } + if (in_type_counter[HDMI] == 0) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS); + } + if (out_type_counter[HDMI] == 0) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS); + } + if (!dev->has_fb) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY); + } + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY); + + /* configure internal data */ + dev->fmt_cap = &vivid_formats[0]; + dev->fmt_out = &vivid_formats[0]; + if (!dev->multiplanar) + vivid_formats[0].data_offset[0] = 0; + dev->webcam_size_idx = 1; + dev->webcam_ival_idx = 3; + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + dev->std_cap = V4L2_STD_PAL; + dev->std_out = V4L2_STD_PAL; + if (dev->input_type[0] == TV || dev->input_type[0] == SVID) + tvnorms_cap = V4L2_STD_ALL; + if (dev->output_type[0] == SVID) + tvnorms_out = V4L2_STD_ALL; + dev->dv_timings_cap = def_dv_timings; + dev->dv_timings_out = def_dv_timings; + dev->tv_freq = 2804 /* 175.25 * 16 */; + dev->tv_audmode = V4L2_TUNER_MODE_STEREO; + dev->tv_field_cap = V4L2_FIELD_INTERLACED; + dev->tv_field_out = V4L2_FIELD_INTERLACED; + dev->radio_rx_freq = 95000 * 16; + dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO; + if (dev->has_radio_tx) { + dev->radio_tx_freq = 95500 * 16; + dev->radio_rds_loop = false; + } + dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; + dev->sdr_adc_freq = 300000; + dev->sdr_fm_freq = 50000000; + dev->edid_max_blocks = dev->edid_blocks = 2; + memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); + ktime_get_ts(&dev->radio_rds_init_ts); + + /* create all controls */ + ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj, + in_type_counter[TV] || in_type_counter[SVID] || + out_type_counter[SVID], + in_type_counter[HDMI] || out_type_counter[HDMI]); + if (ret) + goto unreg_dev; + + /* + * update the capture and output formats to do a proper initial + * configuration. + */ + vivid_update_format_cap(dev, false); + vivid_update_format_out(dev); + + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); + + /* initialize overlay */ + dev->fb_cap.fmt.width = dev->src_rect.width; + dev->fb_cap.fmt.height = dev->src_rect.height; + dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc; + dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2; + dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline; + + /* initialize locks */ + spin_lock_init(&dev->slock); + mutex_init(&dev->mutex); + + /* init dma queues */ + INIT_LIST_HEAD(&dev->vid_cap_active); + INIT_LIST_HEAD(&dev->vid_out_active); + INIT_LIST_HEAD(&dev->vbi_cap_active); + INIT_LIST_HEAD(&dev->vbi_out_active); + INIT_LIST_HEAD(&dev->sdr_cap_active); + + /* start creating the vb2 queues */ + if (dev->has_vid_cap) { + /* initialize vid_cap queue */ + q = &dev->vb_vid_cap_q; + q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = &vivid_vid_cap_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + + ret = vb2_queue_init(q); + if (ret) + goto unreg_dev; + } + + if (dev->has_vid_out) { + /* initialize vid_out queue */ + q = &dev->vb_vid_out_q; + q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = &vivid_vid_out_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + + ret = vb2_queue_init(q); + if (ret) + goto unreg_dev; + } + + if (dev->has_vbi_cap) { + /* initialize vbi_cap queue */ + q = &dev->vb_vbi_cap_q; + q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE : + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = &vivid_vbi_cap_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + + ret = vb2_queue_init(q); + if (ret) + goto unreg_dev; + } + + if (dev->has_vbi_out) { + /* initialize vbi_out queue */ + q = &dev->vb_vbi_out_q; + q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT : + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = &vivid_vbi_out_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + + ret = vb2_queue_init(q); + if (ret) + goto unreg_dev; + } + + if (dev->has_sdr_cap) { + /* initialize sdr_cap queue */ + q = &dev->vb_sdr_cap_q; + q->type = V4L2_BUF_TYPE_SDR_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = &vivid_sdr_cap_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 8; + + ret = vb2_queue_init(q); + if (ret) + goto unreg_dev; + } + + if (dev->has_fb) { + /* Create framebuffer for testing capture/output overlay */ + ret = vivid_fb_init(dev); + if (ret) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", + dev->fb_info.node); + } + + /* finally start creating the device nodes */ + if (dev->has_vid_cap) { + vfd = &dev->vid_cap_dev; + strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name)); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vid_cap_q; + vfd->tvnorms = tvnorms_cap; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_vid_out) { + vfd = &dev->vid_out_dev; + strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name)); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vid_out_q; + vfd->tvnorms = tvnorms_out; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_vbi_cap) { + vfd = &dev->vbi_cap_dev; + strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name)); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vbi_cap_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_cap; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n", + video_device_node_name(vfd), + (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ? + "raw and sliced" : + (dev->has_raw_vbi_cap ? "raw" : "sliced")); + } + + if (dev->has_vbi_out) { + vfd = &dev->vbi_out_dev; + strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name)); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vbi_out_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_out; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n", + video_device_node_name(vfd), + (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ? + "raw and sliced" : + (dev->has_raw_vbi_out ? "raw" : "sliced")); + } + + if (dev->has_sdr_cap) { + vfd = &dev->sdr_cap_dev; + strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name)); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_sdr_cap_q; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_radio_rx) { + vfd = &dev->radio_rx_dev; + strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name)); + vfd->fops = &vivid_radio_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_radio_tx) { + vfd = &dev->radio_tx_dev; + strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name)); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_radio_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n", + video_device_node_name(vfd)); + } + + /* Now that everything is fine, let's add it to device list */ + vivid_devs[inst] = dev; + + return 0; + +unreg_dev: + video_unregister_device(&dev->radio_tx_dev); + video_unregister_device(&dev->radio_rx_dev); + video_unregister_device(&dev->sdr_cap_dev); + video_unregister_device(&dev->vbi_out_dev); + video_unregister_device(&dev->vbi_cap_dev); + video_unregister_device(&dev->vid_out_dev); + video_unregister_device(&dev->vid_cap_dev); + vivid_free_controls(dev); + v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + vfree(dev->scaled_line); + vfree(dev->blended_line); + vfree(dev->edid); + tpg_free(&dev->tpg); + kfree(dev->query_dv_timings_qmenu); + kfree(dev); + return ret; +} + +/* This routine allocates from 1 to n_devs virtual drivers. + + The real maximum number of virtual drivers will depend on how many drivers + will succeed. This is limited to the maximum number of devices that + videodev supports, which is equal to VIDEO_NUM_DEVICES. + */ +static int __init vivid_init(void) +{ + const struct font_desc *font = find_font("VGA8x16"); + int ret = 0, i; + + if (font == NULL) { + pr_err("vivid: could not find font\n"); + return -ENODEV; + } + + tpg_set_font(font->data); + + n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); + + for (i = 0; i < n_devs; i++) { + ret = vivid_create_instance(i); + if (ret) { + /* If some instantiations succeeded, keep driver */ + if (i) + ret = 0; + break; + } + } + + if (ret < 0) { + pr_err("vivid: error %d while loading driver\n", ret); + return ret; + } + + /* n_devs will reflect the actual number of allocated devices */ + n_devs = i; + + return ret; +} + +static void __exit vivid_exit(void) +{ + struct vivid_dev *dev; + unsigned i; + + for (i = 0; vivid_devs[i]; i++) { + dev = vivid_devs[i]; + + if (dev->has_vid_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vid_cap_dev)); + video_unregister_device(&dev->vid_cap_dev); + } + if (dev->has_vid_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vid_out_dev)); + video_unregister_device(&dev->vid_out_dev); + } + if (dev->has_vbi_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vbi_cap_dev)); + video_unregister_device(&dev->vbi_cap_dev); + } + if (dev->has_vbi_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vbi_out_dev)); + video_unregister_device(&dev->vbi_out_dev); + } + if (dev->has_sdr_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->sdr_cap_dev)); + video_unregister_device(&dev->sdr_cap_dev); + } + if (dev->has_radio_rx) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->radio_rx_dev)); + video_unregister_device(&dev->radio_rx_dev); + } + if (dev->has_radio_tx) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->radio_tx_dev)); + video_unregister_device(&dev->radio_tx_dev); + } + if (dev->has_fb) { + v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n", + dev->fb_info.node); + unregister_framebuffer(&dev->fb_info); + vivid_fb_release_buffers(dev); + } + v4l2_device_unregister(&dev->v4l2_dev); + vivid_free_controls(dev); + vfree(dev->scaled_line); + vfree(dev->blended_line); + vfree(dev->edid); + vfree(dev->bitmap_cap); + vfree(dev->bitmap_out); + tpg_free(&dev->tpg); + kfree(dev->query_dv_timings_qmenu); + kfree(dev); + vivid_devs[i] = NULL; + } +} + +module_init(vivid_init); +module_exit(vivid_exit); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h new file mode 100644 index 000000000000..811c286491a5 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-core.h @@ -0,0 +1,520 @@ +/* + * vivid-core.h - core datastructures + * + * Copyright 2014 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 _VIVID_CORE_H_ +#define _VIVID_CORE_H_ + +#include +#include +#include +#include +#include +#include "vivid-tpg.h" +#include "vivid-rds-gen.h" +#include "vivid-vbi-gen.h" + +#define dprintk(dev, level, fmt, arg...) \ + v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg) + +/* Maximum allowed frame rate + * + * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range. + * + * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that + * might hit application errors when they manipulate these values. + * + * Besides, for tpf < 10ms image-generation logic should be changed, to avoid + * producing frames with equal content. + */ +#define FPS_MAX 100 + +/* The maximum number of clip rectangles */ +#define MAX_CLIPS 16 +/* The maximum number of inputs */ +#define MAX_INPUTS 16 +/* The maximum number of outputs */ +#define MAX_OUTPUTS 16 +/* The maximum up or down scaling factor is 4 */ +#define MAX_ZOOM 4 +/* The maximum image width/height are set to 4K DMT */ +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 2160 +/* The minimum image width/height */ +#define MIN_WIDTH 16 +#define MIN_HEIGHT 16 +/* The data_offset of plane 0 for the multiplanar formats */ +#define PLANE0_DATA_OFFSET 128 + +/* The supported TV frequency range in MHz */ +#define MIN_TV_FREQ (44U * 16U) +#define MAX_TV_FREQ (958U * 16U) + +/* The number of samples returned in every SDR buffer */ +#define SDR_CAP_SAMPLES_PER_BUF 0x4000 + +/* used by the threads to know when to resync internal counters */ +#define JIFFIES_PER_DAY (3600U * 24U * HZ) +#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY)) + +extern const struct v4l2_rect vivid_min_rect; +extern const struct v4l2_rect vivid_max_rect; +extern unsigned vivid_debug; + +struct vivid_fmt { + const char *name; + u32 fourcc; /* v4l2 format id */ + u8 depth; + bool is_yuv; + bool can_do_overlay; + u32 alpha_mask; + u8 planes; + u32 data_offset[2]; +}; + +extern struct vivid_fmt vivid_formats[]; + +/* buffer for one video frame */ +struct vivid_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_buffer vb; + struct list_head list; +}; + +enum vivid_input { + WEBCAM, + TV, + SVID, + HDMI, +}; + +enum vivid_signal_mode { + CURRENT_DV_TIMINGS, + CURRENT_STD = CURRENT_DV_TIMINGS, + NO_SIGNAL, + NO_LOCK, + OUT_OF_RANGE, + SELECTED_DV_TIMINGS, + SELECTED_STD = SELECTED_DV_TIMINGS, + CYCLE_DV_TIMINGS, + CYCLE_STD = CYCLE_DV_TIMINGS, + CUSTOM_DV_TIMINGS, +}; + +#define VIVID_INVALID_SIGNAL(mode) \ + ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE) + +struct vivid_dev { + unsigned inst; + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_hdl_user_gen; + struct v4l2_ctrl_handler ctrl_hdl_user_vid; + struct v4l2_ctrl_handler ctrl_hdl_user_aud; + struct v4l2_ctrl_handler ctrl_hdl_streaming; + struct v4l2_ctrl_handler ctrl_hdl_sdtv_cap; + struct v4l2_ctrl_handler ctrl_hdl_loop_out; + struct video_device vid_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_vid_cap; + struct video_device vid_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_vid_out; + struct video_device vbi_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_vbi_cap; + struct video_device vbi_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_vbi_out; + struct video_device radio_rx_dev; + struct v4l2_ctrl_handler ctrl_hdl_radio_rx; + struct video_device radio_tx_dev; + struct v4l2_ctrl_handler ctrl_hdl_radio_tx; + struct video_device sdr_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; + spinlock_t slock; + struct mutex mutex; + + /* capabilities */ + u32 vid_cap_caps; + u32 vid_out_caps; + u32 vbi_cap_caps; + u32 vbi_out_caps; + u32 sdr_cap_caps; + u32 radio_rx_caps; + u32 radio_tx_caps; + + /* supported features */ + bool multiplanar; + unsigned num_inputs; + u8 input_type[MAX_INPUTS]; + u8 input_name_counter[MAX_INPUTS]; + unsigned num_outputs; + u8 output_type[MAX_OUTPUTS]; + u8 output_name_counter[MAX_OUTPUTS]; + bool has_audio_inputs; + bool has_audio_outputs; + bool has_vid_cap; + bool has_vid_out; + bool has_vbi_cap; + bool has_raw_vbi_cap; + bool has_sliced_vbi_cap; + bool has_vbi_out; + bool has_raw_vbi_out; + bool has_sliced_vbi_out; + bool has_radio_rx; + bool has_radio_tx; + bool has_sdr_cap; + bool has_fb; + + bool can_loop_video; + + /* controls */ + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *hue; + struct { + /* autogain/gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *mute; + struct v4l2_ctrl *alpha; + struct v4l2_ctrl *button; + struct v4l2_ctrl *boolean; + struct v4l2_ctrl *int32; + struct v4l2_ctrl *int64; + struct v4l2_ctrl *menu; + struct v4l2_ctrl *string; + struct v4l2_ctrl *bitmask; + struct v4l2_ctrl *int_menu; + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *colorspace; + struct v4l2_ctrl *rgb_range_cap; + struct v4l2_ctrl *real_rgb_range_cap; + struct { + /* std_signal_mode/standard cluster */ + struct v4l2_ctrl *ctrl_std_signal_mode; + struct v4l2_ctrl *ctrl_standard; + }; + struct { + /* dv_timings_signal_mode/timings cluster */ + struct v4l2_ctrl *ctrl_dv_timings_signal_mode; + struct v4l2_ctrl *ctrl_dv_timings; + }; + struct v4l2_ctrl *ctrl_has_crop_cap; + struct v4l2_ctrl *ctrl_has_compose_cap; + struct v4l2_ctrl *ctrl_has_scaler_cap; + struct v4l2_ctrl *ctrl_has_crop_out; + struct v4l2_ctrl *ctrl_has_compose_out; + struct v4l2_ctrl *ctrl_has_scaler_out; + struct v4l2_ctrl *ctrl_tx_mode; + struct v4l2_ctrl *ctrl_tx_rgb_range; + + struct v4l2_ctrl *radio_tx_rds_pi; + struct v4l2_ctrl *radio_tx_rds_pty; + struct v4l2_ctrl *radio_tx_rds_mono_stereo; + struct v4l2_ctrl *radio_tx_rds_art_head; + struct v4l2_ctrl *radio_tx_rds_compressed; + struct v4l2_ctrl *radio_tx_rds_dyn_pty; + struct v4l2_ctrl *radio_tx_rds_ta; + struct v4l2_ctrl *radio_tx_rds_tp; + struct v4l2_ctrl *radio_tx_rds_ms; + struct v4l2_ctrl *radio_tx_rds_psname; + struct v4l2_ctrl *radio_tx_rds_radiotext; + + struct v4l2_ctrl *radio_rx_rds_pty; + struct v4l2_ctrl *radio_rx_rds_ta; + struct v4l2_ctrl *radio_rx_rds_tp; + struct v4l2_ctrl *radio_rx_rds_ms; + struct v4l2_ctrl *radio_rx_rds_psname; + struct v4l2_ctrl *radio_rx_rds_radiotext; + + unsigned input_brightness[MAX_INPUTS]; + unsigned osd_mode; + unsigned button_pressed; + bool sensor_hflip; + bool sensor_vflip; + bool hflip; + bool vflip; + bool vbi_cap_interlaced; + bool loop_video; + + /* Framebuffer */ + unsigned long video_pbase; + void *video_vbase; + u32 video_buffer_size; + int display_width; + int display_height; + int display_byte_stride; + int bits_per_pixel; + int bytes_per_pixel; + struct fb_info fb_info; + struct fb_var_screeninfo fb_defined; + struct fb_fix_screeninfo fb_fix; + + /* Error injection */ + bool queue_setup_error; + bool buf_prepare_error; + bool start_streaming_error; + bool dqbuf_error; + bool seq_wrap; + bool time_wrap; + __kernel_time_t time_wrap_offset; + unsigned perc_dropped_buffers; + enum vivid_signal_mode std_signal_mode; + unsigned query_std_last; + v4l2_std_id query_std; + enum tpg_video_aspect std_aspect_ratio; + + enum vivid_signal_mode dv_timings_signal_mode; + char **query_dv_timings_qmenu; + unsigned query_dv_timings_size; + unsigned query_dv_timings_last; + unsigned query_dv_timings; + enum tpg_video_aspect dv_timings_aspect_ratio; + + /* Input */ + unsigned input; + v4l2_std_id std_cap; + struct v4l2_dv_timings dv_timings_cap; + u32 service_set_cap; + struct vivid_vbi_gen_data vbi_gen; + u8 *edid; + unsigned edid_blocks; + unsigned edid_max_blocks; + unsigned webcam_size_idx; + unsigned webcam_ival_idx; + unsigned tv_freq; + unsigned tv_audmode; + unsigned tv_field_cap; + unsigned tv_audio_input; + + /* Capture Overlay */ + struct v4l2_framebuffer fb_cap; + struct v4l2_fh *overlay_cap_owner; + void *fb_vbase_cap; + int overlay_cap_top, overlay_cap_left; + enum v4l2_field overlay_cap_field; + void *bitmap_cap; + struct v4l2_clip clips_cap[MAX_CLIPS]; + struct v4l2_clip try_clips_cap[MAX_CLIPS]; + unsigned clipcount_cap; + + /* Output */ + unsigned output; + v4l2_std_id std_out; + struct v4l2_dv_timings dv_timings_out; + u32 colorspace_out; + u32 service_set_out; + u32 bytesperline_out[2]; + unsigned tv_field_out; + unsigned tv_audio_output; + bool vbi_out_have_wss; + u8 vbi_out_wss[2]; + bool vbi_out_have_cc[2]; + u8 vbi_out_cc[2][2]; + bool dvi_d_out; + u8 *scaled_line; + u8 *blended_line; + unsigned cur_scaled_line; + + /* Output Overlay */ + void *fb_vbase_out; + bool overlay_out_enabled; + int overlay_out_top, overlay_out_left; + void *bitmap_out; + struct v4l2_clip clips_out[MAX_CLIPS]; + struct v4l2_clip try_clips_out[MAX_CLIPS]; + unsigned clipcount_out; + unsigned fbuf_out_flags; + u32 chromakey_out; + u8 global_alpha_out; + + /* video capture */ + struct tpg_data tpg; + unsigned ms_vid_cap; + bool must_blank[VIDEO_MAX_FRAME]; + + const struct vivid_fmt *fmt_cap; + struct v4l2_fract timeperframe_vid_cap; + enum v4l2_field field_cap; + struct v4l2_rect src_rect; + struct v4l2_rect fmt_cap_rect; + struct v4l2_rect crop_cap; + struct v4l2_rect compose_cap; + struct v4l2_rect crop_bounds_cap; + struct vb2_queue vb_vid_cap_q; + struct list_head vid_cap_active; + struct vb2_queue vb_vbi_cap_q; + struct list_head vbi_cap_active; + + /* thread for generating video capture stream */ + struct task_struct *kthread_vid_cap; + unsigned long jiffies_vid_cap; + u32 cap_seq_offset; + u32 cap_seq_count; + bool cap_seq_resync; + u32 vid_cap_seq_start; + u32 vid_cap_seq_count; + bool vid_cap_streaming; + u32 vbi_cap_seq_start; + u32 vbi_cap_seq_count; + bool vbi_cap_streaming; + bool stream_sliced_vbi_cap; + + /* video output */ + const struct vivid_fmt *fmt_out; + struct v4l2_fract timeperframe_vid_out; + enum v4l2_field field_out; + struct v4l2_rect sink_rect; + struct v4l2_rect fmt_out_rect; + struct v4l2_rect crop_out; + struct v4l2_rect compose_out; + struct v4l2_rect compose_bounds_out; + struct vb2_queue vb_vid_out_q; + struct list_head vid_out_active; + struct vb2_queue vb_vbi_out_q; + struct list_head vbi_out_active; + + /* video loop precalculated rectangles */ + + /* + * Intersection between what the output side composes and the capture side + * crops. I.e., what actually needs to be copied from the output buffer to + * the capture buffer. + */ + struct v4l2_rect loop_vid_copy; + /* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */ + struct v4l2_rect loop_vid_out; + /* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */ + struct v4l2_rect loop_vid_cap; + /* + * The intersection of the framebuffer, the overlay output window and + * loop_vid_copy. I.e., the part of the framebuffer that actually should be + * blended with the compose_out rectangle. This uses the framebuffer origin. + */ + struct v4l2_rect loop_fb_copy; + /* The same as loop_fb_copy but with compose_out origin. */ + struct v4l2_rect loop_vid_overlay; + /* + * The part of the capture buffer that (after scaling) corresponds + * to loop_vid_overlay. + */ + struct v4l2_rect loop_vid_overlay_cap; + + /* thread for generating video output stream */ + struct task_struct *kthread_vid_out; + unsigned long jiffies_vid_out; + u32 out_seq_offset; + u32 out_seq_count; + bool out_seq_resync; + u32 vid_out_seq_start; + u32 vid_out_seq_count; + bool vid_out_streaming; + u32 vbi_out_seq_start; + u32 vbi_out_seq_count; + bool vbi_out_streaming; + bool stream_sliced_vbi_out; + + /* SDR capture */ + struct vb2_queue vb_sdr_cap_q; + struct list_head sdr_cap_active; + unsigned sdr_adc_freq; + unsigned sdr_fm_freq; + int sdr_fixp_src_phase; + int sdr_fixp_mod_phase; + + bool tstamp_src_is_soe; + bool has_crop_cap; + bool has_compose_cap; + bool has_scaler_cap; + bool has_crop_out; + bool has_compose_out; + bool has_scaler_out; + + /* thread for generating SDR stream */ + struct task_struct *kthread_sdr_cap; + unsigned long jiffies_sdr_cap; + u32 sdr_cap_seq_offset; + u32 sdr_cap_seq_count; + bool sdr_cap_seq_resync; + + /* RDS generator */ + struct vivid_rds_gen rds_gen; + + /* Radio receiver */ + unsigned radio_rx_freq; + unsigned radio_rx_audmode; + int radio_rx_sig_qual; + unsigned radio_rx_hw_seek_mode; + bool radio_rx_hw_seek_prog_lim; + bool radio_rx_rds_controls; + bool radio_rx_rds_enabled; + unsigned radio_rx_rds_use_alternates; + unsigned radio_rx_rds_last_block; + struct v4l2_fh *radio_rx_rds_owner; + + /* Radio transmitter */ + unsigned radio_tx_freq; + unsigned radio_tx_subchans; + bool radio_tx_rds_controls; + unsigned radio_tx_rds_last_block; + struct v4l2_fh *radio_tx_rds_owner; + + /* Shared between radio receiver and transmitter */ + bool radio_rds_loop; + struct timespec radio_rds_init_ts; +}; + +static inline bool vivid_is_webcam(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == WEBCAM; +} + +static inline bool vivid_is_tv_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == TV; +} + +static inline bool vivid_is_svid_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == SVID; +} + +static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == HDMI; +} + +static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev) +{ + return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev); +} + +static inline bool vivid_is_svid_out(const struct vivid_dev *dev) +{ + return dev->output_type[dev->output] == SVID; +} + +static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev) +{ + return dev->output_type[dev->output] == HDMI; +} + +void vivid_lock(struct vb2_queue *vq); +void vivid_unlock(struct vb2_queue *vq); + +#endif -- cgit v1.2.3 From 73c3f48230cda01402ae189b05d56f1f7e0d53c9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 07:55:23 -0300 Subject: [media] vivid: add the control handling code The vivid-ctrls code sets up and processes the various V4L2 controls that are needed by this driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-ctrls.c | 1502 ++++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-ctrls.h | 34 + 2 files changed, 1536 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-ctrls.c create mode 100644 drivers/media/platform/vivid/vivid-ctrls.h diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c new file mode 100644 index 000000000000..d5cbf0038f24 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -0,0 +1,1502 @@ +/* + * vivid-ctrls.c - control support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-vid-common.h" +#include "vivid-radio-common.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" + +#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) +#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0) +#define VIVID_CID_BOOLEAN (VIVID_CID_CUSTOM_BASE + 1) +#define VIVID_CID_INTEGER (VIVID_CID_CUSTOM_BASE + 2) +#define VIVID_CID_INTEGER64 (VIVID_CID_CUSTOM_BASE + 3) +#define VIVID_CID_MENU (VIVID_CID_CUSTOM_BASE + 4) +#define VIVID_CID_STRING (VIVID_CID_CUSTOM_BASE + 5) +#define VIVID_CID_BITMASK (VIVID_CID_CUSTOM_BASE + 6) +#define VIVID_CID_INTMENU (VIVID_CID_CUSTOM_BASE + 7) + +#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) +#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) +#define VIVID_CID_TEST_PATTERN (VIVID_CID_VIVID_BASE + 0) +#define VIVID_CID_OSD_TEXT_MODE (VIVID_CID_VIVID_BASE + 1) +#define VIVID_CID_HOR_MOVEMENT (VIVID_CID_VIVID_BASE + 2) +#define VIVID_CID_VERT_MOVEMENT (VIVID_CID_VIVID_BASE + 3) +#define VIVID_CID_SHOW_BORDER (VIVID_CID_VIVID_BASE + 4) +#define VIVID_CID_SHOW_SQUARE (VIVID_CID_VIVID_BASE + 5) +#define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6) +#define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7) +#define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8) + +#define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20) +#define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21) +#define VIVID_CID_STD_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 22) +#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23) +#define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24) +#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25) +#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 26) +#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 27) +#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 28) +#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 29) +#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 30) +#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 31) +#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 32) +#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 33) +#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 34) +#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 35) +#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 36) +#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 37) +#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 38) + +#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) +#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) +#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 62) +#define VIVID_CID_DV_TIMINGS (VIVID_CID_VIVID_BASE + 63) +#define VIVID_CID_PERC_DROPPED (VIVID_CID_VIVID_BASE + 64) +#define VIVID_CID_DISCONNECT (VIVID_CID_VIVID_BASE + 65) +#define VIVID_CID_DQBUF_ERROR (VIVID_CID_VIVID_BASE + 66) +#define VIVID_CID_QUEUE_SETUP_ERROR (VIVID_CID_VIVID_BASE + 67) +#define VIVID_CID_BUF_PREPARE_ERROR (VIVID_CID_VIVID_BASE + 68) +#define VIVID_CID_START_STR_ERROR (VIVID_CID_VIVID_BASE + 69) +#define VIVID_CID_QUEUE_ERROR (VIVID_CID_VIVID_BASE + 70) +#define VIVID_CID_CLEAR_FB (VIVID_CID_VIVID_BASE + 71) + +#define VIVID_CID_RADIO_SEEK_MODE (VIVID_CID_VIVID_BASE + 90) +#define VIVID_CID_RADIO_SEEK_PROG_LIM (VIVID_CID_VIVID_BASE + 91) +#define VIVID_CID_RADIO_RX_RDS_RBDS (VIVID_CID_VIVID_BASE + 92) +#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93) + +#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94) + + +/* General User Controls */ + +static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen); + + switch (ctrl->id) { + case VIVID_CID_DISCONNECT: + v4l2_info(&dev->v4l2_dev, "disconnect\n"); + clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + break; + case VIVID_CID_CLEAR_FB: + vivid_clear_fb(dev); + break; + case VIVID_CID_BUTTON: + dev->button_pressed = 30; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = { + .s_ctrl = vivid_user_gen_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_button = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BUTTON, + .name = "Button", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_boolean = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BOOLEAN, + .name = "Boolean", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int32 = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTEGER, + .name = "Integer 32 Bits", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0xffffffff80000000ULL, + .max = 0x7fffffff, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int64 = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTEGER64, + .name = "Integer 64 Bits", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = 0x8000000000000000ULL, + .max = 0x7fffffffffffffffLL, + .step = 1, +}; + +static const char * const vivid_ctrl_menu_strings[] = { + "Menu Item 0 (Skipped)", + "Menu Item 1", + "Menu Item 2 (Skipped)", + "Menu Item 3", + "Menu Item 4", + "Menu Item 5 (Skipped)", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_menu = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_MENU, + .name = "Menu", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 4, + .def = 3, + .menu_skip_mask = 0x04, + .qmenu = vivid_ctrl_menu_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_string = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_STRING, + .name = "String", + .type = V4L2_CTRL_TYPE_STRING, + .min = 2, + .max = 4, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_bitmask = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BITMASK, + .name = "Bitmask", + .type = V4L2_CTRL_TYPE_BITMASK, + .def = 0x80002000, + .min = 0, + .max = 0x80402010, + .step = 0, +}; + +static const s64 vivid_ctrl_int_menu_values[] = { + 1, 1, 2, 3, 5, 8, 13, 21, 42, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int_menu = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTMENU, + .name = "Integer Menu", + .type = V4L2_CTRL_TYPE_INTEGER_MENU, + .min = 1, + .max = 8, + .def = 4, + .menu_skip_mask = 0x02, + .qmenu_int = vivid_ctrl_int_menu_values, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_disconnect = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_DISCONNECT, + .name = "Disconnect", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_CLEAR_FB, + .name = "Clear Framebuffer", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + + +/* Video User Controls */ + +static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + dev->gain->val = dev->jiffies_vid_cap & 0xff; + break; + } + return 0; +} + +static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + dev->input_brightness[dev->input] = ctrl->val - dev->input * 128; + tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]); + break; + case V4L2_CID_CONTRAST: + tpg_s_contrast(&dev->tpg, ctrl->val); + break; + case V4L2_CID_SATURATION: + tpg_s_saturation(&dev->tpg, ctrl->val); + break; + case V4L2_CID_HUE: + tpg_s_hue(&dev->tpg, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev->hflip = ctrl->val; + tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); + break; + case V4L2_CID_VFLIP: + dev->vflip = ctrl->val; + tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); + break; + case V4L2_CID_ALPHA_COMPONENT: + tpg_s_alpha_component(&dev->tpg, ctrl->val); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = { + .g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl, + .s_ctrl = vivid_user_vid_s_ctrl, +}; + + +/* Video Capture Controls */ + +static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap); + unsigned i; + + switch (ctrl->id) { + case VIVID_CID_TEST_PATTERN: + vivid_update_quality(dev); + tpg_s_pattern(&dev->tpg, ctrl->val); + break; + case VIVID_CID_COLORSPACE: + tpg_s_colorspace(&dev->tpg, ctrl->val); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case V4L2_CID_DV_RX_RGB_RANGE: + if (!vivid_is_hdmi_cap(dev)) + break; + tpg_s_rgb_range(&dev->tpg, ctrl->val); + break; + case VIVID_CID_LIMITED_RGB_RANGE: + tpg_s_real_rgb_range(&dev->tpg, ctrl->val ? + V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL); + break; + case VIVID_CID_ALPHA_MODE: + tpg_s_alpha_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_HOR_MOVEMENT: + tpg_s_mv_hor_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_VERT_MOVEMENT: + tpg_s_mv_vert_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_OSD_TEXT_MODE: + dev->osd_mode = ctrl->val; + break; + case VIVID_CID_PERCENTAGE_FILL: + tpg_s_perc_fill(&dev->tpg, ctrl->val); + for (i = 0; i < VIDEO_MAX_FRAME; i++) + dev->must_blank[i] = ctrl->val < 100; + break; + case VIVID_CID_INSERT_SAV: + tpg_s_insert_sav(&dev->tpg, ctrl->val); + break; + case VIVID_CID_INSERT_EAV: + tpg_s_insert_eav(&dev->tpg, ctrl->val); + break; + case VIVID_CID_HFLIP: + dev->sensor_hflip = ctrl->val; + tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); + break; + case VIVID_CID_VFLIP: + dev->sensor_vflip = ctrl->val; + tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); + break; + case VIVID_CID_HAS_CROP_CAP: + dev->has_crop_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_COMPOSE_CAP: + dev->has_compose_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_SCALER_CAP: + dev->has_scaler_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_SHOW_BORDER: + tpg_s_show_border(&dev->tpg, ctrl->val); + break; + case VIVID_CID_SHOW_SQUARE: + tpg_s_show_square(&dev->tpg, ctrl->val); + break; + case VIVID_CID_STD_ASPECT_RATIO: + dev->std_aspect_ratio = ctrl->val; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + break; + case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: + dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val; + if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) + dev->query_dv_timings = dev->ctrl_dv_timings->val; + v4l2_ctrl_activate(dev->ctrl_dv_timings, + dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS); + vivid_update_quality(dev); + vivid_send_source_change(dev, HDMI); + break; + case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: + dev->dv_timings_aspect_ratio = ctrl->val; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + break; + case VIVID_CID_TSTAMP_SRC: + dev->tstamp_src_is_soe = ctrl->val; + dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + if (dev->tstamp_src_is_soe) + dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE; + break; + case VIVID_CID_MAX_EDID_BLOCKS: + dev->edid_max_blocks = ctrl->val; + if (dev->edid_blocks > dev->edid_max_blocks) + dev->edid_blocks = dev->edid_max_blocks; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = { + .s_ctrl = vivid_vid_cap_s_ctrl, +}; + +static const char * const vivid_ctrl_hor_movement_strings[] = { + "Move Left Fast", + "Move Left", + "Move Left Slow", + "No Movement", + "Move Right Slow", + "Move Right", + "Move Right Fast", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HOR_MOVEMENT, + .name = "Horizontal Movement", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_MOVE_POS_FAST, + .def = TPG_MOVE_NONE, + .qmenu = vivid_ctrl_hor_movement_strings, +}; + +static const char * const vivid_ctrl_vert_movement_strings[] = { + "Move Up Fast", + "Move Up", + "Move Up Slow", + "No Movement", + "Move Down Slow", + "Move Down", + "Move Down Fast", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_VERT_MOVEMENT, + .name = "Vertical Movement", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_MOVE_POS_FAST, + .def = TPG_MOVE_NONE, + .qmenu = vivid_ctrl_vert_movement_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_show_border = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_SHOW_BORDER, + .name = "Show Border", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_show_square = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_SHOW_SQUARE, + .name = "Show Square", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_osd_mode_strings[] = { + "All", + "Counters Only", + "None", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_OSD_TEXT_MODE, + .name = "OSD Text Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 2, + .qmenu = vivid_ctrl_osd_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_PERCENTAGE_FILL, + .name = "Fill Percentage of Frame", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .def = 100, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_INSERT_SAV, + .name = "Insert SAV Code in Image", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_INSERT_EAV, + .name = "Insert EAV Code in Image", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hflip = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HFLIP, + .name = "Sensor Flipped Horizontally", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vflip = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_VFLIP, + .name = "Sensor Flipped Vertically", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_CROP_CAP, + .name = "Enable Capture Cropping", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_COMPOSE_CAP, + .name = "Enable Capture Composing", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_SCALER_CAP, + .name = "Enable Capture Scaler", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_tstamp_src_strings[] = { + "End of Frame", + "Start of Exposure", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_TSTAMP_SRC, + .name = "Timestamp Source", + .type = V4L2_CTRL_TYPE_MENU, + .max = 1, + .qmenu = vivid_ctrl_tstamp_src_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_STD_ASPECT_RATIO, + .name = "Standard Aspect Ratio", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 4, + .def = 1, + .qmenu = tpg_aspect_strings, +}; + +static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = { + "Current DV Timings", + "No Signal", + "No Lock", + "Out of Range", + "Selected DV Timings", + "Cycle Through All DV Timings", + "Custom DV Timings", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE, + .name = "DV Timings Signal Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 5, + .qmenu = vivid_ctrl_dv_timings_signal_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO, + .name = "DV Timings Aspect Ratio", + .type = V4L2_CTRL_TYPE_MENU, + .max = 3, + .qmenu = tpg_aspect_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_MAX_EDID_BLOCKS, + .name = "Maximum EDID Blocks", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 256, + .def = 2, + .step = 1, +}; + +static const char * const vivid_ctrl_colorspace_strings[] = { + "", + "SMPTE 170M", + "SMPTE 240M", + "REC 709", + "", /* Skip Bt878 entry */ + "470 System M", + "470 System BG", + "", /* Skip JPEG entry */ + "sRGB", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_colorspace = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_COLORSPACE, + .name = "Colorspace", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 8, + .menu_skip_mask = (1 << 4) | (1 << 7), + .def = 8, + .qmenu = vivid_ctrl_colorspace_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_ALPHA_MODE, + .name = "Apply Alpha To Red Only", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_LIMITED_RGB_RANGE, + .name = "Limited RGB Range (16-235)", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* VBI Capture Control */ + +static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap); + + switch (ctrl->id) { + case VIVID_CID_VBI_CAP_INTERLACED: + dev->vbi_cap_interlaced = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = { + .s_ctrl = vivid_vbi_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = { + .ops = &vivid_vbi_cap_ctrl_ops, + .id = VIVID_CID_VBI_CAP_INTERLACED, + .name = "Interlaced VBI Format", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* Video Output Controls */ + +static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + + switch (ctrl->id) { + case VIVID_CID_HAS_CROP_OUT: + dev->has_crop_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_COMPOSE_OUT: + dev->has_compose_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_SCALER_OUT: + dev->has_scaler_out = ctrl->val; + vivid_update_format_out(dev); + break; + case V4L2_CID_DV_TX_MODE: + dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; + if (!vivid_is_hdmi_out(dev)) + break; + if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (bt->width == 720 && bt->height <= 576) + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + else + dev->colorspace_out = V4L2_COLORSPACE_REC709; + } else { + dev->colorspace_out = V4L2_COLORSPACE_SRGB; + } + if (dev->loop_video) + vivid_send_source_change(dev, HDMI); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = { + .s_ctrl = vivid_vid_out_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_CROP_OUT, + .name = "Enable Output Cropping", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_COMPOSE_OUT, + .name = "Enable Output Composing", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_SCALER_OUT, + .name = "Enable Output Scaler", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + + +/* Streaming Controls */ + +static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming); + struct timeval tv; + + switch (ctrl->id) { + case VIVID_CID_DQBUF_ERROR: + dev->dqbuf_error = true; + break; + case VIVID_CID_PERC_DROPPED: + dev->perc_dropped_buffers = ctrl->val; + break; + case VIVID_CID_QUEUE_SETUP_ERROR: + dev->queue_setup_error = true; + break; + case VIVID_CID_BUF_PREPARE_ERROR: + dev->buf_prepare_error = true; + break; + case VIVID_CID_START_STR_ERROR: + dev->start_streaming_error = true; + break; + case VIVID_CID_QUEUE_ERROR: + if (dev->vb_vid_cap_q.start_streaming_called) + vb2_queue_error(&dev->vb_vid_cap_q); + if (dev->vb_vbi_cap_q.start_streaming_called) + vb2_queue_error(&dev->vb_vbi_cap_q); + if (dev->vb_vid_out_q.start_streaming_called) + vb2_queue_error(&dev->vb_vid_out_q); + if (dev->vb_vbi_out_q.start_streaming_called) + vb2_queue_error(&dev->vb_vbi_out_q); + if (dev->vb_sdr_cap_q.start_streaming_called) + vb2_queue_error(&dev->vb_sdr_cap_q); + break; + case VIVID_CID_SEQ_WRAP: + dev->seq_wrap = ctrl->val; + break; + case VIVID_CID_TIME_WRAP: + dev->time_wrap = ctrl->val; + if (ctrl->val == 0) { + dev->time_wrap_offset = 0; + break; + } + v4l2_get_timestamp(&tv); + dev->time_wrap_offset = -tv.tv_sec - 16; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = { + .s_ctrl = vivid_streaming_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_DQBUF_ERROR, + .name = "Inject V4L2_BUF_FLAG_ERROR", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_PERC_DROPPED, + .name = "Percentage of Dropped Buffers", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_QUEUE_SETUP_ERROR, + .name = "Inject VIDIOC_REQBUFS Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_BUF_PREPARE_ERROR, + .name = "Inject VIDIOC_QBUF Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_START_STR_ERROR, + .name = "Inject VIDIOC_STREAMON Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_queue_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_QUEUE_ERROR, + .name = "Inject Fatal Streaming Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_SEQ_WRAP, + .name = "Wrap Sequence Number", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_TIME_WRAP, + .name = "Wrap Timestamp", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* SDTV Capture Controls */ + +static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap); + + switch (ctrl->id) { + case VIVID_CID_STD_SIGNAL_MODE: + dev->std_signal_mode = dev->ctrl_std_signal_mode->val; + if (dev->std_signal_mode == SELECTED_STD) + dev->query_std = vivid_standard[dev->ctrl_standard->val]; + v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD); + vivid_update_quality(dev); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = { + .s_ctrl = vivid_sdtv_cap_s_ctrl, +}; + +static const char * const vivid_ctrl_std_signal_mode_strings[] = { + "Current Standard", + "No Signal", + "No Lock", + "", + "Selected Standard", + "Cycle Through All Standards", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = { + .ops = &vivid_sdtv_cap_ctrl_ops, + .id = VIVID_CID_STD_SIGNAL_MODE, + .name = "Standard Signal Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 5, + .menu_skip_mask = 1 << 3, + .qmenu = vivid_ctrl_std_signal_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_standard = { + .ops = &vivid_sdtv_cap_ctrl_ops, + .id = VIVID_CID_STANDARD, + .name = "Standard", + .type = V4L2_CTRL_TYPE_MENU, + .max = 14, + .qmenu = vivid_ctrl_standard_strings, +}; + + + +/* Radio Receiver Controls */ + +static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx); + + switch (ctrl->id) { + case VIVID_CID_RADIO_SEEK_MODE: + dev->radio_rx_hw_seek_mode = ctrl->val; + break; + case VIVID_CID_RADIO_SEEK_PROG_LIM: + dev->radio_rx_hw_seek_prog_lim = ctrl->val; + break; + case VIVID_CID_RADIO_RX_RDS_RBDS: + dev->rds_gen.use_rbds = ctrl->val; + break; + case VIVID_CID_RADIO_RX_RDS_BLOCKIO: + dev->radio_rx_rds_controls = ctrl->val; + dev->radio_rx_caps &= ~V4L2_CAP_READWRITE; + dev->radio_rx_rds_use_alternates = false; + if (!dev->radio_rx_rds_controls) { + dev->radio_rx_caps |= V4L2_CAP_READWRITE; + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0); + __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ""); + __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ""); + } + v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + break; + case V4L2_CID_RDS_RECEPTION: + dev->radio_rx_rds_enabled = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = { + .s_ctrl = vivid_radio_rx_s_ctrl, +}; + +static const char * const vivid_ctrl_radio_rds_mode_strings[] = { + "Block I/O", + "Controls", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_RX_RDS_BLOCKIO, + .name = "RDS Rx I/O Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = vivid_ctrl_radio_rds_mode_strings, + .max = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_RX_RDS_RBDS, + .name = "Generate RBDS Instead of RDS", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = { + "Bounded", + "Wrap Around", + "Both", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_SEEK_MODE, + .name = "Radio HW Seek Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 2, + .qmenu = vivid_ctrl_radio_hw_seek_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_SEEK_PROG_LIM, + .name = "Radio Programmable HW Seek", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* Radio Transmitter Controls */ + +static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx); + + switch (ctrl->id) { + case VIVID_CID_RADIO_TX_RDS_BLOCKIO: + dev->radio_tx_rds_controls = ctrl->val; + dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; + if (!dev->radio_tx_rds_controls) + dev->radio_tx_caps |= V4L2_CAP_READWRITE; + break; + case V4L2_CID_RDS_TX_PTY: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val); + break; + case V4L2_CID_RDS_TX_PS_NAME: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char); + break; + case V4L2_CID_RDS_TX_RADIO_TEXT: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char); + break; + case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val); + break; + case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val); + break; + case V4L2_CID_RDS_TX_MUSIC_SPEECH: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = { + .s_ctrl = vivid_radio_tx_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = { + .ops = &vivid_radio_tx_ctrl_ops, + .id = VIVID_CID_RADIO_TX_RDS_BLOCKIO, + .name = "RDS Tx I/O Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = vivid_ctrl_radio_rds_mode_strings, + .max = 1, + .def = 1, +}; + + + +/* Video Loop Control */ + +static int vivid_loop_out_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_out); + + switch (ctrl->id) { + case VIVID_CID_LOOP_VIDEO: + dev->loop_video = ctrl->val; + vivid_update_quality(dev); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_loop_out_ctrl_ops = { + .s_ctrl = vivid_loop_out_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_loop_video = { + .ops = &vivid_loop_out_ctrl_ops, + .id = VIVID_CID_LOOP_VIDEO, + .name = "Loop Video", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +static const struct v4l2_ctrl_config vivid_ctrl_class = { + .ops = &vivid_user_gen_ctrl_ops, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, + .id = VIVID_CID_VIVID_CLASS, + .name = "Vivid Controls", + .type = V4L2_CTRL_TYPE_CTRL_CLASS, +}; + +int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, + bool show_ccs_out, bool no_error_inj, + bool has_sdtv, bool has_hdmi) +{ + struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen; + struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid; + struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud; + struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming; + struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap; + struct v4l2_ctrl_handler *hdl_loop_out = &dev->ctrl_hdl_loop_out; + struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap; + struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out; + struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap; + struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out; + struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; + struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; + struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap; + struct v4l2_ctrl_config vivid_ctrl_dv_timings = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS, + .name = "DV Timings", + .type = V4L2_CTRL_TYPE_MENU, + }; + int i; + + v4l2_ctrl_handler_init(hdl_user_gen, 10); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_user_vid, 9); + v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_user_aud, 2); + v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_streaming, 8); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_sdtv_cap, 2); + v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_loop_out, 1); + v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vid_cap, 55); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vid_out, 26); + v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vbi_cap, 21); + v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vbi_out, 19); + v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_radio_rx, 17); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_radio_tx, 17); + v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_sdr_cap, 18); + v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); + + /* User Controls */ + dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, + V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); + dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + if (dev->has_vid_cap) { + dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + for (i = 0; i < MAX_INPUTS; i++) + dev->input_brightness[i] = 128; + dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_HUE, -128, 128, 1, 0); + v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 100); + dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); + } + dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL); + dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL); + dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL); + dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL); + dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL); + dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); + dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); + dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); + + if (dev->has_vid_cap) { + /* Image Processing Controls */ + struct v4l2_ctrl_config vivid_ctrl_test_pattern = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_TEST_PATTERN, + .name = "Test Pattern", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_PAT_NOISE, + .qmenu = tpg_pattern_strings, + }; + + dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_test_pattern, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL); + if (show_ccs_cap) { + dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_crop_cap, NULL); + dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_compose_cap, NULL); + dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_scaler_cap, NULL); + } + + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL); + dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_colorspace, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); + } + + if (dev->has_vid_out && show_ccs_out) { + dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_crop_out, NULL); + dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_compose_out, NULL); + dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_scaler_out, NULL); + } + + /* + * Testing this driver with v4l2-compliance will trigger the error + * injection controls, and after that nothing will work as expected. + * So we have a module option to drop these error injecting controls + * allowing us to run v4l2_compliance again. + */ + if (!no_error_inj) { + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL); + } + + if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) { + if (dev->has_vid_cap) + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL); + dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap, + &vivid_ctrl_std_signal_mode, NULL); + dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap, + &vivid_ctrl_standard, NULL); + if (dev->ctrl_std_signal_mode) + v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode); + if (dev->has_raw_vbi_cap) + v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL); + } + + if (has_hdmi && dev->has_vid_cap) { + dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_dv_timings_signal_mode, NULL); + + vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1; + vivid_ctrl_dv_timings.qmenu = + (const char * const *)dev->query_dv_timings_qmenu; + dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_dv_timings, NULL); + if (dev->ctrl_dv_timings_signal_mode) + v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode); + + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL); + dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_limited_rgb_range, NULL); + dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap, + &vivid_vid_cap_ctrl_ops, + V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, + 0, V4L2_DV_RGB_RANGE_AUTO); + } + if (has_hdmi && dev->has_vid_out) { + /* + * We aren't doing anything with this at the moment, but + * HDMI outputs typically have this controls. + */ + dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, + V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, + 0, V4L2_DV_RGB_RANGE_AUTO); + dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, + V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, + 0, V4L2_DV_TX_MODE_HDMI); + } + if ((dev->has_vid_cap && dev->has_vid_out) || + (dev->has_vbi_cap && dev->has_vbi_out)) + v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_loop_video, NULL); + + if (dev->has_fb) + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_clear_fb, NULL); + + if (dev->has_radio_rx) { + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL); + v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1); + dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0); + dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0); + dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0); + dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); + dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0); + dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1); + } + if (dev->has_radio_tx) { + v4l2_ctrl_new_custom(hdl_radio_tx, + &vivid_ctrl_radio_tx_rds_blockio, NULL); + dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088); + dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3); + dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0); + if (dev->radio_tx_rds_psname) + v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX"); + dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0); + if (dev->radio_tx_rds_radiotext) + v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext, + "This is a VIVID default Radio Text template text, change at will"); + dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1); + dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0); + dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0); + dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0); + dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); + dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1); + dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1); + } + if (hdl_user_gen->error) + return hdl_user_gen->error; + if (hdl_user_vid->error) + return hdl_user_vid->error; + if (hdl_user_aud->error) + return hdl_user_aud->error; + if (hdl_streaming->error) + return hdl_streaming->error; + if (hdl_sdr_cap->error) + return hdl_sdr_cap->error; + if (hdl_loop_out->error) + return hdl_loop_out->error; + + if (dev->autogain) + v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); + + if (dev->has_vid_cap) { + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL); + if (hdl_vid_cap->error) + return hdl_vid_cap->error; + dev->vid_cap_dev.ctrl_handler = hdl_vid_cap; + } + if (dev->has_vid_out) { + v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_loop_out, NULL); + if (hdl_vid_out->error) + return hdl_vid_out->error; + dev->vid_out_dev.ctrl_handler = hdl_vid_out; + } + if (dev->has_vbi_cap) { + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL); + if (hdl_vbi_cap->error) + return hdl_vbi_cap->error; + dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap; + } + if (dev->has_vbi_out) { + v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL); + v4l2_ctrl_add_handler(hdl_vbi_out, hdl_loop_out, NULL); + if (hdl_vbi_out->error) + return hdl_vbi_out->error; + dev->vbi_out_dev.ctrl_handler = hdl_vbi_out; + } + if (dev->has_radio_rx) { + v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL); + if (hdl_radio_rx->error) + return hdl_radio_rx->error; + dev->radio_rx_dev.ctrl_handler = hdl_radio_rx; + } + if (dev->has_radio_tx) { + v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL); + if (hdl_radio_tx->error) + return hdl_radio_tx->error; + dev->radio_tx_dev.ctrl_handler = hdl_radio_tx; + } + if (dev->has_sdr_cap) { + v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL); + v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL); + if (hdl_sdr_cap->error) + return hdl_sdr_cap->error; + dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; + } + return 0; +} + +void vivid_free_controls(struct vivid_dev *dev) +{ + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_out); +} diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h new file mode 100644 index 000000000000..9bcca9d56359 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-ctrls.h @@ -0,0 +1,34 @@ +/* + * vivid-ctrls.h - control support functions. + * + * Copyright 2014 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 _VIVID_CTRLS_H_ +#define _VIVID_CTRLS_H_ + +enum vivid_hw_seek_modes { + VIVID_HW_SEEK_BOUNDED, + VIVID_HW_SEEK_WRAP, + VIVID_HW_SEEK_BOTH, +}; + +int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, + bool show_ccs_out, bool no_error_inj, + bool has_sdtv, bool has_hdmi); +void vivid_free_controls(struct vivid_dev *dev); + +#endif -- cgit v1.2.3 From ef834f7836ec0502f49f20bbc42f1240577a9c83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 07:56:18 -0300 Subject: [media] vivid: add the video capture and output parts This adds the ioctl and vb2 queue support for video capture and output. Part of this is common to both, so that is placed in a vid-common source. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 1729 +++++++++++++++++++++++ drivers/media/platform/vivid/vivid-vid-cap.h | 71 + drivers/media/platform/vivid/vivid-vid-common.c | 571 ++++++++ drivers/media/platform/vivid/vivid-vid-common.h | 61 + drivers/media/platform/vivid/vivid-vid-out.c | 1205 ++++++++++++++++ drivers/media/platform/vivid/vivid-vid-out.h | 57 + 6 files changed, 3694 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-vid-cap.c create mode 100644 drivers/media/platform/vivid/vivid-vid-cap.h create mode 100644 drivers/media/platform/vivid/vivid-vid-common.c create mode 100644 drivers/media/platform/vivid/vivid-vid-common.h create mode 100644 drivers/media/platform/vivid/vivid-vid-out.c create mode 100644 drivers/media/platform/vivid/vivid-vid-out.h diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c new file mode 100644 index 000000000000..52f24ea40af3 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -0,0 +1,1729 @@ +/* + * vivid-vid-cap.c - video capture support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-kthread-cap.h" +#include "vivid-vid-cap.h" + +/* timeperframe: min/max and default */ +static const struct v4l2_fract + tpf_min = {.numerator = 1, .denominator = FPS_MAX}, + tpf_max = {.numerator = FPS_MAX, .denominator = 1}, + tpf_default = {.numerator = 1, .denominator = 30}; + +static const struct vivid_fmt formats_ovl[] = { + { + .name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .depth = 16, + .planes = 1, + }, + { + .name = "XRGB555 (LE)", + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + .planes = 1, + }, + { + .name = "ARGB555 (LE)", + .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + .planes = 1, + }, +}; + +/* The number of discrete webcam framesizes */ +#define VIVID_WEBCAM_SIZES 3 +/* The number of discrete webcam frameintervals */ +#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2) + +/* Sizes must be in increasing order */ +static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = { + { 320, 180 }, + { 640, 360 }, + { 1280, 720 }, +}; + +/* + * Intervals must be in increasing order and there must be twice as many + * elements in this array as there are in webcam_sizes. + */ +static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = { + { 1, 10 }, + { 1, 15 }, + { 1, 25 }, + { 1, 30 }, + { 1, 50 }, + { 1, 60 }, +}; + +static const struct v4l2_discrete_probe webcam_probe = { + webcam_sizes, + VIVID_WEBCAM_SIZES +}; + +static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], void *alloc_ctxs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned planes = tpg_g_planes(&dev->tpg); + unsigned h = dev->fmt_cap_rect.height; + unsigned p; + + if (dev->field_cap == V4L2_FIELD_ALTERNATE) { + /* + * You cannot use read() with FIELD_ALTERNATE since the field + * information (TOP/BOTTOM) cannot be passed back to the user. + */ + if (vb2_fileio_is_active(vq)) + return -EINVAL; + } + + if (dev->queue_setup_error) { + /* + * Error injection: test what happens if queue_setup() returns + * an error. + */ + dev->queue_setup_error = false; + return -EINVAL; + } + if (fmt) { + const struct v4l2_pix_format_mplane *mp; + struct v4l2_format mp_fmt; + const struct vivid_fmt *vfmt; + + if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { + fmt_sp2mp(fmt, &mp_fmt); + fmt = &mp_fmt; + } + mp = &fmt->fmt.pix_mp; + /* + * Check if the number of planes in the specified format match + * the number of planes in the current format. You can't mix that. + */ + if (mp->num_planes != planes) + return -EINVAL; + vfmt = get_format(dev, mp->pixelformat); + for (p = 0; p < planes; p++) { + sizes[p] = mp->plane_fmt[p].sizeimage; + if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h + + vfmt->data_offset[p]) + return -EINVAL; + } + } else { + for (p = 0; p < planes; p++) + sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h + + dev->fmt_cap->data_offset[p]; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = planes; + + /* + * videobuf2-vmalloc allocator is context-less so no need to set + * alloc_ctxs array. + */ + + if (planes == 2) + dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, + *nbuffers, sizes[0], sizes[1]); + else + dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, + *nbuffers, sizes[0]); + + return 0; +} + +static int vid_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size; + unsigned planes = tpg_g_planes(&dev->tpg); + unsigned p; + + dprintk(dev, 1, "%s\n", __func__); + + if (WARN_ON(NULL == dev->fmt_cap)) + return -EINVAL; + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + for (p = 0; p < planes; p++) { + size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height + + dev->fmt_cap->data_offset[p]; + + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", + __func__, p, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, p, size); + vb->v4l2_planes[p].data_offset = dev->fmt_cap->data_offset[p]; + } + + return 0; +} + +static void vid_cap_buf_finish(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_timecode *tc = &vb->v4l2_buf.timecode; + unsigned fps = 25; + unsigned seq = vb->v4l2_buf.sequence; + + if (!vivid_is_sdtv_cap(dev)) + return; + + /* + * Set the timecode. Rarely used, so it is interesting to + * test this. + */ + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_TIMECODE; + if (dev->std_cap & V4L2_STD_525_60) + fps = 30; + tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; + tc->flags = 0; + tc->frames = seq % fps; + tc->seconds = (seq / fps) % 60; + tc->minutes = (seq / (60 * fps)) % 60; + tc->hours = (seq / (60 * 60 * fps)) % 24; +} + +static void vid_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vid_cap_active); + spin_unlock(&dev->slock); +} + +static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned i; + int err; + + if (vb2_is_streaming(&dev->vb_vid_out_q)) + dev->can_loop_video = vivid_vid_can_loop(dev); + + if (dev->kthread_vid_cap) + return 0; + + dev->vid_cap_seq_count = 0; + dprintk(dev, 1, "%s\n", __func__); + for (i = 0; i < VIDEO_MAX_FRAME; i++) + dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vid_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming); + dev->can_loop_video = false; +} + +const struct vb2_ops vivid_vid_cap_qops = { + .queue_setup = vid_cap_queue_setup, + .buf_prepare = vid_cap_buf_prepare, + .buf_finish = vid_cap_buf_finish, + .buf_queue = vid_cap_buf_queue, + .start_streaming = vid_cap_start_streaming, + .stop_streaming = vid_cap_stop_streaming, + .wait_prepare = vivid_unlock, + .wait_finish = vivid_lock, +}; + +/* + * Determine the 'picture' quality based on the current TV frequency: either + * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off + * signal or NOISE for no signal. + */ +void vivid_update_quality(struct vivid_dev *dev) +{ + unsigned freq_modulus; + + if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) { + /* + * The 'noise' will only be replaced by the actual video + * if the output video matches the input video settings. + */ + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (!vivid_is_tv_cap(dev)) { + tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); + return; + } + + /* + * There is a fake channel every 6 MHz at 49.25, 55.25, etc. + * From +/- 0.25 MHz around the channel there is color, and from + * +/- 1 MHz there is grayscale (chroma is lost). + * Everywhere else it is just noise. + */ + freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); + if (freq_modulus > 2 * 16) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, + next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f); + return; + } + if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/) + tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0); + else + tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); +} + +/* + * Get the current picture quality and the associated afc value. + */ +static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) +{ + unsigned freq_modulus; + + if (afc) + *afc = 0; + if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR || + tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) + return tpg_g_quality(&dev->tpg); + + /* + * There is a fake channel every 6 MHz at 49.25, 55.25, etc. + * From +/- 0.25 MHz around the channel there is color, and from + * +/- 1 MHz there is grayscale (chroma is lost). + * Everywhere else it is just gray. + */ + freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); + if (afc) + *afc = freq_modulus - 1 * 16; + return TPG_QUAL_GRAY; +} + +enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return dev->std_aspect_ratio; + + if (vivid_is_hdmi_cap(dev)) + return dev->dv_timings_aspect_ratio; + + return TPG_VIDEO_ASPECT_IMAGE; +} + +static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return (dev->std_cap & V4L2_STD_525_60) ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + if (vivid_is_hdmi_cap(dev) && + dev->src_rect.width == 720 && dev->src_rect.height <= 576) + return dev->src_rect.height == 480 ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + return TPG_PIXEL_ASPECT_SQUARE; +} + +/* + * Called whenever the format has to be reset which can occur when + * changing inputs, standard, timings, etc. + */ +void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) +{ + struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + unsigned size; + + switch (dev->input_type[dev->input]) { + case WEBCAM: + default: + dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width; + dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height; + dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx]; + dev->field_cap = V4L2_FIELD_NONE; + tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); + break; + case TV: + case SVID: + dev->field_cap = dev->tv_field_cap; + dev->src_rect.width = 720; + if (dev->std_cap & V4L2_STD_525_60) { + dev->src_rect.height = 480; + dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; + dev->service_set_cap = V4L2_SLICED_CAPTION_525; + } else { + dev->src_rect.height = 576; + dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 }; + dev->service_set_cap = V4L2_SLICED_WSS_625; + } + tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); + break; + case HDMI: + dev->src_rect.width = bt->width; + dev->src_rect.height = bt->height; + size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + dev->timeperframe_vid_cap = (struct v4l2_fract) { + size / 100, (u32)bt->pixelclock / 100 + }; + if (bt->interlaced) + dev->field_cap = V4L2_FIELD_ALTERNATE; + else + dev->field_cap = V4L2_FIELD_NONE; + + /* + * We can be called from within s_ctrl, in that case we can't + * set/get controls. Luckily we don't need to in that case. + */ + if (keep_controls || !dev->colorspace) + break; + if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (bt->width == 720 && bt->height <= 576) + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M); + else + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709); + v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1); + } else { + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB); + v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0); + } + tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap)); + break; + } + vivid_update_quality(dev); + tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap); + dev->crop_cap = dev->src_rect; + dev->crop_bounds_cap = dev->src_rect; + dev->compose_cap = dev->crop_cap; + if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap)) + dev->compose_cap.height /= 2; + dev->fmt_cap_rect = dev->compose_cap; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev)); + tpg_update_mv_step(&dev->tpg); +} + +/* Map the field to something that is valid for the current input */ +static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field) +{ + if (vivid_is_sdtv_cap(dev)) { + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + return field; + case V4L2_FIELD_INTERLACED: + default: + return V4L2_FIELD_INTERLACED; + } + } + if (vivid_is_hdmi_cap(dev)) + return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE : + V4L2_FIELD_NONE; + return V4L2_FIELD_NONE; +} + +static unsigned vivid_colorspace_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_colorspace(&dev->tpg); + return dev->colorspace_out; +} + +int vivid_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + unsigned p; + + mp->width = dev->fmt_cap_rect.width; + mp->height = dev->fmt_cap_rect.height; + mp->field = dev->field_cap; + mp->pixelformat = dev->fmt_cap->fourcc; + mp->colorspace = vivid_colorspace_cap(dev); + mp->num_planes = dev->fmt_cap->planes; + for (p = 0; p < mp->num_planes; p++) { + mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); + mp->plane_fmt[p].sizeimage = + mp->plane_fmt[p].bytesperline * mp->height + + dev->fmt_cap->data_offset[p]; + } + return 0; +} + +int vivid_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + unsigned bytesperline, max_bpl; + unsigned factor = 1; + unsigned w, h; + unsigned p; + + fmt = get_format(dev, mp->pixelformat); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", + mp->pixelformat); + mp->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = get_format(dev, mp->pixelformat); + } + + mp->field = vivid_field_cap(dev, mp->field); + if (vivid_is_webcam(dev)) { + const struct v4l2_frmsize_discrete *sz = + v4l2_find_nearest_format(&webcam_probe, mp->width, mp->height); + + w = sz->width; + h = sz->height; + } else if (vivid_is_sdtv_cap(dev)) { + w = 720; + h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576; + } else { + w = dev->src_rect.width; + h = dev->src_rect.height; + } + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + if (vivid_is_webcam(dev) || + (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) { + mp->width = w; + mp->height = h / factor; + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + + rect_set_min_size(&r, &vivid_min_rect); + rect_set_max_size(&r, &vivid_max_rect); + if (dev->has_scaler_cap && !dev->has_compose_cap) { + struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; + + rect_set_max_size(&r, &max_r); + } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { + rect_set_max_size(&r, &dev->src_rect); + } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { + rect_set_min_size(&r, &dev->src_rect); + } + mp->width = r.width; + mp->height = r.height / factor; + } + + /* This driver supports custom bytesperline values */ + + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->depth) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; + mp->num_planes = fmt->planes; + for (p = 0; p < mp->num_planes; p++) { + if (pfmt[p].bytesperline > max_bpl) + pfmt[p].bytesperline = max_bpl; + if (pfmt[p].bytesperline < bytesperline) + pfmt[p].bytesperline = bytesperline; + pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height + + fmt->data_offset[p]; + memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); + } + mp->colorspace = vivid_colorspace_cap(dev); + memset(mp->reserved, 0, sizeof(mp->reserved)); + return 0; +} + +int vivid_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_cap; + struct v4l2_rect *compose = &dev->compose_cap; + struct vb2_queue *q = &dev->vb_vid_cap_q; + int ret = vivid_try_fmt_vid_cap(file, priv, f); + unsigned factor = 1; + unsigned i; + + if (ret < 0) + return ret; + + if (vb2_is_busy(q)) { + dprintk(dev, 1, "%s device busy\n", __func__); + return -EBUSY; + } + + if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) { + dprintk(dev, 1, "overlay is active, can't change pixelformat\n"); + return -EBUSY; + } + + dev->fmt_cap = get_format(dev, mp->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + + /* Note: the webcam input doesn't support scaling, cropping or composing */ + + if (!vivid_is_webcam(dev) && + (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + if (dev->has_scaler_cap) { + if (dev->has_compose_cap) + rect_map_inside(compose, &r); + else + *compose = r; + if (dev->has_crop_cap && !dev->has_compose_cap) { + struct v4l2_rect min_r = { + 0, 0, + r.width / MAX_ZOOM, + factor * r.height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + r.width * MAX_ZOOM, + factor * r.height * MAX_ZOOM + }; + + rect_set_min_size(crop, &min_r); + rect_set_max_size(crop, &max_r); + rect_map_inside(crop, &dev->crop_bounds_cap); + } else if (dev->has_crop_cap) { + struct v4l2_rect min_r = { + 0, 0, + compose->width / MAX_ZOOM, + factor * compose->height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + compose->width * MAX_ZOOM, + factor * compose->height * MAX_ZOOM + }; + + rect_set_min_size(crop, &min_r); + rect_set_max_size(crop, &max_r); + rect_map_inside(crop, &dev->crop_bounds_cap); + } + } else if (dev->has_crop_cap && !dev->has_compose_cap) { + r.height *= factor; + rect_set_size_to(crop, &r); + rect_map_inside(crop, &dev->crop_bounds_cap); + r = *crop; + r.height /= factor; + rect_set_size_to(compose, &r); + } else if (!dev->has_crop_cap) { + rect_map_inside(compose, &r); + } else { + r.height *= factor; + rect_set_max_size(crop, &r); + rect_map_inside(crop, &dev->crop_bounds_cap); + compose->top *= factor; + compose->height *= factor; + rect_set_size_to(compose, crop); + rect_map_inside(compose, &r); + compose->top /= factor; + compose->height /= factor; + } + } else if (vivid_is_webcam(dev)) { + /* Guaranteed to be a match */ + for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) + if (webcam_sizes[i].width == mp->width && + webcam_sizes[i].height == mp->height) + break; + dev->webcam_size_idx = i; + if (dev->webcam_ival_idx >= 2 * (3 - i)) + dev->webcam_ival_idx = 2 * (3 - i) - 1; + vivid_update_format_cap(dev, false); + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + rect_set_size_to(compose, &r); + r.height *= factor; + rect_set_size_to(crop, &r); + } + + dev->fmt_cap_rect.width = mp->width; + dev->fmt_cap_rect.height = mp->height; + tpg_s_buf_height(&dev->tpg, mp->height); + tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline); + if (tpg_g_planes(&dev->tpg) > 1) + tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline); + dev->field_cap = mp->field; + tpg_s_field(&dev->tpg, dev->field_cap); + tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + if (vivid_is_sdtv_cap(dev)) + dev->tv_field_cap = mp->field; + tpg_update_mv_step(&dev->tpg); + return 0; +} + +int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_g_fmt_vid_cap(file, priv, f); +} + +int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_try_fmt_vid_cap(file, priv, f); +} + +int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_s_fmt_vid_cap(file, priv, f); +} + +int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap); +} + +int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap); +} + +int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap); +} + +int vivid_vid_cap_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->has_crop_cap && !dev->has_compose_cap) + return -ENOTTY; + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (vivid_is_webcam(dev)) + return -EINVAL; + + sel->r.left = sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_cap) + return -EINVAL; + sel->r = dev->crop_cap; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (!dev->has_crop_cap) + return -EINVAL; + sel->r = dev->src_rect; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = vivid_max_rect; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = dev->compose_cap; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = dev->fmt_cap_rect; + break; + default: + return -EINVAL; + } + return 0; +} + +int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_cap; + struct v4l2_rect *compose = &dev->compose_cap; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; + int ret; + + if (!dev->has_crop_cap && !dev->has_compose_cap) + return -ENOTTY; + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (vivid_is_webcam(dev)) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_cap) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + rect_set_min_size(&s->r, &vivid_min_rect); + rect_set_max_size(&s->r, &dev->src_rect); + rect_map_inside(&s->r, &dev->crop_bounds_cap); + s->r.top /= factor; + s->r.height /= factor; + if (dev->has_scaler_cap) { + struct v4l2_rect fmt = dev->fmt_cap_rect; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + s->r.height * MAX_ZOOM + }; + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + s->r.height / MAX_ZOOM + }; + + rect_set_min_size(&fmt, &min_rect); + if (!dev->has_compose_cap) + rect_set_max_size(&fmt, &max_rect); + if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + if (dev->has_compose_cap) { + rect_set_min_size(compose, &min_rect); + rect_set_max_size(compose, &max_rect); + } + dev->fmt_cap_rect = fmt; + tpg_s_buf_height(&dev->tpg, fmt.height); + } else if (dev->has_compose_cap) { + struct v4l2_rect fmt = dev->fmt_cap_rect; + + rect_set_min_size(&fmt, &s->r); + if (!rect_same_size(&dev->fmt_cap_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + dev->fmt_cap_rect = fmt; + tpg_s_buf_height(&dev->tpg, fmt.height); + rect_set_size_to(compose, &s->r); + rect_map_inside(compose, &dev->fmt_cap_rect); + } else { + if (!rect_same_size(&s->r, &dev->fmt_cap_rect) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + rect_set_size_to(&dev->fmt_cap_rect, &s->r); + rect_set_size_to(compose, &s->r); + rect_map_inside(compose, &dev->fmt_cap_rect); + tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); + } + s->r.top *= factor; + s->r.height *= factor; + *crop = s->r; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_cap) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + rect_set_min_size(&s->r, &vivid_min_rect); + rect_set_max_size(&s->r, &dev->fmt_cap_rect); + if (dev->has_scaler_cap) { + struct v4l2_rect max_rect = { + 0, 0, + dev->src_rect.width * MAX_ZOOM, + (dev->src_rect.height / factor) * MAX_ZOOM + }; + + rect_set_max_size(&s->r, &max_rect); + if (dev->has_crop_cap) { + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + (s->r.height * factor) / MAX_ZOOM + }; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + (s->r.height * factor) * MAX_ZOOM + }; + + rect_set_min_size(crop, &min_rect); + rect_set_max_size(crop, &max_rect); + rect_map_inside(crop, &dev->crop_bounds_cap); + } + } else if (dev->has_crop_cap) { + s->r.top *= factor; + s->r.height *= factor; + rect_set_max_size(&s->r, &dev->src_rect); + rect_set_size_to(crop, &s->r); + rect_map_inside(crop, &dev->crop_bounds_cap); + s->r.top /= factor; + s->r.height /= factor; + } else { + rect_set_size_to(&s->r, &dev->src_rect); + s->r.height /= factor; + } + rect_map_inside(&s->r, &dev->fmt_cap_rect); + if (dev->bitmap_cap && (compose->width != s->r.width || + compose->height != s->r.height)) { + kfree(dev->bitmap_cap); + dev->bitmap_cap = NULL; + } + *compose = s->r; + break; + default: + return -EINVAL; + } + + tpg_s_crop_compose(&dev->tpg, crop, compose); + return 0; +} + +int vivid_vid_cap_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (vivid_get_pixel_aspect(dev)) { + case TPG_PIXEL_ASPECT_NTSC: + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + break; + case TPG_PIXEL_ASPECT_PAL: + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + break; + case TPG_PIXEL_ASPECT_SQUARE: + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + break; + } + return 0; +} + +int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct vivid_fmt *fmt; + + if (f->index >= ARRAY_SIZE(formats_ovl)) + return -EINVAL; + + fmt = &formats_ovl[f->index]; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + return 0; +} + +int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + unsigned clipcount = win->clipcount; + + win->w.top = dev->overlay_cap_top; + win->w.left = dev->overlay_cap_left; + win->w.width = compose->width; + win->w.height = compose->height; + win->field = dev->overlay_cap_field; + win->clipcount = dev->clipcount_cap; + if (clipcount > dev->clipcount_cap) + clipcount = dev->clipcount_cap; + if (dev->bitmap_cap == NULL) + win->bitmap = NULL; + else if (win->bitmap) { + if (copy_to_user(win->bitmap, dev->bitmap_cap, + ((compose->width + 7) / 8) * compose->height)) + return -EFAULT; + } + if (clipcount && win->clips) { + if (copy_to_user(win->clips, dev->clips_cap, + clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + int i, j; + + win->w.left = clamp_t(int, win->w.left, + -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); + win->w.top = clamp_t(int, win->w.top, + -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); + win->w.width = compose->width; + win->w.height = compose->height; + if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP) + win->field = V4L2_FIELD_ANY; + win->chromakey = 0; + win->global_alpha = 0; + if (win->clipcount && !win->clips) + win->clipcount = 0; + if (win->clipcount > MAX_CLIPS) + win->clipcount = MAX_CLIPS; + if (win->clipcount) { + if (copy_from_user(dev->try_clips_cap, win->clips, + win->clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + for (i = 0; i < win->clipcount; i++) { + struct v4l2_rect *r = &dev->try_clips_cap[i].c; + + r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1); + r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top); + r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1); + r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left); + } + /* + * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small + * number and it's typically a one-time deal. + */ + for (i = 0; i < win->clipcount - 1; i++) { + struct v4l2_rect *r1 = &dev->try_clips_cap[i].c; + + for (j = i + 1; j < win->clipcount; j++) { + struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; + + if (rect_overlap(r1, r2)) + return -EINVAL; + } + } + if (copy_to_user(win->clips, dev->try_clips_cap, + win->clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + int ret = vidioc_try_fmt_vid_overlay(file, priv, f); + unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; + unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]); + void *new_bitmap = NULL; + + if (ret) + return ret; + + if (win->bitmap) { + new_bitmap = vzalloc(bitmap_size); + + if (new_bitmap == NULL) + return -ENOMEM; + if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { + vfree(new_bitmap); + return -EFAULT; + } + } + + dev->overlay_cap_top = win->w.top; + dev->overlay_cap_left = win->w.left; + dev->overlay_cap_field = win->field; + vfree(dev->bitmap_cap); + dev->bitmap_cap = new_bitmap; + dev->clipcount_cap = win->clipcount; + if (dev->clipcount_cap) + memcpy(dev->clips_cap, dev->try_clips_cap, clips_size); + return 0; +} + +int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (i && dev->fb_vbase_cap == NULL) + return -EINVAL; + + if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) { + dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n"); + return -EINVAL; + } + + if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh) + return -EBUSY; + dev->overlay_cap_owner = i ? fh : NULL; + return 0; +} + +int vivid_vid_cap_g_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + *a = dev->fb_cap; + a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | + V4L2_FBUF_CAP_LIST_CLIPPING; + a->flags = V4L2_FBUF_FLAG_PRIMARY; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.priv = 0; + return 0; +} + +int vivid_vid_cap_s_fbuf(struct file *file, void *fh, + const struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (dev->overlay_cap_owner) + return -EBUSY; + + if (a->base == NULL) { + dev->fb_cap.base = NULL; + dev->fb_vbase_cap = NULL; + return 0; + } + + if (a->fmt.width < 48 || a->fmt.height < 32) + return -EINVAL; + fmt = get_format(dev, a->fmt.pixelformat); + if (!fmt || !fmt->can_do_overlay) + return -EINVAL; + if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8) + return -EINVAL; + if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) + return -EINVAL; + + dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base); + dev->fb_cap = *a; + dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left, + -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); + dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top, + -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); + return 0; +} + +static const struct v4l2_audio vivid_audio_inputs[] = { + { 0, "TV", V4L2_AUDCAP_STEREO }, + { 1, "Line-In", V4L2_AUDCAP_STEREO }, +}; + +int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (inp->index >= dev->num_inputs) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + switch (dev->input_type[inp->index]) { + case WEBCAM: + snprintf(inp->name, sizeof(inp->name), "Webcam %u", + dev->input_name_counter[inp->index]); + inp->capabilities = 0; + break; + case TV: + snprintf(inp->name, sizeof(inp->name), "TV %u", + dev->input_name_counter[inp->index]); + inp->type = V4L2_INPUT_TYPE_TUNER; + inp->std = V4L2_STD_ALL; + if (dev->has_audio_inputs) + inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; + inp->capabilities = V4L2_IN_CAP_STD; + break; + case SVID: + snprintf(inp->name, sizeof(inp->name), "S-Video %u", + dev->input_name_counter[inp->index]); + inp->std = V4L2_STD_ALL; + if (dev->has_audio_inputs) + inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; + inp->capabilities = V4L2_IN_CAP_STD; + break; + case HDMI: + snprintf(inp->name, sizeof(inp->name), "HDMI %u", + dev->input_name_counter[inp->index]); + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + if (dev->edid_blocks == 0 || + dev->dv_timings_signal_mode == NO_SIGNAL) + inp->status |= V4L2_IN_ST_NO_SIGNAL; + else if (dev->dv_timings_signal_mode == NO_LOCK || + dev->dv_timings_signal_mode == OUT_OF_RANGE) + inp->status |= V4L2_IN_ST_NO_H_LOCK; + break; + } + if (dev->sensor_hflip) + inp->status |= V4L2_IN_ST_HFLIP; + if (dev->sensor_vflip) + inp->status |= V4L2_IN_ST_VFLIP; + if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { + if (dev->std_signal_mode == NO_SIGNAL) { + inp->status |= V4L2_IN_ST_NO_SIGNAL; + } else if (dev->std_signal_mode == NO_LOCK) { + inp->status |= V4L2_IN_ST_NO_H_LOCK; + } else if (vivid_is_tv_cap(dev)) { + switch (tpg_g_quality(&dev->tpg)) { + case TPG_QUAL_GRAY: + inp->status |= V4L2_IN_ST_COLOR_KILL; + break; + case TPG_QUAL_NOISE: + inp->status |= V4L2_IN_ST_NO_H_LOCK; + break; + default: + break; + } + } + } + return 0; +} + +int vidioc_g_input(struct file *file, void *priv, unsigned *i) +{ + struct vivid_dev *dev = video_drvdata(file); + + *i = dev->input; + return 0; +} + +int vidioc_s_input(struct file *file, void *priv, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + unsigned brightness; + + if (i >= dev->num_inputs) + return -EINVAL; + + if (i == dev->input) + return 0; + + if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + + dev->input = i; + dev->vid_cap_dev.tvnorms = 0; + if (dev->input_type[i] == TV || dev->input_type[i] == SVID) { + dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1; + dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; + } + dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; + vivid_update_format_cap(dev, false); + + if (dev->colorspace) { + switch (dev->input_type[i]) { + case WEBCAM: + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB); + break; + case TV: + case SVID: + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M); + break; + case HDMI: + if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M); + else + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709); + } else { + v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB); + } + break; + } + } + + /* + * Modify the brightness range depending on the input. + * This makes it easy to use vivid 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. + */ + brightness = 128 * i + dev->input_brightness[i]; + v4l2_ctrl_modify_range(dev->brightness, + 128 * i, 255 + 128 * i, 1, 128 + 128 * i); + v4l2_ctrl_s_ctrl(dev->brightness, brightness); + return 0; +} + +int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) + return -EINVAL; + *vin = vivid_audio_inputs[vin->index]; + return 0; +} + +int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + *vin = vivid_audio_inputs[dev->tv_audio_input]; + return 0; +} + +int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) + return -EINVAL; + dev->tv_audio_input = vin->index; + return 0; +} + +int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vf->tuner != 0) + return -EINVAL; + vf->frequency = dev->tv_freq; + return 0; +} + +int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vf->tuner != 0) + return -EINVAL; + dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ); + if (vivid_is_tv_cap(dev)) + vivid_update_quality(dev); + return 0; +} + +int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vt->index != 0) + return -EINVAL; + if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2) + return -EINVAL; + dev->tv_audmode = vt->audmode; + return 0; +} + +int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + enum tpg_quality qual; + + if (vt->index != 0) + return -EINVAL; + + vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->audmode = dev->tv_audmode; + vt->rangelow = MIN_TV_FREQ; + vt->rangehigh = MAX_TV_FREQ; + qual = vivid_get_quality(dev, &vt->afc); + if (qual == TPG_QUAL_COLOR) + vt->signal = 0xffff; + else if (qual == TPG_QUAL_GRAY) + vt->signal = 0x8000; + else + vt->signal = 0; + if (qual == TPG_QUAL_NOISE) { + vt->rxsubchans = 0; + } else if (qual == TPG_QUAL_GRAY) { + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + } else { + unsigned channel_nr = dev->tv_freq / (6 * 16); + unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3; + + switch (channel_nr % options) { + case 0: + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + case 1: + vt->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 2: + if (dev->std_cap & V4L2_STD_NTSC_M) + vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; + else + vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 3: + vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; + break; + } + } + strlcpy(vt->name, "TV Tuner", sizeof(vt->name)); + return 0; +} + +/* Must remain in sync with the vivid_ctrl_standard_strings array */ +const v4l2_std_id vivid_standard[] = { + V4L2_STD_NTSC_M, + V4L2_STD_NTSC_M_JP, + V4L2_STD_NTSC_M_KR, + V4L2_STD_NTSC_443, + V4L2_STD_PAL_BG | V4L2_STD_PAL_H, + V4L2_STD_PAL_I, + V4L2_STD_PAL_DK, + V4L2_STD_PAL_M, + V4L2_STD_PAL_N, + V4L2_STD_PAL_Nc, + V4L2_STD_PAL_60, + V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + V4L2_STD_SECAM_DK, + V4L2_STD_SECAM_L, + V4L2_STD_SECAM_LC, + V4L2_STD_UNKNOWN +}; + +/* Must remain in sync with the vivid_standard array */ +const char * const vivid_ctrl_standard_strings[] = { + "NTSC-M", + "NTSC-M-JP", + "NTSC-M-KR", + "NTSC-443", + "PAL-BGH", + "PAL-I", + "PAL-DK", + "PAL-M", + "PAL-N", + "PAL-Nc", + "PAL-60", + "SECAM-BGH", + "SECAM-DK", + "SECAM-L", + "SECAM-Lc", + NULL, +}; + +int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + if (dev->std_signal_mode == NO_SIGNAL || + dev->std_signal_mode == NO_LOCK) { + *id = V4L2_STD_UNKNOWN; + return 0; + } + if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) { + *id = V4L2_STD_UNKNOWN; + } else if (dev->std_signal_mode == CURRENT_STD) { + *id = dev->std_cap; + } else if (dev->std_signal_mode == SELECTED_STD) { + *id = dev->query_std; + } else { + *id = vivid_standard[dev->query_std_last]; + dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard); + } + + return 0; +} + +int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + if (dev->std_cap == id) + return 0; + if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->std_cap = id; + vivid_update_format_cap(dev, false); + return 0; +} + +int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + if (vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, + 0, NULL, NULL)) + return -EINVAL; + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) + return 0; + dev->dv_timings_cap = *timings; + vivid_update_format_cap(dev, false); + return 0; +} + +int vidioc_query_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + if (dev->dv_timings_signal_mode == NO_SIGNAL || + dev->edid_blocks == 0) + return -ENOLINK; + if (dev->dv_timings_signal_mode == NO_LOCK) + return -ENOLCK; + if (dev->dv_timings_signal_mode == OUT_OF_RANGE) { + timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; + return -ERANGE; + } + if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) { + *timings = dev->dv_timings_cap; + } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) { + *timings = v4l2_dv_timings_presets[dev->query_dv_timings]; + } else { + *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last]; + dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) % + dev->query_dv_timings_size; + } + return 0; +} + +int vidioc_s_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI || edid->start_block) + return -EINVAL; + if (edid->blocks == 0) { + dev->edid_blocks = 0; + return 0; + } + if (edid->blocks > dev->edid_max_blocks) { + edid->blocks = dev->edid_max_blocks; + return -E2BIG; + } + dev->edid_blocks = edid->blocks; + memcpy(dev->edid, edid->edid, edid->blocks * 128); + return 0; +} + +int vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev) && !dev->has_scaler_cap) + return -EINVAL; + if (get_format(dev, fsize->pixel_format) == NULL) + return -EINVAL; + if (vivid_is_webcam(dev)) { + if (fsize->index >= ARRAY_SIZE(webcam_sizes)) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete = webcam_sizes[fsize->index]; + return 0; + } + if (fsize->index) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM; + fsize->stepwise.step_width = 2; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM; + fsize->stepwise.step_height = 2; + return 0; +} + +/* timeperframe is arbitrary and continuous */ +int vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + int i; + + fmt = get_format(dev, fival->pixel_format); + if (!fmt) + return -EINVAL; + + if (!vivid_is_webcam(dev)) { + static const struct v4l2_fract step = { 1, 1 }; + + if (fival->index) + return -EINVAL; + if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) + return -EINVAL; + if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) + return -EINVAL; + fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + fival->stepwise.min = tpf_min; + fival->stepwise.max = tpf_max; + fival->stepwise.step = step; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) + if (fival->width == webcam_sizes[i].width && + fival->height == webcam_sizes[i].height) + break; + if (i == ARRAY_SIZE(webcam_sizes)) + return -EINVAL; + if (fival->index >= 2 * (3 - i)) + return -EINVAL; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = webcam_intervals[fival->index]; + return 0; +} + +int vivid_vid_cap_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = dev->timeperframe_vid_cap; + parm->parm.capture.readbuffers = 1; + return 0; +} + +#define FRACT_CMP(a, OP, b) \ + ((u64)(a).numerator * (b).denominator OP (u64)(b).numerator * (a).denominator) + +int vivid_vid_cap_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned ival_sz = 2 * (3 - dev->webcam_size_idx); + struct v4l2_fract tpf; + unsigned i; + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (!vivid_is_webcam(dev)) + return vivid_vid_cap_g_parm(file, priv, parm); + + tpf = parm->parm.capture.timeperframe; + + if (tpf.denominator == 0) + tpf = webcam_intervals[ival_sz - 1]; + for (i = 0; i < ival_sz; i++) + if (FRACT_CMP(tpf, >=, webcam_intervals[i])) + break; + if (i == ival_sz) + i = ival_sz - 1; + dev->webcam_ival_idx = i; + tpf = webcam_intervals[dev->webcam_ival_idx]; + tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; + tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; + + /* resync the thread's timings */ + dev->cap_seq_resync = true; + dev->timeperframe_vid_cap = tpf; + parm->parm.capture.timeperframe = tpf; + parm->parm.capture.readbuffers = 1; + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h new file mode 100644 index 000000000000..94079815dbc2 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-cap.h @@ -0,0 +1,71 @@ +/* + * vivid-vid-cap.h - video capture support functions. + * + * Copyright 2014 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 _VIVID_VID_CAP_H_ +#define _VIVID_VID_CAP_H_ + +void vivid_update_quality(struct vivid_dev *dev); +void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls); +enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev); + +extern const v4l2_std_id vivid_standard[]; +extern const char * const vivid_ctrl_standard_strings[]; + +extern const struct vb2_ops vivid_vid_cap_qops; + +int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); +int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_cap_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap); +int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i); +int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); +int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp); +int vidioc_g_input(struct file *file, void *priv, unsigned *i); +int vidioc_s_input(struct file *file, void *priv, unsigned i); +int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin); +int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin); +int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin); +int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); +int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id); +int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id); +int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); +int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival); +int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); +int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); + +#endif diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c new file mode 100644 index 000000000000..7b981c176ad8 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -0,0 +1,571 @@ +/* + * vivid-vid-common.c - common video support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" + +const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT, + V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) +}; + +/* ------------------------------------------------------------------ + Basic structures + ------------------------------------------------------------------*/ + +struct vivid_fmt vivid_formats[] = { + { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .is_yuv = true, + .planes = 1, + .data_offset = { PLANE0_DATA_OFFSET, 0 }, + }, + { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .is_yuv = true, + .planes = 1, + }, + { + .name = "4:2:2, packed, YVYU", + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = 16, + .is_yuv = true, + .planes = 1, + }, + { + .name = "4:2:2, packed, VYUY", + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = 16, + .is_yuv = true, + .planes = 1, + }, + { + .name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + }, + { + .name = "RGB565 (BE)", + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + }, + { + .name = "RGB555 (LE)", + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + }, + { + .name = "XRGB555 (LE)", + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + }, + { + .name = "ARGB555 (LE)", + .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .name = "RGB555 (BE)", + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .depth = 16, + .planes = 1, + .can_do_overlay = true, + }, + { + .name = "RGB24 (LE)", + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .depth = 24, + .planes = 1, + }, + { + .name = "RGB24 (BE)", + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .depth = 24, + .planes = 1, + }, + { + .name = "RGB32 (LE)", + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .depth = 32, + .planes = 1, + }, + { + .name = "RGB32 (BE)", + .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ + .depth = 32, + .planes = 1, + }, + { + .name = "XRGB32 (LE)", + .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */ + .depth = 32, + .planes = 1, + }, + { + .name = "XRGB32 (BE)", + .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */ + .depth = 32, + .planes = 1, + }, + { + .name = "ARGB32 (LE)", + .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ + .depth = 32, + .planes = 1, + .alpha_mask = 0x000000ff, + }, + { + .name = "ARGB32 (BE)", + .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ + .depth = 32, + .planes = 1, + .alpha_mask = 0xff000000, + }, + { + .name = "4:2:2, planar, YUV", + .fourcc = V4L2_PIX_FMT_NV16M, + .depth = 8, + .is_yuv = true, + .planes = 2, + .data_offset = { PLANE0_DATA_OFFSET, 0 }, + }, + { + .name = "4:2:2, planar, YVU", + .fourcc = V4L2_PIX_FMT_NV61M, + .depth = 8, + .is_yuv = true, + .planes = 2, + .data_offset = { 0, PLANE0_DATA_OFFSET }, + }, +}; + +/* There are 2 multiplanar formats in the list */ +#define VIVID_MPLANAR_FORMATS 2 + +const struct vivid_fmt *get_format(struct vivid_dev *dev, u32 pixelformat) +{ + const struct vivid_fmt *fmt; + unsigned k; + + for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { + fmt = &vivid_formats[k]; + if (fmt->fourcc == pixelformat) + if (fmt->planes == 1 || dev->multiplanar) + return fmt; + } + + return NULL; +} + +bool vivid_vid_can_loop(struct vivid_dev *dev) +{ + if (dev->src_rect.width != dev->sink_rect.width || + dev->src_rect.height != dev->sink_rect.height) + return false; + if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc) + return false; + if (dev->field_cap != dev->field_out) + return false; + if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { + if (!(dev->std_cap & V4L2_STD_525_60) != + !(dev->std_out & V4L2_STD_525_60)) + return false; + return true; + } + if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev)) + return true; + return false; +} + +void vivid_send_source_change(struct vivid_dev *dev, unsigned type) +{ + struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + unsigned i; + + for (i = 0; i < dev->num_inputs; i++) { + ev.id = i; + if (dev->input_type[i] == type) { + if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap) + v4l2_event_queue(&dev->vid_cap_dev, &ev); + if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap) + v4l2_event_queue(&dev->vbi_cap_dev, &ev); + } + } +} + +/* + * Conversion function that converts a single-planar format to a + * single-plane multiplanar format. + */ +void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) +{ + struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp; + struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; + const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix; + bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT; + + memset(mp->reserved, 0, sizeof(mp->reserved)); + mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_CAP_VIDEO_CAPTURE_MPLANE; + mp->width = pix->width; + mp->height = pix->height; + mp->pixelformat = pix->pixelformat; + mp->field = pix->field; + mp->colorspace = pix->colorspace; + mp->num_planes = 1; + mp->flags = pix->flags; + ppix->sizeimage = pix->sizeimage; + ppix->bytesperline = pix->bytesperline; + memset(ppix->reserved, 0, sizeof(ppix->reserved)); +} + +int fmt_sp2mp_func(struct file *file, void *priv, + struct v4l2_format *f, fmtfunc func) +{ + struct v4l2_format fmt; + struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp; + struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + /* Converts to a mplane format */ + fmt_sp2mp(f, &fmt); + /* Passes it to the generic mplane format function */ + ret = func(file, priv, &fmt); + /* Copies back the mplane data to the single plane format */ + pix->width = mp->width; + pix->height = mp->height; + pix->pixelformat = mp->pixelformat; + pix->field = mp->field; + pix->colorspace = mp->colorspace; + pix->sizeimage = ppix->sizeimage; + pix->bytesperline = ppix->bytesperline; + pix->flags = mp->flags; + return ret; +} + +/* v4l2_rect helper function: copy the width/height values */ +void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size) +{ + r->width = size->width; + r->height = size->height; +} + +/* v4l2_rect helper function: width and height of r should be >= min_size */ +void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size) +{ + if (r->width < min_size->width) + r->width = min_size->width; + if (r->height < min_size->height) + r->height = min_size->height; +} + +/* v4l2_rect helper function: width and height of r should be <= max_size */ +void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size) +{ + if (r->width > max_size->width) + r->width = max_size->width; + if (r->height > max_size->height) + r->height = max_size->height; +} + +/* v4l2_rect helper function: r should be inside boundary */ +void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary) +{ + rect_set_max_size(r, boundary); + if (r->left < boundary->left) + r->left = boundary->left; + if (r->top < boundary->top) + r->top = boundary->top; + if (r->left + r->width > boundary->width) + r->left = boundary->width - r->width; + if (r->top + r->height > boundary->height) + r->top = boundary->height - r->height; +} + +/* v4l2_rect helper function: return true if r1 has the same size as r2 */ +bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2) +{ + return r1->width == r2->width && r1->height == r2->height; +} + +/* v4l2_rect helper function: calculate the intersection of two rects */ +struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b) +{ + struct v4l2_rect r; + int right, bottom; + + r.top = max(a->top, b->top); + r.left = max(a->left, b->left); + bottom = min(a->top + a->height, b->top + b->height); + right = min(a->left + a->width, b->left + b->width); + r.height = max(0, bottom - r.top); + r.width = max(0, right - r.left); + return r; +} + +/* + * v4l2_rect helper function: scale rect r by to->width / from->width and + * to->height / from->height. + */ +void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from, + const struct v4l2_rect *to) +{ + if (from->width == 0 || from->height == 0) { + r->left = r->top = r->width = r->height = 0; + return; + } + r->left = (((r->left - from->left) * to->width) / from->width) & ~1; + r->width = ((r->width * to->width) / from->width) & ~1; + r->top = ((r->top - from->top) * to->height) / from->height; + r->height = (r->height * to->height) / from->height; +} + +bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2) +{ + /* + * IF the left side of r1 is to the right of the right side of r2 OR + * the left side of r2 is to the right of the right side of r1 THEN + * they do not overlap. + */ + if (r1->left >= r2->left + r2->width || + r2->left >= r1->left + r1->width) + return false; + /* + * IF the top side of r1 is below the bottom of r2 OR + * the top side of r2 is below the bottom of r1 THEN + * they do not overlap. + */ + if (r1->top >= r2->top + r2->height || + r2->top >= r1->top + r1->height) + return false; + return true; +} +int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) +{ + unsigned w = r->width; + unsigned h = r->height; + + if (!(flags & V4L2_SEL_FLAG_LE)) { + w++; + h++; + if (w < 2) + w = 2; + if (h < 2) + h = 2; + } + if (!(flags & V4L2_SEL_FLAG_GE)) { + if (w > MAX_WIDTH) + w = MAX_WIDTH; + if (h > MAX_HEIGHT) + h = MAX_HEIGHT; + } + w = w & ~1; + h = h & ~1; + if (w < 2 || h < 2) + return -ERANGE; + if (w > MAX_WIDTH || h > MAX_HEIGHT) + return -ERANGE; + if (r->top < 0) + r->top = 0; + if (r->left < 0) + r->left = 0; + r->left &= ~1; + r->top &= ~1; + if (r->left + w > MAX_WIDTH) + r->left = MAX_WIDTH - w; + if (r->top + h > MAX_HEIGHT) + r->top = MAX_HEIGHT - h; + if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) == + (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) && + (r->width != w || r->height != h)) + return -ERANGE; + r->width = w; + r->height = h; + return 0; +} + +int vivid_enum_fmt_vid(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + + if (f->index >= ARRAY_SIZE(vivid_formats) - + (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS)) + return -EINVAL; + + fmt = &vivid_formats[f->index]; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + return 0; +} + +int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_enum_fmt_vid(file, priv, f); +} + +int vidioc_enum_fmt_vid(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return vivid_enum_fmt_vid(file, priv, f); +} + +int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + *id = dev->std_cap; + } else { + if (!vivid_is_svid_out(dev)) + return -ENODATA; + *id = dev->std_out; + } + return 0; +} + +int vidioc_g_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + *timings = dev->dv_timings_cap; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + *timings = dev->dv_timings_out; + } + return 0; +} + +int vidioc_enum_dv_timings(struct file *file, void *_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + } + return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap, + NULL, NULL); +} + +int vidioc_dv_timings_cap(struct file *file, void *_fh, + struct v4l2_dv_timings_cap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + } + *cap = vivid_dv_timings_cap; + return 0; +} + +int vidioc_g_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (vdev->vfl_dir == VFL_DIR_RX) { + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI) + return -EINVAL; + } else { + if (edid->pad >= dev->num_outputs) + return -EINVAL; + if (dev->output_type[edid->pad] != HDMI) + return -EINVAL; + } + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = dev->edid_blocks; + return 0; + } + if (dev->edid_blocks == 0) + return -ENODATA; + if (edid->start_block >= dev->edid_blocks) + return -EINVAL; + if (edid->start_block + edid->blocks > dev->edid_blocks) + edid->blocks = dev->edid_blocks - edid->start_block; + memcpy(edid->edid, dev->edid, edid->blocks * 128); + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h new file mode 100644 index 000000000000..9563c327fe56 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -0,0 +1,61 @@ +/* + * vivid-vid-common.h - common video support functions. + * + * Copyright 2014 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 _VIVID_VID_COMMON_H_ +#define _VIVID_VID_COMMON_H_ + +typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f); + +/* + * Conversion function that converts a single-planar format to a + * single-plane multiplanar format. + */ +void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt); +int fmt_sp2mp_func(struct file *file, void *priv, + struct v4l2_format *f, fmtfunc func); + +extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap; + +const struct vivid_fmt *get_format(struct vivid_dev *dev, u32 pixelformat); + +bool vivid_vid_can_loop(struct vivid_dev *dev); +void vivid_send_source_change(struct vivid_dev *dev, unsigned type); + +bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2); +void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size); +void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size); +void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size); +void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary); +bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2); +struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b); +void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from, + const struct v4l2_rect *to); +int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); + +int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); +int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); +int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap); +int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); + +#endif diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c new file mode 100644 index 000000000000..3078bd2fdc01 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -0,0 +1,1205 @@ +/* + * vivid-vid-out.c - video output support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-kthread-out.h" +#include "vivid-vid-out.h" + +static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], void *alloc_ctxs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned planes = dev->fmt_out->planes; + unsigned h = dev->fmt_out_rect.height; + unsigned size = dev->bytesperline_out[0] * h; + + if (dev->field_out == V4L2_FIELD_ALTERNATE) { + /* + * You cannot use write() with FIELD_ALTERNATE since the field + * information (TOP/BOTTOM) cannot be passed to the kernel. + */ + if (vb2_fileio_is_active(vq)) + return -EINVAL; + } + + if (dev->queue_setup_error) { + /* + * Error injection: test what happens if queue_setup() returns + * an error. + */ + dev->queue_setup_error = false; + return -EINVAL; + } + + if (fmt) { + const struct v4l2_pix_format_mplane *mp; + struct v4l2_format mp_fmt; + + if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { + fmt_sp2mp(fmt, &mp_fmt); + fmt = &mp_fmt; + } + mp = &fmt->fmt.pix_mp; + /* + * Check if the number of planes in the specified format match + * the number of planes in the current format. You can't mix that. + */ + if (mp->num_planes != planes) + return -EINVAL; + sizes[0] = mp->plane_fmt[0].sizeimage; + if (planes == 2) { + sizes[1] = mp->plane_fmt[1].sizeimage; + if (sizes[0] < dev->bytesperline_out[0] * h || + sizes[1] < dev->bytesperline_out[1] * h) + return -EINVAL; + } else if (sizes[0] < size) { + return -EINVAL; + } + } else { + if (planes == 2) { + sizes[0] = dev->bytesperline_out[0] * h; + sizes[1] = dev->bytesperline_out[1] * h; + } else { + sizes[0] = size; + } + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = planes; + + /* + * videobuf2-vmalloc allocator is context-less so no need to set + * alloc_ctxs array. + */ + + if (planes == 2) + dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, + *nbuffers, sizes[0], sizes[1]); + else + dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, + *nbuffers, sizes[0]); + return 0; +} + +static int vid_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size; + unsigned planes = dev->fmt_out->planes; + unsigned p; + + dprintk(dev, 1, "%s\n", __func__); + + if (WARN_ON(NULL == dev->fmt_out)) + return -EINVAL; + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + + if (dev->field_out != V4L2_FIELD_ALTERNATE) + vb->v4l2_buf.field = dev->field_out; + else if (vb->v4l2_buf.field != V4L2_FIELD_TOP && + vb->v4l2_buf.field != V4L2_FIELD_BOTTOM) + return -EINVAL; + + for (p = 0; p < planes; p++) { + size = dev->bytesperline_out[p] * dev->fmt_out_rect.height + + vb->v4l2_planes[p].data_offset; + + if (vb2_get_plane_payload(vb, p) < size) { + dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n", + __func__, p, vb2_get_plane_payload(vb, p), size); + return -EINVAL; + } + } + + return 0; +} + +static void vid_out_buf_queue(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vid_out_active); + spin_unlock(&dev->slock); +} + +static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + if (vb2_is_streaming(&dev->vb_vid_cap_q)) + dev->can_loop_video = vivid_vid_can_loop(dev); + + if (dev->kthread_vid_out) + return 0; + + dev->vid_out_seq_count = 0; + dprintk(dev, 1, "%s\n", __func__); + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vid_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming); + dev->can_loop_video = false; +} + +const struct vb2_ops vivid_vid_out_qops = { + .queue_setup = vid_out_queue_setup, + .buf_prepare = vid_out_buf_prepare, + .buf_queue = vid_out_buf_queue, + .start_streaming = vid_out_start_streaming, + .stop_streaming = vid_out_stop_streaming, + .wait_prepare = vivid_unlock, + .wait_finish = vivid_lock, +}; + +/* + * Called whenever the format has to be reset which can occur when + * changing outputs, standard, timings, etc. + */ +void vivid_update_format_out(struct vivid_dev *dev) +{ + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + unsigned size; + + switch (dev->output_type[dev->output]) { + case SVID: + default: + dev->field_out = dev->tv_field_out; + dev->sink_rect.width = 720; + if (dev->std_out & V4L2_STD_525_60) { + dev->sink_rect.height = 480; + dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 }; + dev->service_set_out = V4L2_SLICED_CAPTION_525; + } else { + dev->sink_rect.height = 576; + dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 }; + dev->service_set_out = V4L2_SLICED_WSS_625; + } + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + break; + case HDMI: + dev->sink_rect.width = bt->width; + dev->sink_rect.height = bt->height; + size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + dev->timeperframe_vid_out = (struct v4l2_fract) { + size / 100, (u32)bt->pixelclock / 100 + }; + if (bt->interlaced) + dev->field_out = V4L2_FIELD_ALTERNATE; + else + dev->field_out = V4L2_FIELD_NONE; + if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (bt->width == 720 && bt->height <= 576) + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + else + dev->colorspace_out = V4L2_COLORSPACE_REC709; + } else { + dev->colorspace_out = V4L2_COLORSPACE_SRGB; + } + break; + } + dev->compose_out = dev->sink_rect; + dev->compose_bounds_out = dev->sink_rect; + dev->crop_out = dev->compose_out; + if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) + dev->crop_out.height /= 2; + dev->fmt_out_rect = dev->crop_out; + dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; + if (dev->fmt_out->planes == 2) + dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; +} + +/* Map the field to something that is valid for the current output */ +static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field) +{ + if (vivid_is_svid_out(dev)) { + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_ALTERNATE: + return field; + case V4L2_FIELD_INTERLACED: + default: + return V4L2_FIELD_INTERLACED; + } + } + if (vivid_is_hdmi_out(dev)) + return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE : + V4L2_FIELD_NONE; + return V4L2_FIELD_NONE; +} + +static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_svid_out(dev)) + return (dev->std_out & V4L2_STD_525_60) ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + if (vivid_is_hdmi_out(dev) && + dev->sink_rect.width == 720 && dev->sink_rect.height <= 576) + return dev->sink_rect.height == 480 ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + return TPG_PIXEL_ASPECT_SQUARE; +} + +int vivid_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + unsigned p; + + mp->width = dev->fmt_out_rect.width; + mp->height = dev->fmt_out_rect.height; + mp->field = dev->field_out; + mp->pixelformat = dev->fmt_out->fourcc; + mp->colorspace = dev->colorspace_out; + mp->num_planes = dev->fmt_out->planes; + for (p = 0; p < mp->num_planes; p++) { + mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; + mp->plane_fmt[p].sizeimage = + mp->plane_fmt[p].bytesperline * mp->height; + } + return 0; +} + +int vivid_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; + const struct vivid_fmt *fmt; + unsigned bytesperline, max_bpl; + unsigned factor = 1; + unsigned w, h; + unsigned p; + + fmt = get_format(dev, mp->pixelformat); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", + mp->pixelformat); + mp->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = get_format(dev, mp->pixelformat); + } + + mp->field = vivid_field_out(dev, mp->field); + if (vivid_is_svid_out(dev)) { + w = 720; + h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576; + } else { + w = dev->sink_rect.width; + h = dev->sink_rect.height; + } + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) { + mp->width = w; + mp->height = h / factor; + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + + rect_set_min_size(&r, &vivid_min_rect); + rect_set_max_size(&r, &vivid_max_rect); + if (dev->has_scaler_out && !dev->has_crop_out) { + struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; + + rect_set_max_size(&r, &max_r); + } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { + rect_set_max_size(&r, &dev->sink_rect); + } else if (!dev->has_scaler_out && !dev->has_compose_out) { + rect_set_min_size(&r, &dev->sink_rect); + } + mp->width = r.width; + mp->height = r.height / factor; + } + + /* This driver supports custom bytesperline values */ + + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->depth) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; + mp->num_planes = fmt->planes; + for (p = 0; p < mp->num_planes; p++) { + if (pfmt[p].bytesperline > max_bpl) + pfmt[p].bytesperline = max_bpl; + if (pfmt[p].bytesperline < bytesperline) + pfmt[p].bytesperline = bytesperline; + pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; + memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); + } + if (vivid_is_svid_out(dev)) + mp->colorspace = V4L2_COLORSPACE_SMPTE170M; + else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) + mp->colorspace = V4L2_COLORSPACE_SRGB; + else if (bt->width == 720 && bt->height <= 576) + mp->colorspace = V4L2_COLORSPACE_SMPTE170M; + else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M && + mp->colorspace != V4L2_COLORSPACE_REC709 && + mp->colorspace != V4L2_COLORSPACE_SRGB) + mp->colorspace = V4L2_COLORSPACE_REC709; + memset(mp->reserved, 0, sizeof(mp->reserved)); + return 0; +} + +int vivid_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_out; + struct v4l2_rect *compose = &dev->compose_out; + struct vb2_queue *q = &dev->vb_vid_out_q; + int ret = vivid_try_fmt_vid_out(file, priv, f); + unsigned factor = 1; + + if (ret < 0) + return ret; + + if (vb2_is_busy(q) && + (vivid_is_svid_out(dev) || + mp->width != dev->fmt_out_rect.width || + mp->height != dev->fmt_out_rect.height || + mp->pixelformat != dev->fmt_out->fourcc || + mp->field != dev->field_out)) { + dprintk(dev, 1, "%s device busy\n", __func__); + return -EBUSY; + } + + /* + * Allow for changing the colorspace on the fly. Useful for testing + * purposes, and it is something that HDMI transmitters are able + * to do. + */ + if (vb2_is_busy(q)) + goto set_colorspace; + + dev->fmt_out = get_format(dev, mp->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + + if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + if (dev->has_scaler_out) { + if (dev->has_crop_out) + rect_map_inside(crop, &r); + else + *crop = r; + if (dev->has_compose_out && !dev->has_crop_out) { + struct v4l2_rect min_r = { + 0, 0, + r.width / MAX_ZOOM, + factor * r.height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + r.width * MAX_ZOOM, + factor * r.height * MAX_ZOOM + }; + + rect_set_min_size(compose, &min_r); + rect_set_max_size(compose, &max_r); + rect_map_inside(compose, &dev->compose_bounds_out); + } else if (dev->has_compose_out) { + struct v4l2_rect min_r = { + 0, 0, + crop->width / MAX_ZOOM, + factor * crop->height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + crop->width * MAX_ZOOM, + factor * crop->height * MAX_ZOOM + }; + + rect_set_min_size(compose, &min_r); + rect_set_max_size(compose, &max_r); + rect_map_inside(compose, &dev->compose_bounds_out); + } + } else if (dev->has_compose_out && !dev->has_crop_out) { + rect_set_size_to(crop, &r); + r.height *= factor; + rect_set_size_to(compose, &r); + rect_map_inside(compose, &dev->compose_bounds_out); + } else if (!dev->has_compose_out) { + rect_map_inside(crop, &r); + r.height /= factor; + rect_set_size_to(compose, &r); + } else { + r.height *= factor; + rect_set_max_size(compose, &r); + rect_map_inside(compose, &dev->compose_bounds_out); + crop->top *= factor; + crop->height *= factor; + rect_set_size_to(crop, compose); + rect_map_inside(crop, &r); + crop->top /= factor; + crop->height /= factor; + } + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + rect_set_size_to(crop, &r); + r.height /= factor; + rect_set_size_to(compose, &r); + } + + dev->fmt_out_rect.width = mp->width; + dev->fmt_out_rect.height = mp->height; + dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline; + if (mp->num_planes > 1) + dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline; + dev->field_out = mp->field; + if (vivid_is_svid_out(dev)) + dev->tv_field_out = mp->field; + +set_colorspace: + dev->colorspace_out = mp->colorspace; + if (dev->loop_video) { + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + } + return 0; +} + +int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_g_fmt_vid_out(file, priv, f); +} + +int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_try_fmt_vid_out(file, priv, f); +} + +int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_s_fmt_vid_out(file, priv, f); +} + +int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out); +} + +int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out); +} + +int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out); +} + +int vivid_vid_out_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->has_crop_out && !dev->has_compose_out) + return -ENOTTY; + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + sel->r.left = sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_out) + return -EINVAL; + sel->r = dev->crop_out; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + if (!dev->has_crop_out) + return -EINVAL; + sel->r = dev->fmt_out_rect; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + if (!dev->has_compose_out) + return -EINVAL; + sel->r = vivid_max_rect; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_out) + return -EINVAL; + sel->r = dev->compose_out; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (!dev->has_compose_out) + return -EINVAL; + sel->r = dev->sink_rect; + break; + default: + return -EINVAL; + } + return 0; +} + +int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_out; + struct v4l2_rect *compose = &dev->compose_out; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1; + int ret; + + if (!dev->has_crop_out && !dev->has_compose_out) + return -ENOTTY; + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_out) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + rect_set_min_size(&s->r, &vivid_min_rect); + rect_set_max_size(&s->r, &dev->fmt_out_rect); + if (dev->has_scaler_out) { + struct v4l2_rect max_rect = { + 0, 0, + dev->sink_rect.width * MAX_ZOOM, + (dev->sink_rect.height / factor) * MAX_ZOOM + }; + + rect_set_max_size(&s->r, &max_rect); + if (dev->has_compose_out) { + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + (s->r.height * factor) / MAX_ZOOM + }; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + (s->r.height * factor) * MAX_ZOOM + }; + + rect_set_min_size(compose, &min_rect); + rect_set_max_size(compose, &max_rect); + rect_map_inside(compose, &dev->compose_bounds_out); + } + } else if (dev->has_compose_out) { + s->r.top *= factor; + s->r.height *= factor; + rect_set_max_size(&s->r, &dev->sink_rect); + rect_set_size_to(compose, &s->r); + rect_map_inside(compose, &dev->compose_bounds_out); + s->r.top /= factor; + s->r.height /= factor; + } else { + rect_set_size_to(&s->r, &dev->sink_rect); + s->r.height /= factor; + } + rect_map_inside(&s->r, &dev->fmt_out_rect); + *crop = s->r; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_out) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + rect_set_min_size(&s->r, &vivid_min_rect); + rect_set_max_size(&s->r, &dev->sink_rect); + rect_map_inside(&s->r, &dev->compose_bounds_out); + s->r.top /= factor; + s->r.height /= factor; + if (dev->has_scaler_out) { + struct v4l2_rect fmt = dev->fmt_out_rect; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + s->r.height * MAX_ZOOM + }; + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + s->r.height / MAX_ZOOM + }; + + rect_set_min_size(&fmt, &min_rect); + if (!dev->has_crop_out) + rect_set_max_size(&fmt, &max_rect); + if (!rect_same_size(&dev->fmt_out_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + if (dev->has_crop_out) { + rect_set_min_size(crop, &min_rect); + rect_set_max_size(crop, &max_rect); + } + dev->fmt_out_rect = fmt; + } else if (dev->has_crop_out) { + struct v4l2_rect fmt = dev->fmt_out_rect; + + rect_set_min_size(&fmt, &s->r); + if (!rect_same_size(&dev->fmt_out_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + dev->fmt_out_rect = fmt; + rect_set_size_to(crop, &s->r); + rect_map_inside(crop, &dev->fmt_out_rect); + } else { + if (!rect_same_size(&s->r, &dev->fmt_out_rect) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + rect_set_size_to(&dev->fmt_out_rect, &s->r); + rect_set_size_to(crop, &s->r); + crop->height /= factor; + rect_map_inside(crop, &dev->fmt_out_rect); + } + s->r.top *= factor; + s->r.height *= factor; + if (dev->bitmap_out && (compose->width != s->r.width || + compose->height != s->r.height)) { + kfree(dev->bitmap_out); + dev->bitmap_out = NULL; + } + *compose = s->r; + break; + default: + return -EINVAL; + } + + return 0; +} + +int vivid_vid_out_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (vivid_get_pixel_aspect(dev)) { + case TPG_PIXEL_ASPECT_NTSC: + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + break; + case TPG_PIXEL_ASPECT_PAL: + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + break; + case TPG_PIXEL_ASPECT_SQUARE: + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + break; + } + return 0; +} + +int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + unsigned clipcount = win->clipcount; + + if (!dev->has_fb) + return -EINVAL; + win->w.top = dev->overlay_out_top; + win->w.left = dev->overlay_out_left; + win->w.width = compose->width; + win->w.height = compose->height; + win->clipcount = dev->clipcount_out; + win->field = V4L2_FIELD_ANY; + win->chromakey = dev->chromakey_out; + win->global_alpha = dev->global_alpha_out; + if (clipcount > dev->clipcount_out) + clipcount = dev->clipcount_out; + if (dev->bitmap_out == NULL) + win->bitmap = NULL; + else if (win->bitmap) { + if (copy_to_user(win->bitmap, dev->bitmap_out, + ((dev->compose_out.width + 7) / 8) * dev->compose_out.height)) + return -EFAULT; + } + if (clipcount && win->clips) { + if (copy_to_user(win->clips, dev->clips_out, + clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + int i, j; + + if (!dev->has_fb) + return -EINVAL; + win->w.left = clamp_t(int, win->w.left, + -dev->display_width, dev->display_width); + win->w.top = clamp_t(int, win->w.top, + -dev->display_height, dev->display_height); + win->w.width = compose->width; + win->w.height = compose->height; + /* + * It makes no sense for an OSD to overlay only top or bottom fields, + * so always set this to ANY. + */ + win->field = V4L2_FIELD_ANY; + if (win->clipcount && !win->clips) + win->clipcount = 0; + if (win->clipcount > MAX_CLIPS) + win->clipcount = MAX_CLIPS; + if (win->clipcount) { + if (copy_from_user(dev->try_clips_out, win->clips, + win->clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + for (i = 0; i < win->clipcount; i++) { + struct v4l2_rect *r = &dev->try_clips_out[i].c; + + r->top = clamp_t(s32, r->top, 0, dev->display_height - 1); + r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top); + r->left = clamp_t(u32, r->left, 0, dev->display_width - 1); + r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left); + } + /* + * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small + * number and it's typically a one-time deal. + */ + for (i = 0; i < win->clipcount - 1; i++) { + struct v4l2_rect *r1 = &dev->try_clips_out[i].c; + + for (j = i + 1; j < win->clipcount; j++) { + struct v4l2_rect *r2 = &dev->try_clips_out[j].c; + + if (rect_overlap(r1, r2)) + return -EINVAL; + } + } + if (copy_to_user(win->clips, dev->try_clips_out, + win->clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f); + unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; + unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]); + void *new_bitmap = NULL; + + if (ret) + return ret; + + if (win->bitmap) { + new_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + + if (new_bitmap == NULL) + return -ENOMEM; + if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { + kfree(new_bitmap); + return -EFAULT; + } + } + + dev->overlay_out_top = win->w.top; + dev->overlay_out_left = win->w.left; + kfree(dev->bitmap_out); + dev->bitmap_out = new_bitmap; + dev->clipcount_out = win->clipcount; + if (dev->clipcount_out) + memcpy(dev->clips_out, dev->try_clips_out, clips_size); + dev->chromakey_out = win->chromakey; + dev->global_alpha_out = win->global_alpha; + return ret; +} + +int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (i && !dev->fmt_out->can_do_overlay) { + dprintk(dev, 1, "unsupported output format for output overlay\n"); + return -EINVAL; + } + + dev->overlay_out_enabled = i; + return 0; +} + +int vivid_vid_out_g_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | + V4L2_FBUF_CAP_BITMAP_CLIPPING | + V4L2_FBUF_CAP_LIST_CLIPPING | + V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_SRC_CHROMAKEY | + V4L2_FBUF_CAP_GLOBAL_ALPHA | + V4L2_FBUF_CAP_LOCAL_ALPHA | + V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags; + a->base = (void *)dev->video_pbase; + a->fmt.width = dev->display_width; + a->fmt.height = dev->display_height; + if (dev->fb_defined.green.length == 5) + a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555; + else + a->fmt.pixelformat = V4L2_PIX_FMT_RGB565; + a->fmt.bytesperline = dev->display_byte_stride; + a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.priv = 0; + return 0; +} + +int vivid_vid_out_s_fbuf(struct file *file, void *fh, + const struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_SRC_CHROMAKEY; + const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA | + V4L2_FBUF_FLAG_LOCAL_ALPHA | + V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + + + if ((a->flags & chroma_flags) == chroma_flags) + return -EINVAL; + switch (a->flags & alpha_flags) { + case 0: + case V4L2_FBUF_FLAG_GLOBAL_ALPHA: + case V4L2_FBUF_FLAG_LOCAL_ALPHA: + case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA: + break; + default: + return -EINVAL; + } + dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags); + dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags); + return 0; +} + +static const struct v4l2_audioout vivid_audio_outputs[] = { + { 0, "Line-Out 1" }, + { 1, "Line-Out 2" }, +}; + +int vidioc_enum_output(struct file *file, void *priv, + struct v4l2_output *out) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (out->index >= dev->num_outputs) + return -EINVAL; + + out->type = V4L2_OUTPUT_TYPE_ANALOG; + switch (dev->output_type[out->index]) { + case SVID: + snprintf(out->name, sizeof(out->name), "S-Video %u", + dev->output_name_counter[out->index]); + out->std = V4L2_STD_ALL; + if (dev->has_audio_outputs) + out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1; + out->capabilities = V4L2_OUT_CAP_STD; + break; + case HDMI: + snprintf(out->name, sizeof(out->name), "HDMI %u", + dev->output_name_counter[out->index]); + out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; + break; + } + return 0; +} + +int vidioc_g_output(struct file *file, void *priv, unsigned *o) +{ + struct vivid_dev *dev = video_drvdata(file); + + *o = dev->output; + return 0; +} + +int vidioc_s_output(struct file *file, void *priv, unsigned o) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (o >= dev->num_outputs) + return -EINVAL; + + if (o == dev->output) + return 0; + + if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + + dev->output = o; + dev->tv_audio_output = 0; + if (dev->output_type[o] == SVID) + dev->vid_out_dev.tvnorms = V4L2_STD_ALL; + else + dev->vid_out_dev.tvnorms = 0; + + dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; + vivid_update_format_out(dev); + return 0; +} + +int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) + return -EINVAL; + *vout = vivid_audio_outputs[vout->index]; + return 0; +} + +int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + *vout = vivid_audio_outputs[dev->tv_audio_output]; + return 0; +} + +int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) + return -EINVAL; + dev->tv_audio_output = vout->index; + return 0; +} + +int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -ENODATA; + if (dev->std_out == id) + return 0; + if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->std_out = id; + vivid_update_format_out(dev); + return 0; +} + +int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + if (vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, + 0, NULL, NULL)) + return -EINVAL; + if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) + return 0; + dev->dv_timings_out = *timings; + vivid_update_format_out(dev); + return 0; +} + +int vivid_vid_out_g_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (vdev->vfl_dir == VFL_DIR_RX) { + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI) + return -EINVAL; + } else { + if (edid->pad >= dev->num_outputs) + return -EINVAL; + if (dev->output_type[edid->pad] != HDMI) + return -EINVAL; + } + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = dev->edid_blocks; + return 0; + } + if (dev->edid_blocks == 0) + return -ENODATA; + if (edid->start_block >= dev->edid_blocks) + return -EINVAL; + if (edid->start_block + edid->blocks > dev->edid_blocks) + edid->blocks = dev->edid_blocks - edid->start_block; + memcpy(edid->edid, dev->edid, edid->blocks * 128); + return 0; +} + +int vivid_vid_out_s_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI || edid->start_block) + return -EINVAL; + if (edid->blocks == 0) { + dev->edid_blocks = 0; + return 0; + } + if (edid->blocks > dev->edid_max_blocks) { + edid->blocks = dev->edid_max_blocks; + return -E2BIG; + } + dev->edid_blocks = edid->blocks; + memcpy(dev->edid, edid->edid, edid->blocks * 128); + return 0; +} + +int vivid_vid_out_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.output.timeperframe = dev->timeperframe_vid_out; + parm->parm.output.writebuffers = 1; +return 0; +} + +int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + case V4L2_EVENT_SOURCE_CHANGE: + if (fh->vdev->vfl_dir == VFL_DIR_RX) + return v4l2_src_change_event_subscribe(fh, sub); + break; + default: + break; + } + return -EINVAL; +} diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h new file mode 100644 index 000000000000..a237465432e7 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -0,0 +1,57 @@ +/* + * vivid-vid-out.h - video output support functions. + * + * Copyright 2014 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 _VIVID_VID_OUT_H_ +#define _VIVID_VID_OUT_H_ + +extern const struct vb2_ops vivid_vid_out_qops; + +void vivid_update_format_out(struct vivid_dev *dev); + +int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); +int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_out_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cap); +int vidioc_enum_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i); +int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); +int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out); +int vidioc_g_output(struct file *file, void *priv, unsigned *i); +int vidioc_s_output(struct file *file, void *priv, unsigned i); +int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout); +int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); +int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); +int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); +int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); + +#endif -- cgit v1.2.3 From 7bb70caa3bd59454285738b31f7b47e89fe62c1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 07:56:49 -0300 Subject: [media] vivid: add VBI capture and output code This adds support for VBI capture (raw and sliced) and VBI output (raw and sliced) to the vivid driver. In addition a VBI generator is added that generates simple VBI data in either sliced or raw format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vbi-cap.c | 356 +++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-vbi-cap.h | 40 +++ drivers/media/platform/vivid/vivid-vbi-gen.c | 248 +++++++++++++++++++ drivers/media/platform/vivid/vivid-vbi-gen.h | 33 +++ drivers/media/platform/vivid/vivid-vbi-out.c | 247 +++++++++++++++++++ drivers/media/platform/vivid/vivid-vbi-out.h | 34 +++ 6 files changed, 958 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-vbi-cap.c create mode 100644 drivers/media/platform/vivid/vivid-vbi-cap.h create mode 100644 drivers/media/platform/vivid/vivid-vbi-gen.c create mode 100644 drivers/media/platform/vivid/vivid-vbi-gen.h create mode 100644 drivers/media/platform/vivid/vivid-vbi-out.c create mode 100644 drivers/media/platform/vivid/vivid-vbi-out.h diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c new file mode 100644 index 000000000000..e239cfdc030d --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -0,0 +1,356 @@ +/* + * vivid-vbi-cap.c - vbi capture support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-gen.h" + +static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) +{ + struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; + bool is_60hz = dev->std_cap & V4L2_STD_525_60; + + vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); + + if (!is_60hz) { + if (dev->loop_video) { + if (dev->vbi_out_have_wss) { + vbi_gen->data[0].data[0] = dev->vbi_out_wss[0]; + vbi_gen->data[0].data[1] = dev->vbi_out_wss[1]; + } else { + vbi_gen->data[0].id = 0; + } + } else { + switch (tpg_g_video_aspect(&dev->tpg)) { + case TPG_VIDEO_ASPECT_14X9_CENTRE: + vbi_gen->data[0].data[0] = 0x01; + break; + case TPG_VIDEO_ASPECT_16X9_CENTRE: + vbi_gen->data[0].data[0] = 0x0b; + break; + case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: + vbi_gen->data[0].data[0] = 0x07; + break; + case TPG_VIDEO_ASPECT_4X3: + default: + vbi_gen->data[0].data[0] = 0x08; + break; + } + } + } else if (dev->loop_video && is_60hz) { + if (dev->vbi_out_have_cc[0]) { + vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; + vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; + } else { + vbi_gen->data[0].id = 0; + } + if (dev->vbi_out_have_cc[1]) { + vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; + vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; + } else { + vbi_gen->data[1].id = 0; + } + } +} + +static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) +{ + bool is_60hz = dev->std_cap & V4L2_STD_525_60; + + vbi->sampling_rate = 27000000; + vbi->offset = 24; + vbi->samples_per_line = 1440; + vbi->sample_format = V4L2_PIX_FMT_GREY; + vbi->start[0] = is_60hz ? 10 : 6; + vbi->start[1] = is_60hz ? 273 : 318; + vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; + vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; + vbi->reserved[0] = 0; + vbi->reserved[1] = 0; +} + +void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct v4l2_vbi_format vbi; + u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); + + vivid_g_fmt_vbi_cap(dev, &vbi); + buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.v4l2_buf.sequence /= 2; + + vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence); + + memset(vbuf, 0x10, vb2_plane_size(&buf->vb, 0)); + + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) + vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; +} + + +void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct v4l2_sliced_vbi_data *vbuf = vb2_plane_vaddr(&buf->vb, 0); + + buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.v4l2_buf.sequence /= 2; + + vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence); + + memset(vbuf, 0, vb2_plane_size(&buf->vb, 0)); + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + vbuf[0] = dev->vbi_gen.data[0]; + vbuf[1] = dev->vbi_gen.data[1]; + } + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; +} + +static int vbi_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], void *alloc_ctxs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + bool is_60hz = dev->std_cap & V4L2_STD_525_60; + unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + + sizes[0] = size; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int vbi_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + bool is_60hz = dev->std_cap & V4L2_STD_525_60; + unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void vbi_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vbi_cap_active); + spin_unlock(&dev->slock); +} + +static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->vbi_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vbi_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); +} + +const struct vb2_ops vivid_vbi_cap_qops = { + .queue_setup = vbi_cap_queue_setup, + .buf_prepare = vbi_cap_buf_prepare, + .buf_queue = vbi_cap_buf_queue, + .start_streaming = vbi_cap_start_streaming, + .stop_streaming = vbi_cap_stop_streaming, + .wait_prepare = vivid_unlock, + .wait_finish = vivid_lock, +}; + +int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_vbi_format *vbi = &f->fmt.vbi; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) + return -EINVAL; + + vivid_g_fmt_vbi_cap(dev, vbi); + return 0; +} + +int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + int ret = vidioc_g_fmt_vbi_cap(file, priv, f); + + if (ret) + return ret; + if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->stream_sliced_vbi_cap = false; + dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE; + return 0; +} + +void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) +{ + vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbi->service_set = service_set; + memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); + memset(vbi->reserved, 0, sizeof(vbi->reserved)); + + if (vbi->service_set == 0) + return; + + if (vbi->service_set & V4L2_SLICED_CAPTION_525) { + vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } + if (vbi->service_set & V4L2_SLICED_WSS_625) + vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; +} + +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) + return -EINVAL; + + vivid_fill_service_lines(vbi, dev->service_set_cap); + return 0; +} + +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + bool is_60hz = dev->std_cap & V4L2_STD_525_60; + u32 service_set = vbi->service_set; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) + return -EINVAL; + + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + vivid_fill_service_lines(vbi, service_set); + return 0; +} + +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); + + if (ret) + return ret; + if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->service_set_cap = vbi->service_set; + dev->stream_sliced_vbi_cap = true; + dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + return 0; +} + +int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + bool is_60hz; + + if (vdev->vfl_dir == VFL_DIR_RX) { + is_60hz = dev->std_cap & V4L2_STD_525_60; + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || + cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + } else { + is_60hz = dev->std_out & V4L2_STD_525_60; + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || + cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + } + + cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + if (is_60hz) { + cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h new file mode 100644 index 000000000000..2d8ea0bac743 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-cap.h @@ -0,0 +1,40 @@ +/* + * vivid-vbi-cap.h - vbi capture support functions. + * + * Copyright 2014 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 _VIVID_VBI_CAP_H_ +#define _VIVID_VBI_CAP_H_ + +void vivid_fill_time_of_day_packet(u8 *packet); +void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); +void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap); + +void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set); + +extern const struct vb2_ops vivid_vbi_cap_qops; + +#endif diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c new file mode 100644 index 000000000000..22f4bcc6a6c0 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -0,0 +1,248 @@ +/* + * vivid-vbi-gen.c - vbi generator support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include + +#include "vivid-vbi-gen.h" + +static void wss_insert(u8 *wss, u32 val, unsigned size) +{ + while (size--) + *wss++ = (val & (1 << size)) ? 0xc0 : 0x10; +} + +static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 5000000; /* WSS has a 5 MHz transmission rate */ + u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 }; + const unsigned zero = 0x07; + const unsigned one = 0x38; + unsigned bit = 0; + u16 wss_data; + int i; + + wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29; + wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24; + + wss_data = (data->data[1] << 8) | data->data[0]; + for (i = 0; i <= 13; i++, bit += 6) + wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6); + + for (i = 0, bit = 0; bit < sizeof(wss); bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + + while (i < n) + buf[i++] = wss[bit]; + } +} + +static void cc_insert(u8 *cc, u8 ch) +{ + unsigned tot = 0; + unsigned i; + + for (i = 0; i < 7; i++) { + cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0; + tot += cc[2 * i]; + } + cc[14] = cc[15] = !(tot & 1); +} + +#define CC_PREAMBLE_BITS (14 + 4 + 2) + +static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 1000000; /* CC has a 1 MHz transmission rate */ + + u8 cc[CC_PREAMBLE_BITS + 2 * 16] = { + /* Clock run-in: 7 cycles */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + /* 2 cycles of 0 */ + 0, 0, 0, 0, + /* Start bit of 1 (each bit is two cycles) */ + 1, 1 + }; + unsigned bit, i; + + cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]); + cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]); + + for (i = 0, bit = 0; bit < sizeof(cc); bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + + while (i < n) + buf[i++] = cc[bit] ? 0xc0 : 0x10; + } +} + +void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, + const struct v4l2_vbi_format *vbi_fmt, u8 *buf) +{ + unsigned idx; + + for (idx = 0; idx < 2; idx++) { + const struct v4l2_sliced_vbi_data *data = vbi->data + idx; + unsigned start_2nd_field; + unsigned line = data->line; + u8 *linebuf = buf; + + start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313; + if (data->field) + line += start_2nd_field; + line -= vbi_fmt->start[data->field]; + + if (vbi_fmt->flags & V4L2_VBI_INTERLACED) + linebuf += (line * 2 + data->field) * + vbi_fmt->samples_per_line; + else + linebuf += (line + data->field * vbi_fmt->count[0]) * + vbi_fmt->samples_per_line; + if (data->id == V4L2_SLICED_CAPTION_525) + vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate); + else if (data->id == V4L2_SLICED_WSS_625) + vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate); + } +} + +static const u8 vivid_cc_sequence1[30] = { + 0x14, 0x20, /* Resume Caption Loading */ + 'H', 'e', + 'l', 'l', + 'o', ' ', + 'w', 'o', + 'r', 'l', + 'd', '!', + 0x14, 0x2f, /* End of Caption */ +}; + +static const u8 vivid_cc_sequence2[30] = { + 0x14, 0x20, /* Resume Caption Loading */ + 'C', 'l', + 'o', 's', + 'e', 'd', + ' ', 'c', + 'a', 'p', + 't', 'i', + 'o', 'n', + 's', ' ', + 't', 'e', + 's', 't', + 0x14, 0x2f, /* End of Caption */ +}; + +static u8 calc_parity(u8 val) +{ + unsigned i; + unsigned tot = 0; + + for (i = 0; i < 7; i++) + tot += (val & (1 << i)) ? 1 : 0; + return val | ((tot & 1) ? 0 : 0x80); +} + +static void vivid_vbi_gen_set_time_of_day(u8 *packet) +{ + struct tm tm; + u8 checksum, i; + + time_to_tm(get_seconds(), 0, &tm); + packet[0] = calc_parity(0x07); + packet[1] = calc_parity(0x01); + packet[2] = calc_parity(0x40 | tm.tm_min); + packet[3] = calc_parity(0x40 | tm.tm_hour); + packet[4] = calc_parity(0x40 | tm.tm_mday); + if (tm.tm_mday == 1 && tm.tm_mon == 2 && + sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60) + packet[4] = calc_parity(0x60 | tm.tm_mday); + packet[5] = calc_parity(0x40 | (1 + tm.tm_mon)); + packet[6] = calc_parity(0x40 | (1 + tm.tm_wday)); + packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f)); + packet[8] = calc_parity(0x0f); + for (checksum = i = 0; i <= 8; i++) + checksum += packet[i] & 0x7f; + packet[9] = calc_parity(0x100 - checksum); + checksum = 0; + packet[10] = calc_parity(0x07); + packet[11] = calc_parity(0x04); + if (sys_tz.tz_minuteswest >= 0) + packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f)); + else + packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f)); + packet[13] = calc_parity(0); + packet[14] = calc_parity(0x0f); + for (checksum = 0, i = 10; i <= 14; i++) + checksum += packet[i] & 0x7f; + packet[15] = calc_parity(0x100 - checksum); +} + +void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, + bool is_60hz, unsigned seqnr) +{ + struct v4l2_sliced_vbi_data *data0 = vbi->data; + struct v4l2_sliced_vbi_data *data1 = vbi->data + 1; + unsigned frame = seqnr % 60; + + memset(vbi->data, 0, sizeof(vbi->data)); + + if (!is_60hz) { + data0->id = V4L2_SLICED_WSS_625; + data0->line = 23; + /* 4x3 video aspect ratio */ + data0->data[0] = 0x08; + return; + } + + data0->id = V4L2_SLICED_CAPTION_525; + data0->line = 21; + data1->id = V4L2_SLICED_CAPTION_525; + data1->field = 1; + data1->line = 21; + + if (frame < 15) { + data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]); + data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]); + } else if (frame >= 30 && frame < 45) { + frame -= 30; + data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]); + data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]); + } else { + data0->data[0] = calc_parity(0); + data0->data[1] = calc_parity(0); + } + + frame = seqnr % (30 * 60); + switch (frame) { + case 0: + vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet); + /* fall through */ + case 1 ... 7: + data1->data[0] = vbi->time_of_day_packet[frame * 2]; + data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1]; + break; + default: + data1->data[0] = calc_parity(0); + data1->data[1] = calc_parity(0); + break; + } +} diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h new file mode 100644 index 000000000000..401dd47c0f1d --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-gen.h @@ -0,0 +1,33 @@ +/* + * vivid-vbi-gen.h - vbi generator support functions. + * + * Copyright 2014 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 _VIVID_VBI_GEN_H_ +#define _VIVID_VBI_GEN_H_ + +struct vivid_vbi_gen_data { + struct v4l2_sliced_vbi_data data[2]; + u8 time_of_day_packet[16]; +}; + +void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, + bool is_60hz, unsigned seqnr); +void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, + const struct v4l2_vbi_format *vbi_fmt, u8 *buf); + +#endif diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c new file mode 100644 index 000000000000..039316d835b4 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -0,0 +1,247 @@ +/* + * vivid-vbi-out.c - vbi output support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-out.h" +#include "vivid-vbi-out.h" +#include "vivid-vbi-cap.h" + +static int vbi_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], void *alloc_ctxs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + bool is_60hz = dev->std_out & V4L2_STD_525_60; + unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + + sizes[0] = size; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int vbi_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + bool is_60hz = dev->std_out & V4L2_STD_525_60; + unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void vbi_out_buf_queue(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vbi_out_active); + spin_unlock(&dev->slock); +} + +static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->vbi_out_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vbi_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming); + dev->vbi_out_have_wss = false; + dev->vbi_out_have_cc[0] = false; + dev->vbi_out_have_cc[1] = false; +} + +const struct vb2_ops vivid_vbi_out_qops = { + .queue_setup = vbi_out_queue_setup, + .buf_prepare = vbi_out_buf_prepare, + .buf_queue = vbi_out_buf_queue, + .start_streaming = vbi_out_start_streaming, + .stop_streaming = vbi_out_stop_streaming, + .wait_prepare = vivid_unlock, + .wait_finish = vivid_lock, +}; + +int vidioc_g_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_vbi_format *vbi = &f->fmt.vbi; + bool is_60hz = dev->std_out & V4L2_STD_525_60; + + if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out) + return -EINVAL; + + vbi->sampling_rate = 25000000; + vbi->offset = 24; + vbi->samples_per_line = 1440; + vbi->sample_format = V4L2_PIX_FMT_GREY; + vbi->start[0] = is_60hz ? 10 : 6; + vbi->start[1] = is_60hz ? 273 : 318; + vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; + vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; + vbi->reserved[0] = 0; + vbi->reserved[1] = 0; + return 0; +} + +int vidioc_s_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + int ret = vidioc_g_fmt_vbi_out(file, priv, f); + + if (ret) + return ret; + if (vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->stream_sliced_vbi_out = false; + dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT; + return 0; +} + +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) + return -EINVAL; + + vivid_fill_service_lines(vbi, dev->service_set_out); + return 0; +} + +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + bool is_60hz = dev->std_out & V4L2_STD_525_60; + u32 service_set = vbi->service_set; + + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) + return -EINVAL; + + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + vivid_fill_service_lines(vbi, service_set); + return 0; +} + +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); + + if (ret) + return ret; + if (vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->service_set_out = vbi->service_set; + dev->stream_sliced_vbi_out = true; + dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + return 0; +} + +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct v4l2_sliced_vbi_data *vbi = vb2_plane_vaddr(&buf->vb, 0); + unsigned elems = vb2_get_plane_payload(&buf->vb, 0) / sizeof(*vbi); + + dev->vbi_out_have_cc[0] = false; + dev->vbi_out_have_cc[1] = false; + dev->vbi_out_have_wss = false; + while (elems--) { + switch (vbi->id) { + case V4L2_SLICED_CAPTION_525: + if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) { + dev->vbi_out_have_cc[!!vbi->field] = true; + dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0]; + dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1]; + } + break; + case V4L2_SLICED_WSS_625: + if ((dev->std_out & V4L2_STD_625_50) && + vbi->field == 0 && vbi->line == 23) { + dev->vbi_out_have_wss = true; + dev->vbi_out_wss[0] = vbi->data[0]; + dev->vbi_out_wss[1] = vbi->data[1]; + } + break; + } + vbi++; + } +} diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h new file mode 100644 index 000000000000..6555ba9d2860 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-vbi-out.h @@ -0,0 +1,34 @@ +/* + * vivid-vbi-out.h - vbi output support functions. + * + * Copyright 2014 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 _VIVID_VBI_OUT_H_ +#define _VIVID_VBI_OUT_H_ + +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_g_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); + +extern const struct vb2_ops vivid_vbi_out_qops; + +#endif -- cgit v1.2.3 From 3f682ffcf957b556a7868decd5593d765ed3455d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:00:20 -0300 Subject: [media] vivid: add the kthread code that controls the video rate Add the kthread handlers for video/vbi capture and video/vbi output. These carefully control the rate at which frames are generated (video capture) and accepted (video output). While the short-term jitter is around the order of a jiffie, in the long term the rate matches the configured framerate exactly. The capture thread handler also takes care of the video looping and of capture and overlay support. This is probably the most complex part of this driver due to the many combinations of crop, compose and scaling on the input and output, and the blending that has to be done if overlay support is enabled as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-kthread-cap.c | 885 +++++++++++++++++++++++ drivers/media/platform/vivid/vivid-kthread-cap.h | 26 + drivers/media/platform/vivid/vivid-kthread-out.c | 304 ++++++++ drivers/media/platform/vivid/vivid-kthread-out.h | 26 + 4 files changed, 1241 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-kthread-cap.c create mode 100644 drivers/media/platform/vivid/vivid-kthread-cap.h create mode 100644 drivers/media/platform/vivid/vivid-kthread-out.c create mode 100644 drivers/media/platform/vivid/vivid-kthread-out.h diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c new file mode 100644 index 000000000000..33ab1dfe81c7 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -0,0 +1,885 @@ +/* + * vivid-kthread-cap.h - video/vbi capture thread support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" + +static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return dev->std_cap; + return 0; +} + +static void copy_pix(struct vivid_dev *dev, int win_y, int win_x, + u16 *cap, const u16 *osd) +{ + u16 out; + int left = dev->overlay_out_left; + int top = dev->overlay_out_top; + int fb_x = win_x + left; + int fb_y = win_y + top; + int i; + + out = *cap; + *cap = *osd; + if (dev->bitmap_out) { + const u8 *p = dev->bitmap_out; + unsigned stride = (dev->compose_out.width + 7) / 8; + + win_x -= dev->compose_out.left; + win_y -= dev->compose_out.top; + if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) + return; + } + + for (i = 0; i < dev->clipcount_out; i++) { + struct v4l2_rect *r = &dev->clips_out[i].c; + + if (fb_y >= r->top && fb_y < r->top + r->height && + fb_x >= r->left && fb_x < r->left + r->width) + return; + } + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) && + *osd != dev->chromakey_out) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && + out == dev->chromakey_out) + return; + if (dev->fmt_cap->alpha_mask) { + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) && + dev->global_alpha_out) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) && + *cap & dev->fmt_cap->alpha_mask) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) && + !(*cap & dev->fmt_cap->alpha_mask)) + return; + } + *cap = out; +} + +static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset, + u8 *vcapbuf, const u8 *vosdbuf, + unsigned width, unsigned pixsize) +{ + unsigned x; + + for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) { + copy_pix(dev, y_offset, x_offset + x, + (u16 *)vcapbuf, (const u16 *)vosdbuf); + } +} + +static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize) +{ + /* Coarse scaling with Bresenham */ + unsigned int_part; + unsigned fract_part; + unsigned src_x = 0; + unsigned error = 0; + unsigned x; + + /* + * We always combine two pixels to prevent color bleed in the packed + * yuv case. + */ + srcw /= 2; + dstw /= 2; + int_part = srcw / dstw; + fract_part = srcw % dstw; + for (x = 0; x < dstw; x++, dst += twopixsize) { + memcpy(dst, src + src_x * twopixsize, twopixsize); + src_x += int_part; + error += fract_part; + if (error >= dstw) { + error -= dstw; + src_x++; + } + } +} + +/* + * Precalculate the rectangles needed to perform video looping: + * + * The nominal pipeline is that the video output buffer is cropped by + * crop_out, scaled to compose_out, overlaid with the output overlay, + * cropped on the capture side by crop_cap and scaled again to the video + * capture buffer using compose_cap. + * + * To keep things efficient we calculate the intersection of compose_out + * and crop_cap (since that's the only part of the video that will + * actually end up in the capture buffer), determine which part of the + * video output buffer that is and which part of the video capture buffer + * so we can scale the video straight from the output buffer to the capture + * buffer without any intermediate steps. + * + * If we need to deal with an output overlay, then there is no choice and + * that intermediate step still has to be taken. For the output overlay + * support we calculate the intersection of the framebuffer and the overlay + * window (which may be partially or wholly outside of the framebuffer + * itself) and the intersection of that with loop_vid_copy (i.e. the part of + * the actual looped video that will be overlaid). The result is calculated + * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates + * (loop_vid_overlay). Finally calculate the part of the capture buffer that + * will receive that overlaid video. + */ +static void vivid_precalc_copy_rects(struct vivid_dev *dev) +{ + /* Framebuffer rectangle */ + struct v4l2_rect r_fb = { + 0, 0, dev->display_width, dev->display_height + }; + /* Overlay window rectangle in framebuffer coordinates */ + struct v4l2_rect r_overlay = { + dev->overlay_out_left, dev->overlay_out_top, + dev->compose_out.width, dev->compose_out.height + }; + + dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out); + + dev->loop_vid_out = dev->loop_vid_copy; + rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); + dev->loop_vid_out.left += dev->crop_out.left; + dev->loop_vid_out.top += dev->crop_out.top; + + dev->loop_vid_cap = dev->loop_vid_copy; + rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); + + dprintk(dev, 1, + "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", + dev->loop_vid_copy.width, dev->loop_vid_copy.height, + dev->loop_vid_copy.left, dev->loop_vid_copy.top, + dev->loop_vid_out.width, dev->loop_vid_out.height, + dev->loop_vid_out.left, dev->loop_vid_out.top, + dev->loop_vid_cap.width, dev->loop_vid_cap.height, + dev->loop_vid_cap.left, dev->loop_vid_cap.top); + + r_overlay = rect_intersect(&r_fb, &r_overlay); + + /* shift r_overlay to the same origin as compose_out */ + r_overlay.left += dev->compose_out.left - dev->overlay_out_left; + r_overlay.top += dev->compose_out.top - dev->overlay_out_top; + + dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy); + dev->loop_fb_copy = dev->loop_vid_overlay; + + /* shift dev->loop_fb_copy back again to the fb origin */ + dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left; + dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; + + dev->loop_vid_overlay_cap = dev->loop_vid_overlay; + rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); + + dprintk(dev, 1, + "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", + dev->loop_fb_copy.width, dev->loop_fb_copy.height, + dev->loop_fb_copy.left, dev->loop_fb_copy.top, + dev->loop_vid_overlay.width, dev->loop_vid_overlay.height, + dev->loop_vid_overlay.left, dev->loop_vid_overlay.top, + dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height, + dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); +} + +static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, + struct vivid_buffer *vid_cap_buf) +{ + bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index]; + struct tpg_data *tpg = &dev->tpg; + struct vivid_buffer *vid_out_buf = NULL; + unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2; + unsigned img_width = dev->compose_cap.width; + unsigned img_height = dev->compose_cap.height; + unsigned stride_cap = tpg->bytesperline[p]; + unsigned stride_out = dev->bytesperline_out[p]; + unsigned stride_osd = dev->display_byte_stride; + unsigned hmax = (img_height * tpg->perc_fill) / 100; + u8 *voutbuf; + u8 *vosdbuf = NULL; + unsigned y; + bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags; + /* Coarse scaling with Bresenham */ + unsigned vid_out_int_part; + unsigned vid_out_fract_part; + unsigned vid_out_y = 0; + unsigned vid_out_error = 0; + unsigned vid_overlay_int_part = 0; + unsigned vid_overlay_fract_part = 0; + unsigned vid_overlay_y = 0; + unsigned vid_overlay_error = 0; + unsigned vid_cap_right; + bool quick; + + vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height; + vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height; + + if (!list_empty(&dev->vid_out_active)) + vid_out_buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + if (vid_out_buf == NULL) + return -ENODATA; + + vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field; + + voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) + + vid_out_buf->vb.v4l2_planes[p].data_offset; + voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out; + vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap; + + if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { + /* + * If there is nothing to copy, then just fill the capture window + * with black. + */ + for (y = 0; y < hmax; y++, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + return 0; + } + + if (dev->overlay_out_enabled && + dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { + vosdbuf = dev->video_vbase; + vosdbuf += dev->loop_fb_copy.left * pixsize + + dev->loop_fb_copy.top * stride_osd; + vid_overlay_int_part = dev->loop_vid_overlay.height / + dev->loop_vid_overlay_cap.height; + vid_overlay_fract_part = dev->loop_vid_overlay.height % + dev->loop_vid_overlay_cap.height; + } + + vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width; + /* quick is true if no video scaling is needed */ + quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; + + dev->cur_scaled_line = dev->loop_vid_out.height; + for (y = 0; y < hmax; y++, vcapbuf += stride_cap) { + /* osdline is true if this line requires overlay blending */ + bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && + y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; + + /* + * If this line of the capture buffer doesn't get any video, then + * just fill with black. + */ + if (y < dev->loop_vid_cap.top || + y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { + memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + continue; + } + + /* fill the left border with black */ + if (dev->loop_vid_cap.left) + memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize); + + /* fill the right border with black */ + if (vid_cap_right < img_width) + memcpy(vcapbuf + vid_cap_right * pixsize, + tpg->black_line[p], (img_width - vid_cap_right) * pixsize); + + if (quick && !osdline) { + memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, + voutbuf + vid_out_y * stride_out, + dev->loop_vid_cap.width * pixsize); + goto update_vid_out_y; + } + if (dev->cur_scaled_line == vid_out_y) { + memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, + dev->scaled_line, + dev->loop_vid_cap.width * pixsize); + goto update_vid_out_y; + } + if (!osdline) { + scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, + dev->loop_vid_out.width, dev->loop_vid_cap.width, + tpg_g_twopixelsize(tpg, p)); + } else { + /* + * Offset in bytes within loop_vid_copy to the start of the + * loop_vid_overlay rectangle. + */ + unsigned offset = + (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize; + u8 *osd = vosdbuf + vid_overlay_y * stride_osd; + + scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, + dev->loop_vid_out.width, dev->loop_vid_copy.width, + tpg_g_twopixelsize(tpg, p)); + if (blend) + blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, + dev->loop_vid_overlay.left, + dev->blended_line + offset, osd, + dev->loop_vid_overlay.width, pixsize); + else + memcpy(dev->blended_line + offset, + osd, dev->loop_vid_overlay.width * pixsize); + scale_line(dev->blended_line, dev->scaled_line, + dev->loop_vid_copy.width, dev->loop_vid_cap.width, + tpg_g_twopixelsize(tpg, p)); + } + dev->cur_scaled_line = vid_out_y; + memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, + dev->scaled_line, + dev->loop_vid_cap.width * pixsize); + +update_vid_out_y: + if (osdline) { + vid_overlay_y += vid_overlay_int_part; + vid_overlay_error += vid_overlay_fract_part; + if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) { + vid_overlay_error -= dev->loop_vid_overlay_cap.height; + vid_overlay_y++; + } + } + vid_out_y += vid_out_int_part; + vid_out_error += vid_out_fract_part; + if (vid_out_error >= dev->loop_vid_cap.height) { + vid_out_error -= dev->loop_vid_cap.height; + vid_out_y++; + } + } + + if (!blank) + return 0; + for (; y < img_height; y++, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize); + return 0; +} + +static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; + unsigned line_height = 16 / factor; + bool is_tv = vivid_is_sdtv_cap(dev); + bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60); + unsigned p; + int line = 1; + u8 *basep[TPG_MAX_PLANES][2]; + unsigned ms; + char str[100]; + s32 gain; + bool is_loop = false; + + if (dev->loop_video && dev->can_loop_video && + ((vivid_is_svid_cap(dev) && !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) || + (vivid_is_hdmi_cap(dev) && !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)))) + is_loop = true; + + buf->vb.v4l2_buf.sequence = dev->vid_cap_seq_count; + /* + * Take the timestamp now if the timestamp source is set to + * "Start of Exposure". + */ + if (dev->tstamp_src_is_soe) + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + if (dev->field_cap == V4L2_FIELD_ALTERNATE) { + /* + * 60 Hz standards start with the bottom field, 50 Hz standards + * with the top field. So if the 0-based seq_count is even, + * then the field is TOP for 50 Hz and BOTTOM for 60 Hz + * standards. + */ + buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + /* + * The sequence counter counts frames, not fields. So divide + * by two. + */ + buf->vb.v4l2_buf.sequence /= 2; + } else { + buf->vb.v4l2_buf.field = dev->field_cap; + } + tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field); + tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]); + + vivid_precalc_copy_rects(dev); + + for (p = 0; p < tpg_g_planes(&dev->tpg); p++) { + void *vbuf = vb2_plane_vaddr(&buf->vb, p); + + /* + * The first plane of a multiplanar format has a non-zero + * data_offset. This helps testing whether the application + * correctly supports non-zero data offsets. + */ + if (dev->fmt_cap->data_offset[p]) { + memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, + dev->fmt_cap->data_offset[p]); + vbuf += dev->fmt_cap->data_offset[p]; + } + tpg_calc_text_basep(&dev->tpg, basep, p, vbuf); + if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) + tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf); + } + dev->must_blank[buf->vb.v4l2_buf.index] = false; + + /* Updates stream time, only update at the start of a new frame. */ + if (dev->field_cap != V4L2_FIELD_ALTERNATE || (buf->vb.v4l2_buf.sequence & 1) == 0) + dev->ms_vid_cap = jiffies_to_msecs(jiffies - dev->jiffies_vid_cap); + + ms = dev->ms_vid_cap; + if (dev->osd_mode <= 1) { + snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s", + (ms / (60 * 60 * 1000)) % 24, + (ms / (60 * 1000)) % 60, + (ms / 1000) % 60, + ms % 1000, + buf->vb.v4l2_buf.sequence, + (dev->field_cap == V4L2_FIELD_ALTERNATE) ? + (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ? + " top" : " bottom") : ""); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + } + if (dev->osd_mode == 0) { + snprintf(str, sizeof(str), " %dx%d, input %d ", + dev->src_rect.width, dev->src_rect.height, dev->input); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + + gain = v4l2_ctrl_g_ctrl(dev->gain); + mutex_lock(dev->ctrl_hdl_user_vid.lock); + snprintf(str, sizeof(str), + " brightness %3d, contrast %3d, saturation %3d, hue %d ", + dev->brightness->cur.val, + dev->contrast->cur.val, + dev->saturation->cur.val, + dev->hue->cur.val); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), + " autogain %d, gain %3d, alpha 0x%02x ", + dev->autogain->cur.val, gain, dev->alpha->cur.val); + mutex_unlock(dev->ctrl_hdl_user_vid.lock); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + mutex_lock(dev->ctrl_hdl_user_aud.lock); + snprintf(str, sizeof(str), + " volume %3d, mute %d ", + dev->volume->cur.val, dev->mute->cur.val); + mutex_unlock(dev->ctrl_hdl_user_aud.lock); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + mutex_lock(dev->ctrl_hdl_user_gen.lock); + snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", + dev->int32->cur.val, + *dev->int64->p_cur.p_s64, + dev->bitmask->cur.val); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", + dev->boolean->cur.val, + dev->menu->qmenu[dev->menu->cur.val], + dev->string->p_cur.p_char); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), " integer_menu %lld, value %d ", + dev->int_menu->qmenu_int[dev->int_menu->cur.val], + dev->int_menu->cur.val); + mutex_unlock(dev->ctrl_hdl_user_gen.lock); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + if (dev->button_pressed) { + dev->button_pressed--; + snprintf(str, sizeof(str), " button pressed!"); + tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + } + } + + /* + * If "End of Frame" is specified at the timestamp source, then take + * the timestamp now. + */ + if (!dev->tstamp_src_is_soe) + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; +} + +/* + * Return true if this pixel coordinate is a valid video pixel. + */ +static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x) +{ + int i; + + if (dev->bitmap_cap) { + /* + * Only if the corresponding bit in the bitmap is set can + * the video pixel be shown. Coordinates are relative to + * the overlay window set by VIDIOC_S_FMT. + */ + const u8 *p = dev->bitmap_cap; + unsigned stride = (dev->compose_cap.width + 7) / 8; + + if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) + return false; + } + + for (i = 0; i < dev->clipcount_cap; i++) { + /* + * Only if the framebuffer coordinate is not in any of the + * clip rectangles will be video pixel be shown. + */ + struct v4l2_rect *r = &dev->clips_cap[i].c; + + if (fb_y >= r->top && fb_y < r->top + r->height && + fb_x >= r->left && fb_x < r->left + r->width) + return false; + } + return true; +} + +/* + * Draw the image into the overlay buffer. + * Note that the combination of overlay and multiplanar is not supported. + */ +static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct tpg_data *tpg = &dev->tpg; + unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2; + void *vbase = dev->fb_vbase_cap; + void *vbuf = vb2_plane_vaddr(&buf->vb, 0); + unsigned img_width = dev->compose_cap.width; + unsigned img_height = dev->compose_cap.height; + unsigned stride = tpg->bytesperline[0]; + /* if quick is true, then valid_pix() doesn't have to be called */ + bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; + int x, y, w, out_x = 0; + + if ((dev->overlay_cap_field == V4L2_FIELD_TOP || + dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && + dev->overlay_cap_field != buf->vb.v4l2_buf.field) + return; + + vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride; + x = dev->overlay_cap_left; + w = img_width; + if (x < 0) { + out_x = -x; + w = w - out_x; + x = 0; + } else { + w = dev->fb_cap.fmt.width - x; + if (w > img_width) + w = img_width; + } + if (w <= 0) + return; + if (dev->overlay_cap_top >= 0) + vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline; + for (y = dev->overlay_cap_top; + y < dev->overlay_cap_top + (int)img_height; + y++, vbuf += stride) { + int px; + + if (y < 0 || y > dev->fb_cap.fmt.height) + continue; + if (quick) { + memcpy(vbase + x * pixsize, + vbuf + out_x * pixsize, w * pixsize); + vbase += dev->fb_cap.fmt.bytesperline; + continue; + } + for (px = 0; px < w; px++) { + if (!valid_pix(dev, y - dev->overlay_cap_top, + px + out_x, y, px + x)) + continue; + memcpy(vbase + (px + x) * pixsize, + vbuf + (px + out_x) * pixsize, + pixsize); + } + vbase += dev->fb_cap.fmt.bytesperline; + } +} + +static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs) +{ + struct vivid_buffer *vid_cap_buf = NULL; + struct vivid_buffer *vbi_cap_buf = NULL; + + dprintk(dev, 1, "Video Capture Thread Tick\n"); + + while (dropped_bufs-- > 1) + tpg_update_mv_count(&dev->tpg, + dev->field_cap == V4L2_FIELD_NONE || + dev->field_cap == V4L2_FIELD_ALTERNATE); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + goto update_mv; + + spin_lock(&dev->slock); + if (!list_empty(&dev->vid_cap_active)) { + vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list); + list_del(&vid_cap_buf->list); + } + if (!list_empty(&dev->vbi_cap_active)) { + if (dev->field_cap != V4L2_FIELD_ALTERNATE || + (dev->vbi_cap_seq_count & 1)) { + vbi_cap_buf = list_entry(dev->vbi_cap_active.next, + struct vivid_buffer, list); + list_del(&vbi_cap_buf->list); + } + } + spin_unlock(&dev->slock); + + if (!vid_cap_buf && !vbi_cap_buf) + goto update_mv; + + if (vid_cap_buf) { + /* Fill buffer */ + vivid_fillbuff(dev, vid_cap_buf); + dprintk(dev, 1, "filled buffer %d\n", + vid_cap_buf->vb.v4l2_buf.index); + + /* Handle overlay */ + if (dev->overlay_cap_owner && dev->fb_cap.base && + dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc) + vivid_overlay(dev, vid_cap_buf); + + vb2_buffer_done(&vid_cap_buf->vb, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vid_cap buffer %d done\n", + vid_cap_buf->vb.v4l2_buf.index); + } + + if (vbi_cap_buf) { + if (dev->stream_sliced_vbi_cap) + vivid_sliced_vbi_cap_process(dev, vbi_cap_buf); + else + vivid_raw_vbi_cap_process(dev, vbi_cap_buf); + vb2_buffer_done(&vbi_cap_buf->vb, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vbi_cap %d done\n", + vbi_cap_buf->vb.v4l2_buf.index); + } + dev->dqbuf_error = false; + +update_mv: + /* Update the test pattern movement counters */ + tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE || + dev->field_cap == V4L2_FIELD_ALTERNATE); +} + +static int vivid_thread_vid_cap(void *data) +{ + struct vivid_dev *dev = data; + u64 numerators_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + unsigned numerator; + unsigned denominator; + int dropped_bufs; + + dprintk(dev, 1, "Video Capture Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->cap_seq_offset = 0; + dev->cap_seq_count = 0; + dev->cap_seq_resync = false; + dev->jiffies_vid_cap = jiffies; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + mutex_lock(&dev->mutex); + cur_jiffies = jiffies; + if (dev->cap_seq_resync) { + dev->jiffies_vid_cap = cur_jiffies; + dev->cap_seq_offset = dev->cap_seq_count + 1; + dev->cap_seq_count = 0; + dev->cap_seq_resync = false; + } + numerator = dev->timeperframe_vid_cap.numerator; + denominator = dev->timeperframe_vid_cap.denominator; + + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + denominator *= 2; + + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * denominator + + (HZ * numerator) / 2; + do_div(buffers_since_start, HZ * numerator); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_vid_cap = cur_jiffies; + dev->cap_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count; + dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; + dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; + dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; + + vivid_thread_vid_cap_tick(dev, dropped_bufs); + + /* + * Calculate the number of 'numerators' streamed since we started, + * including the current buffer. + */ + numerators_since_start = ++buffers_since_start * numerator; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_vid_cap; + + mutex_unlock(&dev->mutex); + + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = numerators_since_start * HZ + + denominator / 2; + do_div(next_jiffies_since_start, denominator); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "Video Capture Thread End\n"); + return 0; +} + +static void vivid_grab_controls(struct vivid_dev *dev, bool grab) +{ + v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab); + v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab); + v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab); +} + +int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_cap) { + u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128; + + if (pstreaming == &dev->vid_cap_streaming) + dev->vid_cap_seq_start = seq_count; + else + dev->vbi_cap_seq_start = seq_count; + *pstreaming = true; + return 0; + } + + /* Resets frame counters */ + tpg_init_mv_count(&dev->tpg); + + dev->vid_cap_seq_start = dev->seq_wrap * 128; + dev->vbi_cap_seq_start = dev->seq_wrap * 128; + + dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, + "%s-vid-cap", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_vid_cap)) { + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + return PTR_ERR(dev->kthread_vid_cap); + } + *pstreaming = true; + vivid_grab_controls(dev, true); + + dprintk(dev, 1, "returning from %s\n", __func__); + return 0; +} + +void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_cap == NULL) + return; + + *pstreaming = false; + if (pstreaming == &dev->vid_cap_streaming) { + /* Release all active buffers */ + while (!list_empty(&dev->vid_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vid_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vid_cap buffer %d done\n", + buf->vb.v4l2_buf.index); + } + } + + if (pstreaming == &dev->vbi_cap_streaming) { + while (!list_empty(&dev->vbi_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vbi_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vbi_cap buffer %d done\n", + buf->vb.v4l2_buf.index); + } + } + + if (dev->vid_cap_streaming || dev->vbi_cap_streaming) + return; + + /* shutdown control thread */ + vivid_grab_controls(dev, false); + mutex_unlock(&dev->mutex); + kthread_stop(dev->kthread_vid_cap); + dev->kthread_vid_cap = NULL; + mutex_lock(&dev->mutex); +} diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h new file mode 100644 index 000000000000..5b92fc9a0d04 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-kthread-cap.h @@ -0,0 +1,26 @@ +/* + * vivid-kthread-cap.h - video/vbi capture thread support functions. + * + * Copyright 2014 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 _VIVID_KTHREAD_CAP_H_ +#define _VIVID_KTHREAD_CAP_H_ + +int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); +void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); + +#endif diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c new file mode 100644 index 000000000000..190575577948 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -0,0 +1,304 @@ +/* + * vivid-kthread-out.h - video/vbi output thread support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" + +static void vivid_thread_vid_out_tick(struct vivid_dev *dev) +{ + struct vivid_buffer *vid_out_buf = NULL; + struct vivid_buffer *vbi_out_buf = NULL; + + dprintk(dev, 1, "Video Output Thread Tick\n"); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + return; + + spin_lock(&dev->slock); + /* + * Only dequeue buffer if there is at least one more pending. + * This makes video loopback possible. + */ + if (!list_empty(&dev->vid_out_active) && + !list_is_singular(&dev->vid_out_active)) { + vid_out_buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + list_del(&vid_out_buf->list); + } + if (!list_empty(&dev->vbi_out_active) && + (dev->field_out != V4L2_FIELD_ALTERNATE || + (dev->vbi_out_seq_count & 1))) { + vbi_out_buf = list_entry(dev->vbi_out_active.next, + struct vivid_buffer, list); + list_del(&vbi_out_buf->list); + } + spin_unlock(&dev->slock); + + if (!vid_out_buf && !vbi_out_buf) + return; + + if (vid_out_buf) { + vid_out_buf->vb.v4l2_buf.sequence = dev->vid_out_seq_count; + if (dev->field_out == V4L2_FIELD_ALTERNATE) { + /* + * The sequence counter counts frames, not fields. So divide + * by two. + */ + vid_out_buf->vb.v4l2_buf.sequence /= 2; + } + v4l2_get_timestamp(&vid_out_buf->vb.v4l2_buf.timestamp); + vid_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; + vb2_buffer_done(&vid_out_buf->vb, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vid_out buffer %d done\n", + vid_out_buf->vb.v4l2_buf.index); + } + + if (vbi_out_buf) { + if (dev->stream_sliced_vbi_out) + vivid_sliced_vbi_out_process(dev, vbi_out_buf); + + vbi_out_buf->vb.v4l2_buf.sequence = dev->vbi_out_seq_count; + v4l2_get_timestamp(&vbi_out_buf->vb.v4l2_buf.timestamp); + vbi_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; + vb2_buffer_done(&vbi_out_buf->vb, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vbi_out buffer %d done\n", + vbi_out_buf->vb.v4l2_buf.index); + } + dev->dqbuf_error = false; +} + +static int vivid_thread_vid_out(void *data) +{ + struct vivid_dev *dev = data; + u64 numerators_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + unsigned numerator; + unsigned denominator; + + dprintk(dev, 1, "Video Output Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->out_seq_offset = 0; + if (dev->seq_wrap) + dev->out_seq_count = 0xffffff80U; + dev->jiffies_vid_out = jiffies; + dev->vid_out_seq_start = dev->vbi_out_seq_start = 0; + dev->out_seq_resync = false; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + mutex_lock(&dev->mutex); + cur_jiffies = jiffies; + if (dev->out_seq_resync) { + dev->jiffies_vid_out = cur_jiffies; + dev->out_seq_offset = dev->out_seq_count + 1; + dev->out_seq_count = 0; + dev->out_seq_resync = false; + } + numerator = dev->timeperframe_vid_out.numerator; + denominator = dev->timeperframe_vid_out.denominator; + + if (dev->field_out == V4L2_FIELD_ALTERNATE) + denominator *= 2; + + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_vid_out; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * denominator + + (HZ * numerator) / 2; + do_div(buffers_since_start, HZ * numerator); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_vid_out = cur_jiffies; + dev->out_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dev->out_seq_count = buffers_since_start + dev->out_seq_offset; + dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; + dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; + + vivid_thread_vid_out_tick(dev); + mutex_unlock(&dev->mutex); + + /* + * Calculate the number of 'numerators' streamed since we started, + * not including the current buffer. + */ + numerators_since_start = buffers_since_start * numerator; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_vid_out; + + /* Increase by the 'numerator' of one buffer */ + numerators_since_start += numerator; + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = numerators_since_start * HZ + + denominator / 2; + do_div(next_jiffies_since_start, denominator); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "Video Output Thread End\n"); + return 0; +} + +static void vivid_grab_controls(struct vivid_dev *dev, bool grab) +{ + v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab); + v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab); + v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab); + v4l2_ctrl_grab(dev->ctrl_tx_mode, grab); + v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab); +} + +int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_out) { + u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128; + + if (pstreaming == &dev->vid_out_streaming) + dev->vid_out_seq_start = seq_count; + else + dev->vbi_out_seq_start = seq_count; + *pstreaming = true; + return 0; + } + + /* Resets frame counters */ + dev->jiffies_vid_out = jiffies; + dev->vid_out_seq_start = dev->seq_wrap * 128; + dev->vbi_out_seq_start = dev->seq_wrap * 128; + + dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, + "%s-vid-out", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_vid_out)) { + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + return PTR_ERR(dev->kthread_vid_out); + } + *pstreaming = true; + vivid_grab_controls(dev, true); + + dprintk(dev, 1, "returning from %s\n", __func__); + return 0; +} + +void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_out == NULL) + return; + + *pstreaming = false; + if (pstreaming == &dev->vid_out_streaming) { + /* Release all active buffers */ + while (!list_empty(&dev->vid_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vid_out buffer %d done\n", + buf->vb.v4l2_buf.index); + } + } + + if (pstreaming == &dev->vbi_out_streaming) { + while (!list_empty(&dev->vbi_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vbi_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vbi_out buffer %d done\n", + buf->vb.v4l2_buf.index); + } + } + + if (dev->vid_out_streaming || dev->vbi_out_streaming) + return; + + /* shutdown control thread */ + vivid_grab_controls(dev, false); + mutex_unlock(&dev->mutex); + kthread_stop(dev->kthread_vid_out); + dev->kthread_vid_out = NULL; + mutex_lock(&dev->mutex); +} diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h new file mode 100644 index 000000000000..2bf04a17b05d --- /dev/null +++ b/drivers/media/platform/vivid/vivid-kthread-out.h @@ -0,0 +1,26 @@ +/* + * vivid-kthread-out.h - video/vbi output thread support functions. + * + * Copyright 2014 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 _VIVID_KTHREAD_OUT_H_ +#define _VIVID_KTHREAD_OUT_H_ + +int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); +void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); + +#endif -- cgit v1.2.3 From ad4e02d5081d9da38b5b91886e5fa71f0505d607 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:01:49 -0300 Subject: [media] vivid: add a simple framebuffer device for overlay testing In order to test capture and output overlays a simple framebuffer device is created. It's bare bone, but it does the job. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-osd.c | 400 +++++++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-osd.h | 27 +++ 2 files changed, 427 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-osd.c create mode 100644 drivers/media/platform/vivid/vivid-osd.h diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c new file mode 100644 index 000000000000..084d346fb4c4 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -0,0 +1,400 @@ +/* + * vivid-osd.c - osd support for testing overlays. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-osd.h" + +#define MAX_OSD_WIDTH 720 +#define MAX_OSD_HEIGHT 576 + +/* + * Order: white, yellow, cyan, green, magenta, red, blue, black, + * and same again with the alpha bit set (if any) + */ +static const u16 rgb555[16] = { + 0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000, + 0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000 +}; + +static const u16 rgb565[16] = { + 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000, + 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000 +}; + +void vivid_clear_fb(struct vivid_dev *dev) +{ + void *p = dev->video_vbase; + const u16 *rgb = rgb555; + unsigned x, y; + + if (dev->fb_defined.green.length == 6) + rgb = rgb565; + + for (y = 0; y < dev->display_height; y++) { + u16 *d = p; + + for (x = 0; x < dev->display_width; x++) + d[x] = rgb[(y / 16 + x / 16) % 16]; + p += dev->display_byte_stride; + } +} + +/* --------------------------------------------------------------------- */ + +static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg) +{ + struct vivid_dev *dev = (struct vivid_dev *)info->par; + + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + + vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + vblank.count = 0; + vblank.vcount = 0; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + default: + dprintk(dev, 1, "Unknown ioctl %08x\n", cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var) +{ + dprintk(dev, 1, "vivid_fb_set_var\n"); + + if (var->bits_per_pixel != 16) { + dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n"); + return -EINVAL; + } + dev->display_byte_stride = var->xres * dev->bytes_per_pixel; + + return 0; +} + +static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix) +{ + dprintk(dev, 1, "vivid_fb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strlcpy(fix->id, "vioverlay fb", sizeof(fix->id)); + fix->smem_start = dev->video_pbase; + fix->smem_len = dev->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = dev->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev) +{ + dprintk(dev, 1, "vivid_fb_check_var\n"); + + var->bits_per_pixel = 16; + if (var->green.length == 5) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + var->xoffset = var->yoffset = 0; + var->left_margin = var->upper_margin = 0; + var->nonstd = 0; + + var->vmode &= ~FB_VMODE_MASK; + var->vmode = FB_VMODE_NONINTERLACED; + + /* Dummy values */ + var->hsync_len = 24; + var->vsync_len = 2; + var->pixclock = 84316; + var->right_margin = 776; + var->lower_margin = 591; + return 0; +} + +static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct vivid_dev *dev = (struct vivid_dev *) info->par; + + dprintk(dev, 1, "vivid_fb_check_var\n"); + return _vivid_fb_check_var(var, dev); +} + +static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + return 0; +} + +static int vivid_fb_set_par(struct fb_info *info) +{ + int rc = 0; + struct vivid_dev *dev = (struct vivid_dev *) info->par; + + dprintk(dev, 1, "vivid_fb_set_par\n"); + + rc = vivid_fb_set_var(dev, &info->var); + vivid_fb_get_fix(dev, &info->fix); + return rc; +} + +static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | + (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 6: + color = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11) | + (transp ? 0x8000 : 0); + break; + } + } + palette[regno] = color; + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int vivid_fb_blank(int blank_mode, struct fb_info *info) +{ + struct vivid_dev *dev = (struct vivid_dev *)info->par; + + dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + break; + } + return 0; +} + +static struct fb_ops vivid_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = vivid_fb_check_var, + .fb_set_par = vivid_fb_set_par, + .fb_setcolreg = vivid_fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = vivid_fb_ioctl, + .fb_pan_display = vivid_fb_pan_display, + .fb_blank = vivid_fb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int vivid_fb_init_vidmode(struct vivid_dev *dev) +{ + struct v4l2_rect start_window; + + /* Color mode */ + + dev->bits_per_pixel = 16; + dev->bytes_per_pixel = dev->bits_per_pixel / 8; + + start_window.width = MAX_OSD_WIDTH; + start_window.left = 0; + + dev->display_byte_stride = start_window.width * dev->bytes_per_pixel; + + /* Vertical size & position */ + + start_window.height = MAX_OSD_HEIGHT; + start_window.top = 0; + + dev->display_width = start_window.width; + dev->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + dev->fb_defined.xres = dev->display_width; + dev->fb_defined.yres = dev->display_height; + dev->fb_defined.xres_virtual = dev->display_width; + dev->fb_defined.yres_virtual = dev->display_height; + dev->fb_defined.bits_per_pixel = dev->bits_per_pixel; + dev->fb_defined.vmode = FB_VMODE_NONINTERLACED; + dev->fb_defined.left_margin = start_window.left + 1; + dev->fb_defined.upper_margin = start_window.top + 1; + dev->fb_defined.accel_flags = FB_ACCEL_NONE; + dev->fb_defined.nonstd = 0; + /* set default to 1:5:5:5 */ + dev->fb_defined.green.length = 5; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _vivid_fb_check_var(&dev->fb_defined, dev); + + /* Generate valid fb_fix_screeninfo */ + + vivid_fb_get_fix(dev, &dev->fb_fix); + + /* Generate valid fb_info */ + + dev->fb_info.node = -1; + dev->fb_info.flags = FBINFO_FLAG_DEFAULT; + dev->fb_info.fbops = &vivid_fb_ops; + dev->fb_info.par = dev; + dev->fb_info.var = dev->fb_defined; + dev->fb_info.fix = dev->fb_fix; + dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase; + dev->fb_info.fbops = &vivid_fb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + dev->fb_info.monspecs.hfmin = 8000; + dev->fb_info.monspecs.hfmax = 70000; + dev->fb_info.monspecs.vfmin = 10; + dev->fb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) { + pr_err("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL); + + return dev->fb_info.pseudo_palette ? 0 : -ENOMEM; +} + +/* Release any memory we've grabbed */ +void vivid_fb_release_buffers(struct vivid_dev *dev) +{ + if (dev->video_vbase == NULL) + return; + + /* Release cmap */ + if (dev->fb_info.cmap.len) + fb_dealloc_cmap(&dev->fb_info.cmap); + + /* Release pseudo palette */ + kfree(dev->fb_info.pseudo_palette); + kfree((void *)dev->video_vbase); +} + +/* Initialize the specified card */ + +int vivid_fb_init(struct vivid_dev *dev) +{ + int ret; + + dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2; + dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32); + if (dev->video_vbase == NULL) + return -ENOMEM; + dev->video_pbase = virt_to_phys(dev->video_vbase); + + pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + dev->video_pbase, dev->video_vbase, + dev->video_buffer_size / 1024); + + /* Set the startup video mode information */ + ret = vivid_fb_init_vidmode(dev); + if (ret) { + vivid_fb_release_buffers(dev); + return ret; + } + + vivid_clear_fb(dev); + + /* Register the framebuffer */ + if (register_framebuffer(&dev->fb_info) < 0) { + vivid_fb_release_buffers(dev); + return -EINVAL; + } + + /* Set the card to the requested mode */ + vivid_fb_set_par(&dev->fb_info); + return 0; + +} diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h new file mode 100644 index 000000000000..57c9daa5940a --- /dev/null +++ b/drivers/media/platform/vivid/vivid-osd.h @@ -0,0 +1,27 @@ +/* + * vivid-osd.h - output overlay support functions. + * + * Copyright 2014 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 _VIVID_OSD_H_ +#define _VIVID_OSD_H_ + +int vivid_fb_init(struct vivid_dev *dev); +void vivid_fb_release_buffers(struct vivid_dev *dev); +void vivid_clear_fb(struct vivid_dev *dev); + +#endif -- cgit v1.2.3 From 63881df94d3ecbb0deafa0b77da62ff2f32961c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:02:14 -0300 Subject: [media] vivid: add the Test Pattern Generator The test patterns for video capture are generated by this code. All patterns are precalculated taking into account colorspace information, pixel and video aspect ratios and scaling information. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg-colors.c | 310 +++++ drivers/media/platform/vivid/vivid-tpg-colors.h | 64 + drivers/media/platform/vivid/vivid-tpg.c | 1439 +++++++++++++++++++++++ drivers/media/platform/vivid/vivid-tpg.h | 438 +++++++ 4 files changed, 2251 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.c create mode 100644 drivers/media/platform/vivid/vivid-tpg-colors.h create mode 100644 drivers/media/platform/vivid/vivid-tpg.c create mode 100644 drivers/media/platform/vivid/vivid-tpg.h diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c new file mode 100644 index 000000000000..2adddc0ca662 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-tpg-colors.c @@ -0,0 +1,310 @@ +/* + * vivid-color.c - A table that converts colors to various colorspaces + * + * The test pattern generator uses the tpg_colors for its test patterns. + * For testing colorspaces the first 8 colors of that table need to be + * converted to their equivalent in the target colorspace. + * + * The tpg_csc_colors[] table is the result of that conversion and since + * it is precalculated the colorspace conversion is just a simple table + * lookup. + * + * This source also contains the code used to generate the tpg_csc_colors + * table. Run the following command to compile it: + * + * gcc vivid-colors.c -DCOMPILE_APP -o gen-colors -lm + * + * and run the utility. + * + * Note that the converted colors are in the range 0x000-0xff0 (so times 16) + * in order to preserve precision. + * + * Copyright 2014 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. + */ + +#include + +#include "vivid-tpg-colors.h" + +/* sRGB colors with range [0-255] */ +const struct color tpg_colors[TPG_COLOR_MAX] = { + /* + * Colors to test colorspace conversion: converting these colors + * to other colorspaces will never lead to out-of-gamut colors. + */ + { 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */ + { 191, 191, 50 }, /* TPG_COLOR_CSC_YELLOW */ + { 50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */ + { 50, 191, 50 }, /* TPG_COLOR_CSC_GREEN */ + { 191, 50, 191 }, /* TPG_COLOR_CSC_MAGENTA */ + { 191, 50, 50 }, /* TPG_COLOR_CSC_RED */ + { 50, 50, 191 }, /* TPG_COLOR_CSC_BLUE */ + { 50, 50, 50 }, /* TPG_COLOR_CSC_BLACK */ + + /* 75% colors */ + { 191, 191, 0 }, /* TPG_COLOR_75_YELLOW */ + { 0, 191, 191 }, /* TPG_COLOR_75_CYAN */ + { 0, 191, 0 }, /* TPG_COLOR_75_GREEN */ + { 191, 0, 191 }, /* TPG_COLOR_75_MAGENTA */ + { 191, 0, 0 }, /* TPG_COLOR_75_RED */ + { 0, 0, 191 }, /* TPG_COLOR_75_BLUE */ + + /* 100% colors */ + { 255, 255, 255 }, /* TPG_COLOR_100_WHITE */ + { 255, 255, 0 }, /* TPG_COLOR_100_YELLOW */ + { 0, 255, 255 }, /* TPG_COLOR_100_CYAN */ + { 0, 255, 0 }, /* TPG_COLOR_100_GREEN */ + { 255, 0, 255 }, /* TPG_COLOR_100_MAGENTA */ + { 255, 0, 0 }, /* TPG_COLOR_100_RED */ + { 0, 0, 255 }, /* TPG_COLOR_100_BLUE */ + { 0, 0, 0 }, /* TPG_COLOR_100_BLACK */ + + { 0, 0, 0 }, /* TPG_COLOR_RANDOM placeholder */ +}; + +#ifndef COMPILE_APP + +/* Generated table */ +const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = { + [V4L2_COLORSPACE_SMPTE170M][0] = { 2953, 2939, 2939 }, + [V4L2_COLORSPACE_SMPTE170M][1] = { 2954, 2963, 585 }, + [V4L2_COLORSPACE_SMPTE170M][2] = { 84, 2967, 2937 }, + [V4L2_COLORSPACE_SMPTE170M][3] = { 93, 2990, 575 }, + [V4L2_COLORSPACE_SMPTE170M][4] = { 3030, 259, 2933 }, + [V4L2_COLORSPACE_SMPTE170M][5] = { 3031, 406, 557 }, + [V4L2_COLORSPACE_SMPTE170M][6] = { 544, 428, 2931 }, + [V4L2_COLORSPACE_SMPTE170M][7] = { 551, 547, 547 }, + [V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 }, + [V4L2_COLORSPACE_SMPTE240M][1] = { 2926, 2926, 857 }, + [V4L2_COLORSPACE_SMPTE240M][2] = { 1594, 2901, 2901 }, + [V4L2_COLORSPACE_SMPTE240M][3] = { 1594, 2901, 774 }, + [V4L2_COLORSPACE_SMPTE240M][4] = { 2484, 618, 2858 }, + [V4L2_COLORSPACE_SMPTE240M][5] = { 2484, 618, 617 }, + [V4L2_COLORSPACE_SMPTE240M][6] = { 507, 507, 2832 }, + [V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 }, + [V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 }, + [V4L2_COLORSPACE_REC709][2] = { 547, 2939, 2939 }, + [V4L2_COLORSPACE_REC709][3] = { 547, 2939, 547 }, + [V4L2_COLORSPACE_REC709][4] = { 2939, 547, 2939 }, + [V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 }, + [V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 }, + [V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2894, 2988, 2808 }, + [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2847, 3070, 843 }, + [V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 }, + [V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 }, + [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2477, 229, 2743 }, + [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2422, 672, 614 }, + [V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 }, + [V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 621 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 621 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2923 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2923 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 }, + [V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 }, + [V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 }, + [V4L2_COLORSPACE_SRGB][2] = { 800, 3056, 3056 }, + [V4L2_COLORSPACE_SRGB][3] = { 800, 3056, 800 }, + [V4L2_COLORSPACE_SRGB][4] = { 3056, 800, 3056 }, + [V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 }, + [V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 }, + [V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 }, +}; + +#else + +/* This code generates the table above */ + +#include +#include +#include + +static const double rec709_to_ntsc1953[3][3] = { + { 0.6698, 0.2678, 0.0323 }, + { 0.0185, 1.0742, -0.0603 }, + { 0.0162, 0.0432, 0.8551 } +}; + +static const double rec709_to_ebu[3][3] = { + { 0.9578, 0.0422, 0 }, + { 0 , 1 , 0 }, + { 0 , 0.0118, 0.9882 } +}; + +static const double rec709_to_170m[3][3] = { + { 1.0654, -0.0554, -0.0010 }, + { -0.0196, 1.0364, -0.0167 }, + { 0.0016, 0.0044, 0.9940 } +}; + +static const double rec709_to_240m[3][3] = { + { 0.7151, 0.2849, 0 }, + { 0.0179, 0.9821, 0 }, + { 0.0177, 0.0472, 0.9350 } +}; + + +static void mult_matrix(double *r, double *g, double *b, const double m[3][3]) +{ + double ir, ig, ib; + + ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b); + ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b); + ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b); + *r = ir; + *g = ig; + *b = ib; +} + +static double transfer_srgb_to_rgb(double v) +{ + return (v <= 0.03928) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4); +} + +static double transfer_rgb_to_smpte240m(double v) +{ + return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115; +} + +static double transfer_rgb_to_rec709(double v) +{ + return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099; +} + +static double transfer_srgb_to_rec709(double v) +{ + return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v)); +} + +static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b) +{ + /* Convert the primaries of Rec. 709 Linear RGB */ + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE240M: + *r = transfer_srgb_to_rgb(*r); + *g = transfer_srgb_to_rgb(*g); + *b = transfer_srgb_to_rgb(*b); + mult_matrix(r, g, b, rec709_to_240m); + break; + case V4L2_COLORSPACE_SMPTE170M: + *r = transfer_srgb_to_rgb(*r); + *g = transfer_srgb_to_rgb(*g); + *b = transfer_srgb_to_rgb(*b); + mult_matrix(r, g, b, rec709_to_170m); + break; + case V4L2_COLORSPACE_470_SYSTEM_BG: + *r = transfer_srgb_to_rgb(*r); + *g = transfer_srgb_to_rgb(*g); + *b = transfer_srgb_to_rgb(*b); + mult_matrix(r, g, b, rec709_to_ebu); + break; + case V4L2_COLORSPACE_470_SYSTEM_M: + *r = transfer_srgb_to_rgb(*r); + *g = transfer_srgb_to_rgb(*g); + *b = transfer_srgb_to_rgb(*b); + mult_matrix(r, g, b, rec709_to_ntsc1953); + break; + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_REC709: + default: + break; + } + + *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r)); + *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g)); + *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b)); + + /* Encode to gamma corrected colorspace */ + switch (colorspace) { + case V4L2_COLORSPACE_SMPTE240M: + *r = transfer_rgb_to_smpte240m(*r); + *g = transfer_rgb_to_smpte240m(*g); + *b = transfer_rgb_to_smpte240m(*b); + break; + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + *r = transfer_rgb_to_rec709(*r); + *g = transfer_rgb_to_rec709(*g); + *b = transfer_rgb_to_rec709(*b); + break; + case V4L2_COLORSPACE_SRGB: + break; + case V4L2_COLORSPACE_REC709: + default: + *r = transfer_srgb_to_rec709(*r); + *g = transfer_srgb_to_rec709(*g); + *b = transfer_srgb_to_rec709(*b); + break; + } +} + +int main(int argc, char **argv) +{ + static const unsigned colorspaces[] = { + 0, + V4L2_COLORSPACE_SMPTE170M, + V4L2_COLORSPACE_SMPTE240M, + V4L2_COLORSPACE_REC709, + 0, + V4L2_COLORSPACE_470_SYSTEM_M, + V4L2_COLORSPACE_470_SYSTEM_BG, + 0, + V4L2_COLORSPACE_SRGB, + }; + static const char * const colorspace_names[] = { + "", + "V4L2_COLORSPACE_SMPTE170M", + "V4L2_COLORSPACE_SMPTE240M", + "V4L2_COLORSPACE_REC709", + "", + "V4L2_COLORSPACE_470_SYSTEM_M", + "V4L2_COLORSPACE_470_SYSTEM_BG", + "", + "V4L2_COLORSPACE_SRGB", + }; + int i; + int c; + + printf("/* Generated table */\n"); + printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {\n"); + for (c = 0; c <= V4L2_COLORSPACE_SRGB; c++) { + for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) { + double r, g, b; + + if (colorspaces[c] == 0) + continue; + + r = tpg_colors[i].r / 255.0; + g = tpg_colors[i].g / 255.0; + b = tpg_colors[i].b / 255.0; + + csc(c, &r, &g, &b); + + printf("\t[%s][%d] = { %d, %d, %d },\n", colorspace_names[c], i, + (int)(r * 4080), (int)(g * 4080), (int)(b * 4080)); + } + } + printf("};\n\n"); + return 0; +} + +#endif diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h new file mode 100644 index 000000000000..a2678fbec256 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-tpg-colors.h @@ -0,0 +1,64 @@ +/* + * vivid-color.h - Color definitions for the test pattern generator + * + * Copyright 2014 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 _VIVID_COLORS_H_ +#define _VIVID_COLORS_H_ + +struct color { + unsigned char r, g, b; +}; + +struct color16 { + int r, g, b; +}; + +enum tpg_color { + TPG_COLOR_CSC_WHITE, + TPG_COLOR_CSC_YELLOW, + TPG_COLOR_CSC_CYAN, + TPG_COLOR_CSC_GREEN, + TPG_COLOR_CSC_MAGENTA, + TPG_COLOR_CSC_RED, + TPG_COLOR_CSC_BLUE, + TPG_COLOR_CSC_BLACK, + TPG_COLOR_75_YELLOW, + TPG_COLOR_75_CYAN, + TPG_COLOR_75_GREEN, + TPG_COLOR_75_MAGENTA, + TPG_COLOR_75_RED, + TPG_COLOR_75_BLUE, + TPG_COLOR_100_WHITE, + TPG_COLOR_100_YELLOW, + TPG_COLOR_100_CYAN, + TPG_COLOR_100_GREEN, + TPG_COLOR_100_MAGENTA, + TPG_COLOR_100_RED, + TPG_COLOR_100_BLUE, + TPG_COLOR_100_BLACK, + TPG_COLOR_TEXTFG, + TPG_COLOR_TEXTBG, + TPG_COLOR_RANDOM, + TPG_COLOR_RAMP, + TPG_COLOR_MAX = TPG_COLOR_RAMP + 256 +}; + +extern const struct color tpg_colors[TPG_COLOR_MAX]; +extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1]; + +#endif diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c new file mode 100644 index 000000000000..8576b2c1d4a1 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -0,0 +1,1439 @@ +/* + * vivid-tpg.c - Test Pattern Generator + * + * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the + * vivi.c source for the copyright information of those functions. + * + * Copyright 2014 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. + */ + +#include "vivid-tpg.h" + +/* Must remain in sync with enum tpg_pattern */ +const char * const tpg_pattern_strings[] = { + "75% Colorbar", + "100% Colorbar", + "CSC Colorbar", + "Horizontal 100% Colorbar", + "100% Color Squares", + "100% Black", + "100% White", + "100% Red", + "100% Green", + "100% Blue", + "16x16 Checkers", + "1x1 Checkers", + "Alternating Hor Lines", + "Alternating Vert Lines", + "One Pixel Wide Cross", + "Two Pixels Wide Cross", + "Ten Pixels Wide Cross", + "Gray Ramp", + "Noise", + NULL +}; + +/* Must remain in sync with enum tpg_aspect */ +const char * const tpg_aspect_strings[] = { + "Source Width x Height", + "4x3", + "14x9", + "16x9", + "16x9 Anamorphic", + NULL +}; + +/* + * Sine table: sin[0] = 127 * sin(-180 degrees) + * sin[128] = 127 * sin(0 degrees) + * sin[256] = 127 * sin(180 degrees) + */ +static const s8 sin[257] = { + 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48, + -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88, + -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117, + -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127, + -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118, + -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91, + -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50, + -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2, + 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46, + 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87, + 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127, + 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, + 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93, + 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52, + 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4, + 0, +}; + +#define cos(idx) sin[((idx) + 64) % sizeof(sin)] + +/* Global font descriptor */ +static const u8 *font8x16; + +void tpg_set_font(const u8 *f) +{ + font8x16 = f; +} + +void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) +{ + memset(tpg, 0, sizeof(*tpg)); + tpg->scaled_width = tpg->src_width = w; + tpg->src_height = tpg->buf_height = h; + tpg->crop.width = tpg->compose.width = w; + tpg->crop.height = tpg->compose.height = h; + tpg->recalc_colors = true; + tpg->recalc_square_border = true; + tpg->brightness = 128; + tpg->contrast = 128; + tpg->saturation = 128; + tpg->hue = 0; + tpg->mv_hor_mode = TPG_MOVE_NONE; + tpg->mv_vert_mode = TPG_MOVE_NONE; + tpg->field = V4L2_FIELD_NONE; + tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24); + tpg->colorspace = V4L2_COLORSPACE_SRGB; + tpg->perc_fill = 100; +} + +int tpg_alloc(struct tpg_data *tpg, unsigned max_w) +{ + unsigned pat; + unsigned plane; + + tpg->max_line_width = max_w; + for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { + for (plane = 0; plane < TPG_MAX_PLANES; plane++) { + unsigned pixelsz = plane ? 1 : 4; + + tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); + if (!tpg->lines[pat][plane]) + return -ENOMEM; + } + } + for (plane = 0; plane < TPG_MAX_PLANES; plane++) { + unsigned pixelsz = plane ? 1 : 4; + + tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); + if (!tpg->contrast_line[plane]) + return -ENOMEM; + tpg->black_line[plane] = vzalloc(max_w * pixelsz); + if (!tpg->black_line[plane]) + return -ENOMEM; + tpg->random_line[plane] = vzalloc(max_w * pixelsz); + if (!tpg->random_line[plane]) + return -ENOMEM; + } + return 0; +} + +void tpg_free(struct tpg_data *tpg) +{ + unsigned pat; + unsigned plane; + + for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) + for (plane = 0; plane < TPG_MAX_PLANES; plane++) { + vfree(tpg->lines[pat][plane]); + tpg->lines[pat][plane] = NULL; + } + for (plane = 0; plane < TPG_MAX_PLANES; plane++) { + vfree(tpg->contrast_line[plane]); + vfree(tpg->black_line[plane]); + vfree(tpg->random_line[plane]); + tpg->contrast_line[plane] = NULL; + tpg->black_line[plane] = NULL; + tpg->random_line[plane] = NULL; + } +} + +bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) +{ + tpg->fourcc = fourcc; + tpg->planes = 1; + tpg->recalc_colors = true; + switch (fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_XRGB555: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: + tpg->is_yuv = 0; + break; + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_NV61M: + tpg->planes = 2; + /* fall-through */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + tpg->is_yuv = 1; + break; + default: + return false; + } + + switch (fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_XRGB555: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + tpg->twopixelsize[0] = 2 * 2; + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + tpg->twopixelsize[0] = 2 * 3; + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: + tpg->twopixelsize[0] = 2 * 4; + break; + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_NV61M: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 2; + break; + } + return true; +} + +void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, + const struct v4l2_rect *compose) +{ + tpg->crop = *crop; + tpg->compose = *compose; + tpg->scaled_width = (tpg->src_width * tpg->compose.width + + tpg->crop.width - 1) / tpg->crop.width; + tpg->scaled_width &= ~1; + if (tpg->scaled_width > tpg->max_line_width) + tpg->scaled_width = tpg->max_line_width; + if (tpg->scaled_width < 2) + tpg->scaled_width = 2; + tpg->recalc_lines = true; +} + +void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, + enum v4l2_field field) +{ + unsigned p; + + tpg->src_width = width; + tpg->src_height = height; + tpg->field = field; + tpg->buf_height = height; + if (V4L2_FIELD_HAS_T_OR_B(field)) + tpg->buf_height /= 2; + tpg->scaled_width = width; + tpg->crop.top = tpg->crop.left = 0; + tpg->crop.width = width; + tpg->crop.height = height; + tpg->compose.top = tpg->compose.left = 0; + tpg->compose.width = width; + tpg->compose.height = tpg->buf_height; + for (p = 0; p < tpg->planes; p++) + tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2; + tpg->recalc_square_border = true; +} + +static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg) +{ + switch (tpg->pattern) { + case TPG_PAT_BLACK: + return TPG_COLOR_100_WHITE; + case TPG_PAT_CSC_COLORBAR: + return TPG_COLOR_CSC_BLACK; + default: + return TPG_COLOR_100_BLACK; + } +} + +static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg) +{ + switch (tpg->pattern) { + case TPG_PAT_75_COLORBAR: + case TPG_PAT_CSC_COLORBAR: + return TPG_COLOR_CSC_WHITE; + case TPG_PAT_BLACK: + return TPG_COLOR_100_BLACK; + default: + return TPG_COLOR_100_WHITE; + } +} + +static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b) +{ + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4); + case V4L2_COLORSPACE_SMPTE240M: + return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4); + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4); + } +} + +static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b) +{ + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4); + case V4L2_COLORSPACE_SMPTE240M: + return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4); + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4); + } +} + +static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b) +{ + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4); + case V4L2_COLORSPACE_SMPTE240M: + return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4); + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4); + } +} + +static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr) +{ + int r; + + y -= 16 << 4; + cb -= 128 << 4; + cr -= 128 << 4; + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + r = 4769 * y + 6537 * cr; + break; + case V4L2_COLORSPACE_SMPTE240M: + r = 4769 * y + 7376 * cr; + break; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + r = 4769 * y + 7343 * cr; + break; + } + return clamp(r >> 12, 0, 0xff0); +} + +static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr) +{ + int g; + + y -= 16 << 4; + cb -= 128 << 4; + cr -= 128 << 4; + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + g = 4769 * y - 1605 * cb - 3330 * cr; + break; + case V4L2_COLORSPACE_SMPTE240M: + g = 4769 * y - 1055 * cb - 2341 * cr; + break; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + g = 4769 * y - 873 * cb - 2183 * cr; + break; + } + return clamp(g >> 12, 0, 0xff0); +} + +static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr) +{ + int b; + + y -= 16 << 4; + cb -= 128 << 4; + cr -= 128 << 4; + switch (tpg->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + b = 4769 * y + 7343 * cb; + break; + case V4L2_COLORSPACE_SMPTE240M: + b = 4769 * y + 8552 * cb; + break; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SRGB: + default: + b = 4769 * y + 8652 * cb; + break; + } + return clamp(b >> 12, 0, 0xff0); +} + +/* precalculate color bar values to speed up rendering */ +static void precalculate_color(struct tpg_data *tpg, int k) +{ + int col = k; + int r = tpg_colors[col].r; + int g = tpg_colors[col].g; + int b = tpg_colors[col].b; + + if (k == TPG_COLOR_TEXTBG) { + col = tpg_get_textbg_color(tpg); + + r = tpg_colors[col].r; + g = tpg_colors[col].g; + b = tpg_colors[col].b; + } else if (k == TPG_COLOR_TEXTFG) { + col = tpg_get_textfg_color(tpg); + + r = tpg_colors[col].r; + g = tpg_colors[col].g; + b = tpg_colors[col].b; + } else if (tpg->pattern == TPG_PAT_NOISE) { + r = g = b = prandom_u32_max(256); + } else if (k == TPG_COLOR_RANDOM) { + r = g = b = tpg->qual_offset + prandom_u32_max(196); + } else if (k >= TPG_COLOR_RAMP) { + r = g = b = k - TPG_COLOR_RAMP; + } + + if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) { + r = tpg_csc_colors[tpg->colorspace][col].r; + g = tpg_csc_colors[tpg->colorspace][col].g; + b = tpg_csc_colors[tpg->colorspace][col].b; + } else { + r <<= 4; + g <<= 4; + b <<= 4; + } + if (tpg->qual == TPG_QUAL_GRAY) + r = g = b = color_to_y(tpg, r, g, b); + + /* + * The assumption is that the RGB output is always full range, + * so only if the rgb_range overrides the 'real' rgb range do + * we need to convert the RGB values. + * + * Currently there is no way of signalling to userspace if you + * are actually giving it limited range RGB (or full range + * YUV for that matter). + * + * Remember that r, g and b are still in the 0 - 0xff0 range. + */ + if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED && + tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) { + /* + * Convert from full range (which is what r, g and b are) + * to limited range (which is the 'real' RGB range), which + * is then interpreted as full range. + */ + r = (r * 219) / 255 + (16 << 4); + g = (g * 219) / 255 + (16 << 4); + b = (b * 219) / 255 + (16 << 4); + } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED && + tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) { + /* + * Clamp r, g and b to the limited range and convert to full + * range since that's what we deliver. + */ + r = clamp(r, 16 << 4, 235 << 4); + g = clamp(g, 16 << 4, 235 << 4); + b = clamp(b, 16 << 4, 235 << 4); + r = (r - (16 << 4)) * 255 / 219; + g = (g - (16 << 4)) * 255 / 219; + b = (b - (16 << 4)) * 255 / 219; + } + + if (tpg->brightness != 128 || tpg->contrast != 128 || + tpg->saturation != 128 || tpg->hue) { + /* Implement these operations */ + + /* First convert to YCbCr */ + int y = color_to_y(tpg, r, g, b); /* Luma */ + int cb = color_to_cb(tpg, r, g, b); /* Cb */ + int cr = color_to_cr(tpg, r, g, b); /* Cr */ + int tmp_cb, tmp_cr; + + y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128; + y += (tpg->brightness << 4) - (128 << 4); + + cb -= 128 << 4; + cr -= 128 << 4; + tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127; + tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127; + + cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128); + cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128); + if (tpg->is_yuv) { + tpg->colors[k][0] = clamp(y >> 4, 1, 254); + tpg->colors[k][1] = clamp(cb >> 4, 1, 254); + tpg->colors[k][2] = clamp(cr >> 4, 1, 254); + return; + } + r = ycbcr_to_r(tpg, y, cb, cr); + g = ycbcr_to_g(tpg, y, cb, cr); + b = ycbcr_to_b(tpg, y, cb, cr); + } + + if (tpg->is_yuv) { + /* Convert to YCbCr */ + u16 y = color_to_y(tpg, r, g, b); /* Luma */ + u16 cb = color_to_cb(tpg, r, g, b); /* Cb */ + u16 cr = color_to_cr(tpg, r, g, b); /* Cr */ + + tpg->colors[k][0] = clamp(y >> 4, 1, 254); + tpg->colors[k][1] = clamp(cb >> 4, 1, 254); + tpg->colors[k][2] = clamp(cr >> 4, 1, 254); + } else { + switch (tpg->fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + r >>= 7; + g >>= 6; + b >>= 7; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_XRGB555: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_RGB555X: + r >>= 7; + g >>= 7; + b >>= 7; + break; + default: + r >>= 4; + g >>= 4; + b >>= 4; + break; + } + + tpg->colors[k][0] = r; + tpg->colors[k][1] = g; + tpg->colors[k][2] = b; + } +} + +static void tpg_precalculate_colors(struct tpg_data *tpg) +{ + int k; + + for (k = 0; k < TPG_COLOR_MAX; k++) + precalculate_color(tpg, k); +} + +/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ +static void gen_twopix(struct tpg_data *tpg, + u8 buf[TPG_MAX_PLANES][8], int color, bool odd) +{ + unsigned offset = odd * tpg->twopixelsize[0] / 2; + u8 alpha = tpg->alpha_component; + u8 r_y, g_u, b_v; + + if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED && + color != TPG_COLOR_100_RED && + color != TPG_COLOR_75_RED) + alpha = 0; + if (color == TPG_COLOR_RANDOM) + precalculate_color(tpg, color); + r_y = tpg->colors[color][0]; /* R or precalculated Y */ + g_u = tpg->colors[color][1]; /* G or precalculated U */ + b_v = tpg->colors[color][2]; /* B or precalculated V */ + + switch (tpg->fourcc) { + case V4L2_PIX_FMT_NV16M: + buf[0][offset] = r_y; + buf[1][offset] = odd ? b_v : g_u; + break; + case V4L2_PIX_FMT_NV61M: + buf[0][offset] = r_y; + buf[1][offset] = odd ? g_u : b_v; + break; + + case V4L2_PIX_FMT_YUYV: + buf[0][offset] = r_y; + buf[0][offset + 1] = odd ? b_v : g_u; + break; + case V4L2_PIX_FMT_UYVY: + buf[0][offset] = odd ? b_v : g_u; + buf[0][offset + 1] = r_y; + break; + case V4L2_PIX_FMT_YVYU: + buf[0][offset] = r_y; + buf[0][offset + 1] = odd ? g_u : b_v; + break; + case V4L2_PIX_FMT_VYUY: + buf[0][offset] = odd ? g_u : b_v; + buf[0][offset + 1] = r_y; + break; + case V4L2_PIX_FMT_RGB565: + buf[0][offset] = (g_u << 5) | b_v; + buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); + break; + case V4L2_PIX_FMT_RGB565X: + buf[0][offset] = (r_y << 3) | (g_u >> 3); + buf[0][offset + 1] = (g_u << 5) | b_v; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_XRGB555: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ARGB555: + buf[0][offset] = (g_u << 5) | b_v; + buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); + break; + case V4L2_PIX_FMT_RGB555X: + buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); + buf[0][offset + 1] = (g_u << 5) | b_v; + break; + case V4L2_PIX_FMT_RGB24: + buf[0][offset] = r_y; + buf[0][offset + 1] = g_u; + buf[0][offset + 2] = b_v; + break; + case V4L2_PIX_FMT_BGR24: + buf[0][offset] = b_v; + buf[0][offset + 1] = g_u; + buf[0][offset + 2] = r_y; + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_XRGB32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ARGB32: + buf[0][offset] = alpha; + buf[0][offset + 1] = r_y; + buf[0][offset + 2] = g_u; + buf[0][offset + 3] = b_v; + break; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XBGR32: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ABGR32: + buf[0][offset] = b_v; + buf[0][offset + 1] = g_u; + buf[0][offset + 2] = r_y; + buf[0][offset + 3] = alpha; + break; + } +} + +/* Return how many pattern lines are used by the current pattern. */ +static unsigned tpg_get_pat_lines(struct tpg_data *tpg) +{ + switch (tpg->pattern) { + case TPG_PAT_CHECKERS_16X16: + case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_ALTERNATING_HLINES: + case TPG_PAT_CROSS_1_PIXEL: + case TPG_PAT_CROSS_2_PIXELS: + case TPG_PAT_CROSS_10_PIXELS: + return 2; + case TPG_PAT_100_COLORSQUARES: + case TPG_PAT_100_HCOLORBAR: + return 8; + default: + return 1; + } +} + +/* Which pattern line should be used for the given frame line. */ +static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) +{ + switch (tpg->pattern) { + case TPG_PAT_CHECKERS_16X16: + return (line >> 4) & 1; + case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_ALTERNATING_HLINES: + return line & 1; + case TPG_PAT_100_COLORSQUARES: + case TPG_PAT_100_HCOLORBAR: + return (line * 8) / tpg->src_height; + case TPG_PAT_CROSS_1_PIXEL: + return line == tpg->src_height / 2; + case TPG_PAT_CROSS_2_PIXELS: + return (line + 1) / 2 == tpg->src_height / 4; + case TPG_PAT_CROSS_10_PIXELS: + return (line + 10) / 20 == tpg->src_height / 40; + default: + return 0; + } +} + +/* + * Which color should be used for the given pattern line and X coordinate. + * Note: x is in the range 0 to 2 * tpg->src_width. + */ +static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x) +{ + /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code + should be modified */ + static const enum tpg_color bars[3][8] = { + /* Standard ITU-R 75% color bar sequence */ + { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW, + TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN, + TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED, + TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, }, + /* Standard ITU-R 100% color bar sequence */ + { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW, + TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN, + TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED, + TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, }, + /* Color bar sequence suitable to test CSC */ + { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW, + TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN, + TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED, + TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, }, + }; + + switch (tpg->pattern) { + case TPG_PAT_75_COLORBAR: + case TPG_PAT_100_COLORBAR: + case TPG_PAT_CSC_COLORBAR: + return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8]; + case TPG_PAT_100_COLORSQUARES: + return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8]; + case TPG_PAT_100_HCOLORBAR: + return bars[1][pat_line]; + case TPG_PAT_BLACK: + return TPG_COLOR_100_BLACK; + case TPG_PAT_WHITE: + return TPG_COLOR_100_WHITE; + case TPG_PAT_RED: + return TPG_COLOR_100_RED; + case TPG_PAT_GREEN: + return TPG_COLOR_100_GREEN; + case TPG_PAT_BLUE: + return TPG_COLOR_100_BLUE; + case TPG_PAT_CHECKERS_16X16: + return (((x >> 4) & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE; + case TPG_PAT_CHECKERS_1X1: + return ((x & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_ALTERNATING_HLINES: + return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_ALTERNATING_VLINES: + return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_CROSS_1_PIXEL: + if (pat_line || (x % tpg->src_width) == tpg->src_width / 2) + return TPG_COLOR_100_BLACK; + return TPG_COLOR_100_WHITE; + case TPG_PAT_CROSS_2_PIXELS: + if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4) + return TPG_COLOR_100_BLACK; + return TPG_COLOR_100_WHITE; + case TPG_PAT_CROSS_10_PIXELS: + if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40) + return TPG_COLOR_100_BLACK; + return TPG_COLOR_100_WHITE; + case TPG_PAT_GRAY_RAMP: + return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width; + default: + return TPG_COLOR_100_RED; + } +} + +/* + * Given the pixel aspect ratio and video aspect ratio calculate the + * coordinates of a centered square and the coordinates of the border of + * the active video area. The coordinates are relative to the source + * frame rectangle. + */ +static void tpg_calculate_square_border(struct tpg_data *tpg) +{ + unsigned w = tpg->src_width; + unsigned h = tpg->src_height; + unsigned sq_w, sq_h; + + sq_w = (w * 2 / 5) & ~1; + if (((w - sq_w) / 2) & 1) + sq_w += 2; + sq_h = sq_w; + tpg->square.width = sq_w; + if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) { + unsigned ana_sq_w = (sq_w / 4) * 3; + + if (((w - ana_sq_w) / 2) & 1) + ana_sq_w += 2; + tpg->square.width = ana_sq_w; + } + tpg->square.left = (w - tpg->square.width) / 2; + if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC) + sq_h = sq_w * 10 / 11; + else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL) + sq_h = sq_w * 59 / 54; + tpg->square.height = sq_h; + tpg->square.top = (h - sq_h) / 2; + tpg->border.left = 0; + tpg->border.width = w; + tpg->border.top = 0; + tpg->border.height = h; + switch (tpg->vid_aspect) { + case TPG_VIDEO_ASPECT_4X3: + if (tpg->pix_aspect) + return; + if (3 * w >= 4 * h) { + tpg->border.width = ((4 * h) / 3) & ~1; + if (((w - tpg->border.width) / 2) & ~1) + tpg->border.width -= 2; + tpg->border.left = (w - tpg->border.width) / 2; + break; + } + tpg->border.height = ((3 * w) / 4) & ~1; + tpg->border.top = (h - tpg->border.height) / 2; + break; + case TPG_VIDEO_ASPECT_14X9_CENTRE: + if (tpg->pix_aspect) { + tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506; + tpg->border.top = (h - tpg->border.height) / 2; + break; + } + if (9 * w >= 14 * h) { + tpg->border.width = ((14 * h) / 9) & ~1; + if (((w - tpg->border.width) / 2) & ~1) + tpg->border.width -= 2; + tpg->border.left = (w - tpg->border.width) / 2; + break; + } + tpg->border.height = ((9 * w) / 14) & ~1; + tpg->border.top = (h - tpg->border.height) / 2; + break; + case TPG_VIDEO_ASPECT_16X9_CENTRE: + if (tpg->pix_aspect) { + tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442; + tpg->border.top = (h - tpg->border.height) / 2; + break; + } + if (9 * w >= 16 * h) { + tpg->border.width = ((16 * h) / 9) & ~1; + if (((w - tpg->border.width) / 2) & ~1) + tpg->border.width -= 2; + tpg->border.left = (w - tpg->border.width) / 2; + break; + } + tpg->border.height = ((9 * w) / 16) & ~1; + tpg->border.top = (h - tpg->border.height) / 2; + break; + default: + break; + } +} + +static void tpg_precalculate_line(struct tpg_data *tpg) +{ + enum tpg_color contrast; + unsigned pat; + unsigned p; + unsigned x; + + switch (tpg->pattern) { + case TPG_PAT_GREEN: + contrast = TPG_COLOR_100_RED; + break; + case TPG_PAT_CSC_COLORBAR: + contrast = TPG_COLOR_CSC_GREEN; + break; + default: + contrast = TPG_COLOR_100_GREEN; + break; + } + + for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) { + /* Coarse scaling with Bresenham */ + unsigned int_part = tpg->src_width / tpg->scaled_width; + unsigned fract_part = tpg->src_width % tpg->scaled_width; + unsigned src_x = 0; + unsigned error = 0; + + for (x = 0; x < tpg->scaled_width * 2; x += 2) { + unsigned real_x = src_x; + enum tpg_color color1, color2; + u8 pix[TPG_MAX_PLANES][8]; + + real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; + color1 = tpg_get_color(tpg, pat, real_x); + + src_x += int_part; + error += fract_part; + if (error >= tpg->scaled_width) { + error -= tpg->scaled_width; + src_x++; + } + + real_x = src_x; + real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; + color2 = tpg_get_color(tpg, pat, real_x); + + src_x += int_part; + error += fract_part; + if (error >= tpg->scaled_width) { + error -= tpg->scaled_width; + src_x++; + } + + gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0); + gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2; + + memcpy(pos, pix[p], twopixsize); + } + } + } + for (x = 0; x < tpg->scaled_width; x += 2) { + u8 pix[TPG_MAX_PLANES][8]; + + gen_twopix(tpg, pix, contrast, 0); + gen_twopix(tpg, pix, contrast, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2; + + memcpy(pos, pix[p], twopixsize); + } + } + for (x = 0; x < tpg->scaled_width; x += 2) { + u8 pix[TPG_MAX_PLANES][8]; + + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->black_line[p] + x * twopixsize / 2; + + memcpy(pos, pix[p], twopixsize); + } + } + for (x = 0; x < tpg->scaled_width * 2; x += 2) { + u8 pix[TPG_MAX_PLANES][8]; + + gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); + gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->random_line[p] + x * twopixsize / 2; + + memcpy(pos, pix[p], twopixsize); + } + } + gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); + gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); + gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); + gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1); +} + +/* need this to do rgb24 rendering */ +typedef struct { u16 __; u8 _; } __packed x24; + +void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + int y, int x, char *text) +{ + int line; + unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; + unsigned div = step; + unsigned first = 0; + unsigned len = strlen(text); + unsigned p; + + if (font8x16 == NULL || basep == NULL) + return; + + /* Checks if it is possible to show string */ + if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) + return; + + if (len > (tpg->compose.width - x) / 8) + len = (tpg->compose.width - x) / 8; + if (tpg->vflip) + y = tpg->compose.height - y - 16; + if (tpg->hflip) + x = tpg->compose.width - x - 8; + y += tpg->compose.top; + x += tpg->compose.left; + if (tpg->field == V4L2_FIELD_BOTTOM) + first = 1; + else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT) + div = 2; + + for (p = 0; p < tpg->planes; p++) { + /* Print stream time */ +#define PRINTSTR(PIXTYPE) do { \ + PIXTYPE fg; \ + PIXTYPE bg; \ + memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ + memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \ + \ + for (line = first; line < 16; line += step) { \ + int l = tpg->vflip ? 15 - line : line; \ + PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \ + ((y * step + l) / div) * tpg->bytesperline[p] + \ + x * sizeof(PIXTYPE)); \ + unsigned s; \ + \ + for (s = 0; s < len; s++) { \ + u8 chr = font8x16[text[s] * 16 + line]; \ + \ + if (tpg->hflip) { \ + pos[7] = (chr & (0x01 << 7) ? fg : bg); \ + pos[6] = (chr & (0x01 << 6) ? fg : bg); \ + pos[5] = (chr & (0x01 << 5) ? fg : bg); \ + pos[4] = (chr & (0x01 << 4) ? fg : bg); \ + pos[3] = (chr & (0x01 << 3) ? fg : bg); \ + pos[2] = (chr & (0x01 << 2) ? fg : bg); \ + pos[1] = (chr & (0x01 << 1) ? fg : bg); \ + pos[0] = (chr & (0x01 << 0) ? fg : bg); \ + } else { \ + pos[0] = (chr & (0x01 << 7) ? fg : bg); \ + pos[1] = (chr & (0x01 << 6) ? fg : bg); \ + pos[2] = (chr & (0x01 << 5) ? fg : bg); \ + pos[3] = (chr & (0x01 << 4) ? fg : bg); \ + pos[4] = (chr & (0x01 << 3) ? fg : bg); \ + pos[5] = (chr & (0x01 << 2) ? fg : bg); \ + pos[6] = (chr & (0x01 << 1) ? fg : bg); \ + pos[7] = (chr & (0x01 << 0) ? fg : bg); \ + } \ + \ + pos += tpg->hflip ? -8 : 8; \ + } \ + } \ +} while (0) + + switch (tpg->twopixelsize[p]) { + case 2: + PRINTSTR(u8); break; + case 4: + PRINTSTR(u16); break; + case 6: + PRINTSTR(x24); break; + case 8: + PRINTSTR(u32); break; + } + } +} + +void tpg_update_mv_step(struct tpg_data *tpg) +{ + int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1; + + if (tpg->hflip) + factor = -factor; + switch (tpg->mv_hor_mode) { + case TPG_MOVE_NEG_FAST: + case TPG_MOVE_POS_FAST: + tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4; + break; + case TPG_MOVE_NEG: + case TPG_MOVE_POS: + tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4; + break; + case TPG_MOVE_NEG_SLOW: + case TPG_MOVE_POS_SLOW: + tpg->mv_hor_step = 2; + break; + case TPG_MOVE_NONE: + tpg->mv_hor_step = 0; + break; + } + if (factor < 0) + tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step; + + factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1; + switch (tpg->mv_vert_mode) { + case TPG_MOVE_NEG_FAST: + case TPG_MOVE_POS_FAST: + tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4; + break; + case TPG_MOVE_NEG: + case TPG_MOVE_POS: + tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4; + break; + case TPG_MOVE_NEG_SLOW: + case TPG_MOVE_POS_SLOW: + tpg->mv_vert_step = 1; + break; + case TPG_MOVE_NONE: + tpg->mv_vert_step = 0; + break; + } + if (factor < 0) + tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step; +} + +/* Map the line number relative to the crop rectangle to a frame line number */ +static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, + unsigned field) +{ + switch (field) { + case V4L2_FIELD_TOP: + return tpg->crop.top + src_y * 2; + case V4L2_FIELD_BOTTOM: + return tpg->crop.top + src_y * 2 + 1; + default: + return src_y + tpg->crop.top; + } +} + +/* + * Map the line number relative to the compose rectangle to a destination + * buffer line number. + */ +static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y, + unsigned field) +{ + y += tpg->compose.top; + switch (field) { + case V4L2_FIELD_SEQ_TB: + if (y & 1) + return tpg->buf_height / 2 + y / 2; + return y / 2; + case V4L2_FIELD_SEQ_BT: + if (y & 1) + return y / 2; + return tpg->buf_height / 2 + y / 2; + default: + return y; + } +} + +static void tpg_recalc(struct tpg_data *tpg) +{ + if (tpg->recalc_colors) { + tpg->recalc_colors = false; + tpg->recalc_lines = true; + tpg_precalculate_colors(tpg); + } + if (tpg->recalc_square_border) { + tpg->recalc_square_border = false; + tpg_calculate_square_border(tpg); + } + if (tpg->recalc_lines) { + tpg->recalc_lines = false; + tpg_precalculate_line(tpg); + } +} + +void tpg_calc_text_basep(struct tpg_data *tpg, + u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) +{ + unsigned stride = tpg->bytesperline[p]; + + tpg_recalc(tpg); + + basep[p][0] = vbuf; + basep[p][1] = vbuf; + if (tpg->field == V4L2_FIELD_SEQ_TB) + basep[p][1] += tpg->buf_height * stride / 2; + else if (tpg->field == V4L2_FIELD_SEQ_BT) + basep[p][0] += tpg->buf_height * stride / 2; +} + +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +{ + bool is_tv = std; + bool is_60hz = is_tv && (std & V4L2_STD_525_60); + unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width; + unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width; + unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height; + unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; + unsigned wss_width; + unsigned f; + int hmax = (tpg->compose.height * tpg->perc_fill) / 100; + int h; + unsigned twopixsize = tpg->twopixelsize[p]; + unsigned img_width = tpg->compose.width * twopixsize / 2; + unsigned line_offset; + unsigned left_pillar_width = 0; + unsigned right_pillar_start = img_width; + unsigned stride = tpg->bytesperline[p]; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; + u8 *orig_vbuf = vbuf; + + /* Coarse scaling with Bresenham */ + unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; + unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; + unsigned src_y = 0; + unsigned error = 0; + + tpg_recalc(tpg); + + mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1; + mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1; + wss_width = tpg->crop.left < tpg->src_width / 2 ? + tpg->src_width / 2 - tpg->crop.left : 0; + if (wss_width > tpg->crop.width) + wss_width = tpg->crop.width; + wss_width = wss_width * tpg->scaled_width / tpg->src_width; + + vbuf += tpg->compose.left * twopixsize / 2; + line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; + line_offset = (line_offset & ~1) * twopixsize / 2; + if (tpg->crop.left < tpg->border.left) { + left_pillar_width = tpg->border.left - tpg->crop.left; + if (left_pillar_width > tpg->crop.width) + left_pillar_width = tpg->crop.width; + left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; + left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2; + } + if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { + right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; + right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; + right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2; + if (right_pillar_start > img_width) + right_pillar_start = img_width; + } + + f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + + for (h = 0; h < tpg->compose.height; h++) { + bool even; + bool fill_blank = false; + unsigned frame_line; + unsigned buf_line; + unsigned pat_line_old; + unsigned pat_line_new; + u8 *linestart_older; + u8 *linestart_newer; + u8 *linestart_top; + u8 *linestart_bottom; + + frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); + even = !(frame_line & 1); + buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); + src_y += int_part; + error += fract_part; + if (error >= tpg->compose.height) { + error -= tpg->compose.height; + src_y++; + } + + if (h >= hmax) { + if (hmax == tpg->compose.height) + continue; + if (!tpg->perc_fill_blank) + continue; + fill_blank = true; + } + + if (tpg->vflip) + frame_line = tpg->src_height - frame_line - 1; + + if (fill_blank) { + linestart_older = tpg->contrast_line[p]; + linestart_newer = tpg->contrast_line[p]; + } else if (tpg->qual != TPG_QUAL_NOISE && + (frame_line < tpg->border.top || + frame_line >= tpg->border.top + tpg->border.height)) { + linestart_older = tpg->black_line[p]; + linestart_newer = tpg->black_line[p]; + } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { + linestart_older = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + linestart_newer = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + } else { + pat_line_old = tpg_get_pat_line(tpg, + (frame_line + mv_vert_old) % tpg->src_height); + pat_line_new = tpg_get_pat_line(tpg, + (frame_line + mv_vert_new) % tpg->src_height); + linestart_older = tpg->lines[pat_line_old][p] + + mv_hor_old * twopixsize / 2; + linestart_newer = tpg->lines[pat_line_new][p] + + mv_hor_new * twopixsize / 2; + linestart_older += line_offset; + linestart_newer += line_offset; + } + if (is_60hz) { + linestart_top = linestart_newer; + linestart_bottom = linestart_older; + } else { + linestart_top = linestart_older; + linestart_bottom = linestart_newer; + } + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + if (even) + memcpy(vbuf + buf_line * stride, linestart_top, img_width); + else + memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); + break; + case V4L2_FIELD_INTERLACED_BT: + if (even) + memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); + else + memcpy(vbuf + buf_line * stride, linestart_top, img_width); + break; + case V4L2_FIELD_TOP: + memcpy(vbuf + buf_line * stride, linestart_top, img_width); + break; + case V4L2_FIELD_BOTTOM: + memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); + break; + case V4L2_FIELD_NONE: + default: + memcpy(vbuf + buf_line * stride, linestart_older, img_width); + break; + } + + if (is_tv && !is_60hz && frame_line == 0 && wss_width) { + /* + * Replace the first half of the top line of a 50 Hz frame + * with random data to simulate a WSS signal. + */ + u8 *wss = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + + memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2); + } + } + + vbuf = orig_vbuf; + vbuf += tpg->compose.left * twopixsize / 2; + src_y = 0; + error = 0; + for (h = 0; h < tpg->compose.height; h++) { + unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); + unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); + const struct v4l2_rect *sq = &tpg->square; + const struct v4l2_rect *b = &tpg->border; + const struct v4l2_rect *c = &tpg->crop; + + src_y += int_part; + error += fract_part; + if (error >= tpg->compose.height) { + error -= tpg->compose.height; + src_y++; + } + + if (tpg->show_border && frame_line >= b->top && + frame_line < b->top + b->height) { + unsigned bottom = b->top + b->height - 1; + unsigned left = left_pillar_width; + unsigned right = right_pillar_start; + + if (frame_line == b->top || frame_line == b->top + 1 || + frame_line == bottom || frame_line == bottom - 1) { + memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], + right - left); + } else { + if (b->left >= c->left && + b->left < c->left + c->width) + memcpy(vbuf + buf_line * stride + left, + tpg->contrast_line[p], twopixsize); + if (b->left + b->width > c->left && + b->left + b->width <= c->left + c->width) + memcpy(vbuf + buf_line * stride + right - twopixsize, + tpg->contrast_line[p], twopixsize); + } + } + if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && + frame_line < b->top + b->height) { + memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width); + memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p], + img_width - right_pillar_start); + } + if (tpg->show_square && frame_line >= sq->top && + frame_line < sq->top + sq->height && + sq->left < c->left + c->width && + sq->left + sq->width >= c->left) { + unsigned left = sq->left; + unsigned width = sq->width; + + if (c->left > left) { + width -= c->left - left; + left = c->left; + } + if (c->left + c->width < left + width) + width -= left + width - c->left - c->width; + left -= c->left; + left = (left * tpg->scaled_width) / tpg->src_width; + left = (left & ~1) * twopixsize / 2; + width = (width * tpg->scaled_width) / tpg->src_width; + width = (width & ~1) * twopixsize / 2; + memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); + } + if (tpg->insert_sav) { + unsigned offset = (tpg->compose.width / 6) * twopixsize; + u8 *p = vbuf + buf_line * stride + offset; + unsigned vact = 0, hact = 0; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ f) << 2) | + ((f ^ vact) << 1) | + (hact ^ vact ^ f); + } + if (tpg->insert_eav) { + unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize; + u8 *p = vbuf + buf_line * stride + offset; + unsigned vact = 0, hact = 1; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ f) << 2) | + ((f ^ vact) << 1) | + (hact ^ vact ^ f); + } + } +} diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h new file mode 100644 index 000000000000..51ef7d1253c9 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -0,0 +1,438 @@ +/* + * vivid-tpg.h - Test Pattern Generator + * + * Copyright 2014 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 _VIVID_TPG_H_ +#define _VIVID_TPG_H_ + +#include +#include +#include +#include +#include +#include + +#include "vivid-tpg-colors.h" + +enum tpg_pattern { + TPG_PAT_75_COLORBAR, + TPG_PAT_100_COLORBAR, + TPG_PAT_CSC_COLORBAR, + TPG_PAT_100_HCOLORBAR, + TPG_PAT_100_COLORSQUARES, + TPG_PAT_BLACK, + TPG_PAT_WHITE, + TPG_PAT_RED, + TPG_PAT_GREEN, + TPG_PAT_BLUE, + TPG_PAT_CHECKERS_16X16, + TPG_PAT_CHECKERS_1X1, + TPG_PAT_ALTERNATING_HLINES, + TPG_PAT_ALTERNATING_VLINES, + TPG_PAT_CROSS_1_PIXEL, + TPG_PAT_CROSS_2_PIXELS, + TPG_PAT_CROSS_10_PIXELS, + TPG_PAT_GRAY_RAMP, + + /* Must be the last pattern */ + TPG_PAT_NOISE, +}; + +extern const char * const tpg_pattern_strings[]; + +enum tpg_quality { + TPG_QUAL_COLOR, + TPG_QUAL_GRAY, + TPG_QUAL_NOISE +}; + +enum tpg_video_aspect { + TPG_VIDEO_ASPECT_IMAGE, + TPG_VIDEO_ASPECT_4X3, + TPG_VIDEO_ASPECT_14X9_CENTRE, + TPG_VIDEO_ASPECT_16X9_CENTRE, + TPG_VIDEO_ASPECT_16X9_ANAMORPHIC, +}; + +enum tpg_pixel_aspect { + TPG_PIXEL_ASPECT_SQUARE, + TPG_PIXEL_ASPECT_NTSC, + TPG_PIXEL_ASPECT_PAL, +}; + +enum tpg_move_mode { + TPG_MOVE_NEG_FAST, + TPG_MOVE_NEG, + TPG_MOVE_NEG_SLOW, + TPG_MOVE_NONE, + TPG_MOVE_POS_SLOW, + TPG_MOVE_POS, + TPG_MOVE_POS_FAST, +}; + +extern const char * const tpg_aspect_strings[]; + +#define TPG_MAX_PLANES 2 +#define TPG_MAX_PAT_LINES 8 + +struct tpg_data { + /* Source frame size */ + unsigned src_width, src_height; + /* Buffer height */ + unsigned buf_height; + /* Scaled output frame size */ + unsigned scaled_width; + u32 field; + /* crop coordinates are frame-based */ + struct v4l2_rect crop; + /* compose coordinates are format-based */ + struct v4l2_rect compose; + /* border and square coordinates are frame-based */ + struct v4l2_rect border; + struct v4l2_rect square; + + /* Color-related fields */ + enum tpg_quality qual; + unsigned qual_offset; + u8 alpha_component; + bool alpha_red_only; + u8 brightness; + u8 contrast; + u8 saturation; + s16 hue; + u32 fourcc; + bool is_yuv; + u32 colorspace; + enum tpg_video_aspect vid_aspect; + enum tpg_pixel_aspect pix_aspect; + unsigned rgb_range; + unsigned real_rgb_range; + unsigned planes; + /* Used to store the colors in native format, either RGB or YUV */ + u8 colors[TPG_COLOR_MAX][3]; + u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; + /* size in bytes for two pixels in each plane */ + unsigned twopixelsize[TPG_MAX_PLANES]; + unsigned bytesperline[TPG_MAX_PLANES]; + + /* Configuration */ + enum tpg_pattern pattern; + bool hflip; + bool vflip; + unsigned perc_fill; + bool perc_fill_blank; + bool show_border; + bool show_square; + bool insert_sav; + bool insert_eav; + + /* Test pattern movement */ + enum tpg_move_mode mv_hor_mode; + int mv_hor_count; + int mv_hor_step; + enum tpg_move_mode mv_vert_mode; + int mv_vert_count; + int mv_vert_step; + + bool recalc_colors; + bool recalc_lines; + bool recalc_square_border; + + /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ + unsigned max_line_width; + u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; + u8 *random_line[TPG_MAX_PLANES]; + u8 *contrast_line[TPG_MAX_PLANES]; + u8 *black_line[TPG_MAX_PLANES]; +}; + +void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h); +int tpg_alloc(struct tpg_data *tpg, unsigned max_w); +void tpg_free(struct tpg_data *tpg); +void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, + u32 field); + +void tpg_set_font(const u8 *f); +void tpg_gen_text(struct tpg_data *tpg, + u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); +void tpg_calc_text_basep(struct tpg_data *tpg, + u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); +bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); +void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, + const struct v4l2_rect *compose); + +static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern) +{ + if (tpg->pattern == pattern) + return; + tpg->pattern = pattern; + tpg->recalc_colors = true; +} + +static inline void tpg_s_quality(struct tpg_data *tpg, + enum tpg_quality qual, unsigned qual_offset) +{ + if (tpg->qual == qual && tpg->qual_offset == qual_offset) + return; + tpg->qual = qual; + tpg->qual_offset = qual_offset; + tpg->recalc_colors = true; +} + +static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg) +{ + return tpg->qual; +} + +static inline void tpg_s_alpha_component(struct tpg_data *tpg, + u8 alpha_component) +{ + if (tpg->alpha_component == alpha_component) + return; + tpg->alpha_component = alpha_component; + tpg->recalc_colors = true; +} + +static inline void tpg_s_alpha_mode(struct tpg_data *tpg, + bool red_only) +{ + if (tpg->alpha_red_only == red_only) + return; + tpg->alpha_red_only = red_only; + tpg->recalc_colors = true; +} + +static inline void tpg_s_brightness(struct tpg_data *tpg, + u8 brightness) +{ + if (tpg->brightness == brightness) + return; + tpg->brightness = brightness; + tpg->recalc_colors = true; +} + +static inline void tpg_s_contrast(struct tpg_data *tpg, + u8 contrast) +{ + if (tpg->contrast == contrast) + return; + tpg->contrast = contrast; + tpg->recalc_colors = true; +} + +static inline void tpg_s_saturation(struct tpg_data *tpg, + u8 saturation) +{ + if (tpg->saturation == saturation) + return; + tpg->saturation = saturation; + tpg->recalc_colors = true; +} + +static inline void tpg_s_hue(struct tpg_data *tpg, + s16 hue) +{ + if (tpg->hue == hue) + return; + tpg->hue = hue; + tpg->recalc_colors = true; +} + +static inline void tpg_s_rgb_range(struct tpg_data *tpg, + unsigned rgb_range) +{ + if (tpg->rgb_range == rgb_range) + return; + tpg->rgb_range = rgb_range; + tpg->recalc_colors = true; +} + +static inline void tpg_s_real_rgb_range(struct tpg_data *tpg, + unsigned rgb_range) +{ + if (tpg->real_rgb_range == rgb_range) + return; + tpg->real_rgb_range = rgb_range; + tpg->recalc_colors = true; +} + +static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace) +{ + if (tpg->colorspace == colorspace) + return; + tpg->colorspace = colorspace; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_colorspace(const struct tpg_data *tpg) +{ + return tpg->colorspace; +} + +static inline unsigned tpg_g_planes(const struct tpg_data *tpg) +{ + return tpg->planes; +} + +static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) +{ + return tpg->twopixelsize[plane]; +} + +static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) +{ + return tpg->bytesperline[plane]; +} + +static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) +{ + tpg->bytesperline[plane] = bpl; +} + +static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) +{ + tpg->buf_height = h; +} + +static inline void tpg_s_field(struct tpg_data *tpg, unsigned field) +{ + tpg->field = field; +} + +static inline void tpg_s_perc_fill(struct tpg_data *tpg, + unsigned perc_fill) +{ + tpg->perc_fill = perc_fill; +} + +static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg) +{ + return tpg->perc_fill; +} + +static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg, + bool perc_fill_blank) +{ + tpg->perc_fill_blank = perc_fill_blank; +} + +static inline void tpg_s_video_aspect(struct tpg_data *tpg, + enum tpg_video_aspect vid_aspect) +{ + if (tpg->vid_aspect == vid_aspect) + return; + tpg->vid_aspect = vid_aspect; + tpg->recalc_square_border = true; +} + +static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg) +{ + return tpg->vid_aspect; +} + +static inline void tpg_s_pixel_aspect(struct tpg_data *tpg, + enum tpg_pixel_aspect pix_aspect) +{ + if (tpg->pix_aspect == pix_aspect) + return; + tpg->pix_aspect = pix_aspect; + tpg->recalc_square_border = true; +} + +static inline void tpg_s_show_border(struct tpg_data *tpg, + bool show_border) +{ + tpg->show_border = show_border; +} + +static inline void tpg_s_show_square(struct tpg_data *tpg, + bool show_square) +{ + tpg->show_square = show_square; +} + +static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav) +{ + tpg->insert_sav = insert_sav; +} + +static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav) +{ + tpg->insert_eav = insert_eav; +} + +void tpg_update_mv_step(struct tpg_data *tpg); + +static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg, + enum tpg_move_mode mv_hor_mode) +{ + tpg->mv_hor_mode = mv_hor_mode; + tpg_update_mv_step(tpg); +} + +static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg, + enum tpg_move_mode mv_vert_mode) +{ + tpg->mv_vert_mode = mv_vert_mode; + tpg_update_mv_step(tpg); +} + +static inline void tpg_init_mv_count(struct tpg_data *tpg) +{ + tpg->mv_hor_count = tpg->mv_vert_count = 0; +} + +static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field) +{ + tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2); + tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2); +} + +static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip) +{ + if (tpg->hflip == hflip) + return; + tpg->hflip = hflip; + tpg_update_mv_step(tpg); + tpg->recalc_lines = true; +} + +static inline bool tpg_g_hflip(const struct tpg_data *tpg) +{ + return tpg->hflip; +} + +static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip) +{ + tpg->vflip = vflip; +} + +static inline bool tpg_g_vflip(const struct tpg_data *tpg) +{ + return tpg->vflip; +} + +static inline bool tpg_pattern_is_static(const struct tpg_data *tpg) +{ + return tpg->pattern != TPG_PAT_NOISE && + tpg->mv_hor_mode == TPG_MOVE_NONE && + tpg->mv_vert_mode == TPG_MOVE_NONE; +} + +#endif -- cgit v1.2.3 From 55d58e989856aa7506001c4ecfc7920f5232bbd1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:02:56 -0300 Subject: [media] vivid: add support for radio receivers and transmitters This adds radio receiver and transmitter support. Part of that is common to both and so is placed in the radio-common source. These drivers also support RDS. In order to generate valid RDS data a simple RDS generator is implemented in rds-gen. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-radio-common.c | 189 ++++++++++++++ drivers/media/platform/vivid/vivid-radio-common.h | 40 +++ drivers/media/platform/vivid/vivid-radio-rx.c | 287 ++++++++++++++++++++++ drivers/media/platform/vivid/vivid-radio-rx.h | 31 +++ drivers/media/platform/vivid/vivid-radio-tx.c | 141 +++++++++++ drivers/media/platform/vivid/vivid-radio-tx.h | 29 +++ drivers/media/platform/vivid/vivid-rds-gen.c | 165 +++++++++++++ drivers/media/platform/vivid/vivid-rds-gen.h | 53 ++++ 8 files changed, 935 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-radio-common.c create mode 100644 drivers/media/platform/vivid/vivid-radio-common.h create mode 100644 drivers/media/platform/vivid/vivid-radio-rx.c create mode 100644 drivers/media/platform/vivid/vivid-radio-rx.h create mode 100644 drivers/media/platform/vivid/vivid-radio-tx.c create mode 100644 drivers/media/platform/vivid/vivid-radio-tx.h create mode 100644 drivers/media/platform/vivid/vivid-rds-gen.c create mode 100644 drivers/media/platform/vivid/vivid-rds-gen.h diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c new file mode 100644 index 000000000000..78c1e920670a --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-common.c @@ -0,0 +1,189 @@ +/* + * vivid-radio-common.c - common radio rx/tx support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-rds-gen.h" + +/* + * These functions are shared between the vivid receiver and transmitter + * since both use the same frequency bands. + */ + +const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = { + /* Band FM */ + { + .type = V4L2_TUNER_RADIO, + .index = 0, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = FM_FREQ_RANGE_LOW, + .rangehigh = FM_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_FM, + }, + /* Band AM */ + { + .type = V4L2_TUNER_RADIO, + .index = 1, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = AM_FREQ_RANGE_LOW, + .rangehigh = AM_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_AM, + }, + /* Band SW */ + { + .type = V4L2_TUNER_RADIO, + .index = 2, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = SW_FREQ_RANGE_LOW, + .rangehigh = SW_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +/* + * Initialize the RDS generator. If we can loop, then the RDS generator + * is set up with the values from the RDS TX controls, otherwise it + * will fill in standard values using one of two alternates. + */ +void vivid_radio_rds_init(struct vivid_dev *dev) +{ + struct vivid_rds_gen *rds = &dev->rds_gen; + bool alt = dev->radio_rx_rds_use_alternates; + + /* Do nothing, blocks will be filled by the transmitter */ + if (dev->radio_rds_loop && !dev->radio_tx_rds_controls) + return; + + if (dev->radio_rds_loop) { + v4l2_ctrl_lock(dev->radio_tx_rds_pi); + rds->picode = dev->radio_tx_rds_pi->cur.val; + rds->pty = dev->radio_tx_rds_pty->cur.val; + rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val; + rds->art_head = dev->radio_tx_rds_art_head->cur.val; + rds->compressed = dev->radio_tx_rds_compressed->cur.val; + rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val; + rds->ta = dev->radio_tx_rds_ta->cur.val; + rds->tp = dev->radio_tx_rds_tp->cur.val; + rds->ms = dev->radio_tx_rds_ms->cur.val; + strlcpy(rds->psname, + dev->radio_tx_rds_psname->p_cur.p_char, + sizeof(rds->psname)); + strlcpy(rds->radiotext, + dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64, + sizeof(rds->radiotext)); + v4l2_ctrl_unlock(dev->radio_tx_rds_pi); + } else { + vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt); + } + if (dev->radio_rx_rds_controls) { + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms); + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname); + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext); + if (!dev->radio_rds_loop) + dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates; + } + vivid_rds_generate(rds); +} + +/* + * Calculate the emulated signal quality taking into account the frequency + * the transmitter is using. + */ +static void vivid_radio_calc_sig_qual(struct vivid_dev *dev) +{ + int mod = 16000; + int delta = 800; + int sig_qual, sig_qual_tx = mod; + + /* + * For SW and FM there is a channel every 1000 kHz, for AM there is one + * every 100 kHz. + */ + if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) { + mod /= 10; + delta /= 10; + } + sig_qual = (dev->radio_rx_freq + delta) % mod - delta; + if (dev->has_radio_tx) + sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq; + if (abs(sig_qual_tx) <= abs(sig_qual)) { + sig_qual = sig_qual_tx; + /* + * Zero the internal rds buffer if we are going to loop + * rds blocks. + */ + if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls) + memset(dev->rds_gen.data, 0, + sizeof(dev->rds_gen.data)); + dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW; + } else { + dev->radio_rds_loop = false; + } + if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) + sig_qual *= 10; + dev->radio_rx_sig_qual = sig_qual; +} + +int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf) +{ + if (vf->tuner != 0) + return -EINVAL; + vf->frequency = *pfreq; + return 0; +} + +int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned freq; + unsigned band; + + if (vf->tuner != 0) + return -EINVAL; + + if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2) + band = BAND_FM; + else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2) + band = BAND_AM; + else + band = BAND_SW; + + freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow, + vivid_radio_bands[band].rangehigh); + *pfreq = freq; + + /* + * For both receiver and transmitter recalculate the signal quality + * (since that depends on both frequencies) and re-init the rds + * generator. + */ + vivid_radio_calc_sig_qual(dev); + vivid_radio_rds_init(dev); + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h new file mode 100644 index 000000000000..92fe589141b7 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-common.h @@ -0,0 +1,40 @@ +/* + * vivid-radio-common.h - common radio rx/tx support functions. + * + * Copyright 2014 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 _VIVID_RADIO_COMMON_H_ +#define _VIVID_RADIO_COMMON_H_ + +/* The supported radio frequency ranges in kHz */ +#define FM_FREQ_RANGE_LOW (64000U * 16U) +#define FM_FREQ_RANGE_HIGH (108000U * 16U) +#define AM_FREQ_RANGE_LOW (520U * 16U) +#define AM_FREQ_RANGE_HIGH (1710U * 16U) +#define SW_FREQ_RANGE_LOW (2300U * 16U) +#define SW_FREQ_RANGE_HIGH (26100U * 16U) + +enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS }; + +extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS]; + +int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf); +int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf); + +void vivid_radio_rds_init(struct vivid_dev *dev); + +#endif diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c new file mode 100644 index 000000000000..c7651a506668 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -0,0 +1,287 @@ +/* + * vivid-radio-rx.c - radio receiver support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-rds-gen.h" +#include "vivid-radio-rx.h" + +ssize_t vivid_radio_rx_read(struct file *file, char __user *buf, + size_t size, loff_t *offset) +{ + struct vivid_dev *dev = video_drvdata(file); + struct timespec ts; + struct v4l2_rds_data *data = dev->rds_gen.data; + bool use_alternates; + unsigned blk; + int perc; + int i; + + if (dev->radio_rx_rds_controls) + return -EINVAL; + if (size < sizeof(*data)) + return 0; + size = sizeof(*data) * (size / sizeof(*data)); + + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + if (dev->radio_rx_rds_owner && + file->private_data != dev->radio_rx_rds_owner) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + if (dev->radio_rx_rds_owner == NULL) { + vivid_radio_rds_init(dev); + dev->radio_rx_rds_owner = file->private_data; + } + +retry: + ktime_get_ts(&ts); + use_alternates = ts.tv_sec % 10 >= 5; + if (dev->radio_rx_rds_last_block == 0 || + dev->radio_rx_rds_use_alternates != use_alternates) { + dev->radio_rx_rds_use_alternates = use_alternates; + /* Re-init the RDS generator */ + vivid_radio_rds_init(dev); + } + ts = timespec_sub(ts, dev->radio_rds_init_ts); + blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000; + blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500; + if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS) + dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; + + /* + * No data is available if there hasn't been time to get new data, + * or if the RDS receiver has been disabled, or if we use the data + * from the RDS transmitter and that RDS transmitter has been disabled, + * or if the signal quality is too weak. + */ + if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled || + (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) || + abs(dev->radio_rx_sig_qual) > 200) { + mutex_unlock(&dev->mutex); + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (msleep_interruptible(20) && signal_pending(current)) + return -EINTR; + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + goto retry; + } + + /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */ + perc = abs(dev->radio_rx_sig_qual) / 4; + + for (i = 0; i < size && blk > dev->radio_rx_rds_last_block; + dev->radio_rx_rds_last_block++) { + unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS; + struct v4l2_rds_data rds = data[data_blk]; + + if (data_blk == 0 && dev->radio_rds_loop) + vivid_radio_rds_init(dev); + if (perc && prandom_u32_max(100) < perc) { + switch (prandom_u32_max(4)) { + case 0: + rds.block |= V4L2_RDS_BLOCK_CORRECTED; + break; + case 1: + rds.block |= V4L2_RDS_BLOCK_INVALID; + break; + case 2: + rds.block |= V4L2_RDS_BLOCK_ERROR; + rds.lsb = prandom_u32_max(256); + rds.msb = prandom_u32_max(256); + break; + case 3: /* Skip block altogether */ + if (i) + continue; + /* + * Must make sure at least one block is + * returned, otherwise the application + * might think that end-of-file occurred. + */ + break; + } + } + if (copy_to_user(buf + i, &rds, sizeof(rds))) { + i = -EFAULT; + break; + } + i += sizeof(rds); + } + mutex_unlock(&dev->mutex); + return i; +} + +unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait) +{ + return POLLIN | POLLRDNORM | v4l2_ctrl_poll(file, wait); +} + +int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +{ + if (band->tuner != 0) + return -EINVAL; + + if (band->index >= TOT_BANDS) + return -EINVAL; + + *band = vivid_radio_bands[band->index]; + return 0; +} + +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned low, high; + unsigned freq; + unsigned spacing; + unsigned band; + + if (a->tuner) + return -EINVAL; + if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED) + return -EINVAL; + + if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP) + return -EINVAL; + if (!a->rangelow ^ !a->rangehigh) + return -EINVAL; + + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + if (a->rangelow) { + for (band = 0; band < TOT_BANDS; band++) + if (a->rangelow >= vivid_radio_bands[band].rangelow && + a->rangehigh <= vivid_radio_bands[band].rangehigh) + break; + if (band == TOT_BANDS) + return -EINVAL; + if (!dev->radio_rx_hw_seek_prog_lim && + (a->rangelow != vivid_radio_bands[band].rangelow || + a->rangehigh != vivid_radio_bands[band].rangehigh)) + return -EINVAL; + low = a->rangelow; + high = a->rangehigh; + } else { + for (band = 0; band < TOT_BANDS; band++) + if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow && + dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh) + break; + low = vivid_radio_bands[band].rangelow; + high = vivid_radio_bands[band].rangehigh; + } + spacing = band == BAND_AM ? 1600 : 16000; + freq = clamp(dev->radio_rx_freq, low, high); + + if (a->seek_upward) { + freq = spacing * (freq / spacing) + spacing; + if (freq > high) { + if (!a->wrap_around) + return -ENODATA; + freq = spacing * (low / spacing) + spacing; + if (freq >= dev->radio_rx_freq) + return -ENODATA; + } + } else { + freq = spacing * ((freq + spacing - 1) / spacing) - spacing; + if (freq < low) { + if (!a->wrap_around) + return -ENODATA; + freq = spacing * ((high + spacing - 1) / spacing) - spacing; + if (freq <= dev->radio_rx_freq) + return -ENODATA; + } + } + return 0; +} + +int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + int delta = 800; + int sig_qual; + + if (vt->index > 0) + return -EINVAL; + + strlcpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name)); + vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | + (dev->radio_rx_rds_controls ? + V4L2_TUNER_CAP_RDS_CONTROLS : + V4L2_TUNER_CAP_RDS_BLOCK_IO) | + (dev->radio_rx_hw_seek_prog_lim ? + V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0); + switch (dev->radio_rx_hw_seek_mode) { + case VIVID_HW_SEEK_BOUNDED: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED; + break; + case VIVID_HW_SEEK_WRAP: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP; + break; + case VIVID_HW_SEEK_BOTH: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP | + V4L2_TUNER_CAP_HWSEEK_BOUNDED; + break; + } + vt->rangelow = AM_FREQ_RANGE_LOW; + vt->rangehigh = FM_FREQ_RANGE_HIGH; + sig_qual = dev->radio_rx_sig_qual; + vt->signal = abs(sig_qual) > delta ? 0 : + 0xffff - (abs(sig_qual) * 0xffff) / delta; + vt->afc = sig_qual > delta ? 0 : sig_qual; + if (abs(sig_qual) > delta) + vt->rxsubchans = 0; + else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000) + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO)) + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + else + vt->rxsubchans = V4L2_TUNER_SUB_STEREO; + if (dev->radio_rx_rds_enabled && + (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) && + dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000) + vt->rxsubchans |= V4L2_TUNER_SUB_RDS; + if (dev->radio_rx_rds_controls) + vivid_radio_rds_init(dev); + vt->audmode = dev->radio_rx_audmode; + return 0; +} + +int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vt->index) + return -EINVAL; + dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO; + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h new file mode 100644 index 000000000000..1077d8f061eb --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-rx.h @@ -0,0 +1,31 @@ +/* + * vivid-radio-rx.h - radio receiver support functions. + * + * Copyright 2014 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 _VIVID_RADIO_RX_H_ +#define _VIVID_RADIO_RX_H_ + +ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *); +unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait); + +int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a); +int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); + +#endif diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c new file mode 100644 index 000000000000..8c59d4f53200 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-tx.c @@ -0,0 +1,141 @@ +/* + * vivid-radio-tx.c - radio transmitter support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-radio-tx.h" + +ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf, + size_t size, loff_t *offset) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rds_data *data = dev->rds_gen.data; + struct timespec ts; + unsigned blk; + int i; + + if (dev->radio_tx_rds_controls) + return -EINVAL; + + if (size < sizeof(*data)) + return -EINVAL; + size = sizeof(*data) * (size / sizeof(*data)); + + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + if (dev->radio_tx_rds_owner && + file->private_data != dev->radio_tx_rds_owner) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + dev->radio_tx_rds_owner = file->private_data; + +retry: + ktime_get_ts(&ts); + ts = timespec_sub(ts, dev->radio_rds_init_ts); + blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000; + blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500; + if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block) + dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; + + /* + * No data is available if there hasn't been time to get new data, + * or if the RDS receiver has been disabled, or if we use the data + * from the RDS transmitter and that RDS transmitter has been disabled, + * or if the signal quality is too weak. + */ + if (blk == dev->radio_tx_rds_last_block || + !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) { + mutex_unlock(&dev->mutex); + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (msleep_interruptible(20) && signal_pending(current)) + return -EINTR; + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + goto retry; + } + + for (i = 0; i < size && blk > dev->radio_tx_rds_last_block; + dev->radio_tx_rds_last_block++) { + unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS; + struct v4l2_rds_data rds; + + if (copy_from_user(&rds, buf + i, sizeof(rds))) { + i = -EFAULT; + break; + } + i += sizeof(rds); + if (!dev->radio_rds_loop) + continue; + if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID || + (rds.block & V4L2_RDS_BLOCK_ERROR)) + continue; + rds.block &= V4L2_RDS_BLOCK_MSK; + data[data_blk] = rds; + } + mutex_unlock(&dev->mutex); + return i; +} + +unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait) +{ + return POLLOUT | POLLWRNORM | v4l2_ctrl_poll(file, wait); +} + +int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (a->index > 0) + return -EINVAL; + + strlcpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name)); + a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | + (dev->radio_tx_rds_controls ? + V4L2_TUNER_CAP_RDS_CONTROLS : + V4L2_TUNER_CAP_RDS_BLOCK_IO); + a->rangelow = AM_FREQ_RANGE_LOW; + a->rangehigh = FM_FREQ_RANGE_HIGH; + a->txsubchans = dev->radio_tx_subchans; + return 0; +} + +int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (a->index) + return -EINVAL; + if (a->txsubchans & ~0x13) + return -EINVAL; + dev->radio_tx_subchans = a->txsubchans; + return 0; +} diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h new file mode 100644 index 000000000000..7f8ff7547119 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-radio-tx.h @@ -0,0 +1,29 @@ +/* + * vivid-radio-tx.h - radio transmitter support functions. + * + * Copyright 2014 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 _VIVID_RADIO_TX_H_ +#define _VIVID_RADIO_TX_H_ + +ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *); +unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait); + +int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a); +int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a); + +#endif diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c new file mode 100644 index 000000000000..dab5463e26fa --- /dev/null +++ b/drivers/media/platform/vivid/vivid-rds-gen.c @@ -0,0 +1,165 @@ +/* + * vivid-rds-gen.c - rds (radio data system) generator support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include + +#include "vivid-rds-gen.h" + +static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp) +{ + switch (grp) { + case 0: + return (rds->dyn_pty << 2) | (grp & 3); + case 1: + return (rds->compressed << 2) | (grp & 3); + case 2: + return (rds->art_head << 2) | (grp & 3); + case 3: + return (rds->mono_stereo << 2) | (grp & 3); + } + return 0; +} + +/* + * This RDS generator creates 57 RDS groups (one group == four RDS blocks). + * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a + * standard 0B group containing the PI code and PS name. + * + * Groups 4-19 and 26-41 use group 2A for the radio text. + * + * Group 56 contains the time (group 4A). + * + * All remaining groups use a filler group 15B block that just repeats + * the PI and PTY codes. + */ +void vivid_rds_generate(struct vivid_rds_gen *rds) +{ + struct v4l2_rds_data *data = rds->data; + unsigned grp; + struct tm tm; + unsigned date; + unsigned time; + int l; + + for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) { + data[0].lsb = rds->picode & 0xff; + data[0].msb = rds->picode >> 8; + data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3); + data[1].lsb = rds->pty << 5; + data[1].msb = (rds->pty >> 3) | (rds->tp << 2); + data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3); + data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3); + + switch (grp) { + case 0 ... 3: + case 22 ... 25: + case 44 ... 47: /* Group 0B */ + data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[1].lsb |= vivid_get_di(rds, grp % 22); + data[1].msb |= 1 << 3; + data[2].lsb = rds->picode & 0xff; + data[2].msb = rds->picode >> 8; + data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); + data[3].lsb = rds->psname[2 * (grp % 22) + 1]; + data[3].msb = rds->psname[2 * (grp % 22)]; + break; + case 4 ... 19: + case 26 ... 41: /* Group 2A */ + data[1].lsb |= (grp - 4) % 22; + data[1].msb |= 4 << 3; + data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)]; + data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1]; + data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); + data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2]; + data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3]; + break; + case 56: + /* + * Group 4A + * + * Uses the algorithm from Annex G of the RDS standard + * EN 50067:1998 to convert a UTC date to an RDS Modified + * Julian Day. + */ + time_to_tm(get_seconds(), 0, &tm); + l = tm.tm_mon <= 1; + date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 + + ((tm.tm_mon + 2 + l * 12) * 306001) / 10000; + time = (tm.tm_hour << 12) | + (tm.tm_min << 6) | + (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) | + (abs(sys_tz.tz_minuteswest) / 30); + data[1].lsb &= ~3; + data[1].lsb |= date >> 15; + data[1].msb |= 8 << 3; + data[2].lsb = (date << 1) & 0xfe; + data[2].lsb |= (time >> 16) & 1; + data[2].msb = (date >> 7) & 0xff; + data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); + data[3].lsb = time & 0xff; + data[3].msb = (time >> 8) & 0xff; + break; + default: /* Group 15B */ + data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[1].lsb |= vivid_get_di(rds, grp % 22); + data[1].msb |= 0x1f << 3; + data[2].lsb = rds->picode & 0xff; + data[2].msb = rds->picode >> 8; + data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); + data[3].lsb = rds->pty << 5; + data[3].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[3].lsb |= vivid_get_di(rds, grp % 22); + data[3].msb |= rds->pty >> 3; + data[3].msb |= 0x1f << 3; + break; + } + } +} + +void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, + bool alt) +{ + /* Alternate PTY between Info and Weather */ + if (rds->use_rbds) { + rds->picode = 0x2e75; /* 'KLNX' call sign */ + rds->pty = alt ? 29 : 2; + } else { + rds->picode = 0x8088; + rds->pty = alt ? 16 : 3; + } + rds->mono_stereo = true; + rds->art_head = false; + rds->compressed = false; + rds->dyn_pty = false; + rds->tp = true; + rds->ta = alt; + rds->ms = true; + snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", + freq / 16, ((freq & 0xf) * 10) / 16); + if (alt) + strlcpy(rds->radiotext, + " The Radio Data System can switch between different Radio Texts ", + sizeof(rds->radiotext)); + else + strlcpy(rds->radiotext, + "An example of Radio Text as transmitted by the Radio Data System", + sizeof(rds->radiotext)); +} diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h new file mode 100644 index 000000000000..eff4bf552ed3 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-rds-gen.h @@ -0,0 +1,53 @@ +/* + * vivid-rds-gen.h - rds (radio data system) generator support functions. + * + * Copyright 2014 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 _VIVID_RDS_GEN_H_ +#define _VIVID_RDS_GEN_H_ + +/* + * It takes almost exactly 5 seconds to transmit 57 RDS groups. + * Each group has 4 blocks and each block has a payload of 16 bits + a + * block identification. The driver will generate the contents of these + * 57 groups only when necessary and it will just be played continuously. + */ +#define VIVID_RDS_GEN_GROUPS 57 +#define VIVID_RDS_GEN_BLKS_PER_GRP 4 +#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS) + +struct vivid_rds_gen { + struct v4l2_rds_data data[VIVID_RDS_GEN_BLOCKS]; + bool use_rbds; + u16 picode; + u8 pty; + bool mono_stereo; + bool art_head; + bool compressed; + bool dyn_pty; + bool ta; + bool tp; + bool ms; + char psname[8 + 1]; + char radiotext[64 + 1]; +}; + +void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, + bool use_alternate); +void vivid_rds_generate(struct vivid_rds_gen *rds); + +#endif -- cgit v1.2.3 From 6de8653f410c5413a557eb48e2492a93f7af664b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:03:32 -0300 Subject: [media] vivid: add support for software defined radio This adds support for an SDR capture device. It generates simple sine/cosine waves. The code for that has been contributed by Antti. Signed-off-by: Antti Palosaari Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-sdr-cap.c | 499 +++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-sdr-cap.h | 34 ++ 2 files changed, 533 insertions(+) create mode 100644 drivers/media/platform/vivid/vivid-sdr-cap.c create mode 100644 drivers/media/platform/vivid/vivid-sdr-cap.h diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c new file mode 100644 index 000000000000..8c5d661cfc49 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -0,0 +1,499 @@ +/* + * vivid-sdr-cap.c - software defined radio support functions. + * + * Copyright 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-sdr-cap.h" + +static const struct v4l2_frequency_band bands_adc[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 300000, + .rangehigh = 300000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 900001, + .rangehigh = 2800000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 2, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 3200000, + .rangehigh = 3200000, + }, +}; + +/* ADC band midpoints */ +#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) +#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2) + +static const struct v4l2_frequency_band bands_fm[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 50000000, + .rangehigh = 2000000000, + }, +}; + +static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev) +{ + struct vivid_buffer *sdr_cap_buf = NULL; + + dprintk(dev, 1, "SDR Capture Thread Tick\n"); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + return; + + spin_lock(&dev->slock); + if (!list_empty(&dev->sdr_cap_active)) { + sdr_cap_buf = list_entry(dev->sdr_cap_active.next, + struct vivid_buffer, list); + list_del(&sdr_cap_buf->list); + } + spin_unlock(&dev->slock); + + if (sdr_cap_buf) { + sdr_cap_buf->vb.v4l2_buf.sequence = dev->sdr_cap_seq_count; + vivid_sdr_cap_process(dev, sdr_cap_buf); + v4l2_get_timestamp(&sdr_cap_buf->vb.v4l2_buf.timestamp); + sdr_cap_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset; + vb2_buffer_done(&sdr_cap_buf->vb, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev->dqbuf_error = false; + } +} + +static int vivid_thread_sdr_cap(void *data) +{ + struct vivid_dev *dev = data; + u64 samples_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + + dprintk(dev, 1, "SDR Capture Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->sdr_cap_seq_offset = 0; + if (dev->seq_wrap) + dev->sdr_cap_seq_offset = 0xffffff80U; + dev->jiffies_sdr_cap = jiffies; + dev->sdr_cap_seq_resync = false; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + mutex_lock(&dev->mutex); + cur_jiffies = jiffies; + if (dev->sdr_cap_seq_resync) { + dev->jiffies_sdr_cap = cur_jiffies; + dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1; + dev->sdr_cap_seq_count = 0; + dev->sdr_cap_seq_resync = false; + } + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * dev->sdr_adc_freq + + (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2; + do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_sdr_cap = cur_jiffies; + dev->sdr_cap_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dev->sdr_cap_seq_count = buffers_since_start + dev->sdr_cap_seq_offset; + + vivid_thread_sdr_cap_tick(dev); + mutex_unlock(&dev->mutex); + + /* + * Calculate the number of samples streamed since we started, + * not including the current buffer. + */ + samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_sdr_cap; + + /* Increase by the number of samples in one buffer */ + samples_since_start += SDR_CAP_SAMPLES_PER_BUF; + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = samples_since_start * HZ + + dev->sdr_adc_freq / 2; + do_div(next_jiffies_since_start, dev->sdr_adc_freq); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "SDR Capture Thread End\n"); + return 0; +} + +static int sdr_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], void *alloc_ctxs[]) +{ + /* 2 = max 16-bit sample returned */ + sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2; + *nplanes = 1; + return 0; +} + +static int sdr_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2; + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void sdr_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->sdr_cap_active); + spin_unlock(&dev->slock); +} + +static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err = 0; + + dprintk(dev, 1, "%s\n", __func__); + dev->sdr_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else if (dev->kthread_sdr_cap == NULL) { + dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev, + "%s-sdr-cap", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_sdr_cap)) { + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + err = PTR_ERR(dev->kthread_sdr_cap); + dev->kthread_sdr_cap = NULL; + } + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void sdr_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + if (dev->kthread_sdr_cap == NULL) + return; + + while (!list_empty(&dev->sdr_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->sdr_cap_active.next, struct vivid_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + /* shutdown control thread */ + mutex_unlock(&dev->mutex); + kthread_stop(dev->kthread_sdr_cap); + dev->kthread_sdr_cap = NULL; + mutex_lock(&dev->mutex); +} + +const struct vb2_ops vivid_sdr_cap_qops = { + .queue_setup = sdr_cap_queue_setup, + .buf_prepare = sdr_cap_buf_prepare, + .buf_queue = sdr_cap_buf_queue, + .start_streaming = sdr_cap_start_streaming, + .stop_streaming = sdr_cap_stop_streaming, + .wait_prepare = vivid_unlock, + .wait_finish = vivid_lock, +}; + +int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +{ + switch (band->tuner) { + case 0: + if (band->index >= ARRAY_SIZE(bands_adc)) + return -EINVAL; + *band = bands_adc[band->index]; + return 0; + case 1: + if (band->index >= ARRAY_SIZE(bands_fm)) + return -EINVAL; + *band = bands_fm[band->index]; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + switch (vf->tuner) { + case 0: + vf->frequency = dev->sdr_adc_freq; + vf->type = V4L2_TUNER_ADC; + return 0; + case 1: + vf->frequency = dev->sdr_fm_freq; + vf->type = V4L2_TUNER_RF; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned freq = vf->frequency; + unsigned band; + + switch (vf->tuner) { + case 0: + if (vf->type != V4L2_TUNER_ADC) + return -EINVAL; + if (freq < BAND_ADC_0) + band = 0; + else if (freq < BAND_ADC_1) + band = 1; + else + band = 2; + + freq = clamp_t(unsigned, freq, + bands_adc[band].rangelow, + bands_adc[band].rangehigh); + + if (vb2_is_streaming(&dev->vb_sdr_cap_q) && + freq != dev->sdr_adc_freq) { + /* resync the thread's timings */ + dev->sdr_cap_seq_resync = true; + } + dev->sdr_adc_freq = freq; + return 0; + case 1: + if (vf->type != V4L2_TUNER_RF) + return -EINVAL; + dev->sdr_fm_freq = clamp_t(unsigned, freq, + bands_fm[0].rangelow, + bands_fm[0].rangehigh); + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + switch (vt->index) { + case 0: + strlcpy(vt->name, "ADC", sizeof(vt->name)); + vt->type = V4L2_TUNER_ADC; + vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + vt->rangelow = bands_adc[0].rangelow; + vt->rangehigh = bands_adc[2].rangehigh; + return 0; + case 1: + strlcpy(vt->name, "RF", sizeof(vt->name)); + vt->type = V4L2_TUNER_RF; + vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + vt->rangelow = bands_fm[0].rangelow; + vt->rangehigh = bands_fm[0].rangehigh; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + if (vt->index > 1) + return -EINVAL; + return 0; +} + +int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_SDR_FMT_CU8; + strlcpy(f->description, "IQ U8", sizeof(f->description)); + return 0; +} + +int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + f->fmt.sdr.pixelformat = V4L2_SDR_FMT_CU8; + f->fmt.sdr.buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + return 0; +} + +#define FIXP_FRAC (1 << 15) +#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) + +/* cos() from cx88 driver: cx88-dsp.c */ +static s32 fixp_cos(unsigned int x) +{ + u32 t2, t4, t6, t8; + u16 period = x / FIXP_PI; + + if (period % 2) + return -fixp_cos(x - FIXP_PI); + x = x % FIXP_PI; + if (x > FIXP_PI/2) + return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); + /* Now x is between 0 and FIXP_PI/2. + * To calculate cos(x) we use it's Taylor polinom. */ + t2 = x*x/FIXP_FRAC/2; + t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; + t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; + t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; + return FIXP_FRAC-t2+t4-t6+t8; +} + +static inline s32 fixp_sin(unsigned int x) +{ + return -fixp_cos(x + (FIXP_PI / 2)); +} + +void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); + unsigned long i; + unsigned long plane_size = vb2_plane_size(&buf->vb, 0); + int fixp_src_phase_step, fixp_i, fixp_q; + + /* + * TODO: Generated beep tone goes very crackly when sample rate is + * increased to ~1Msps or more. That is because of huge rounding error + * of phase angle caused by used cosine implementation. + */ + + /* calculate phase step */ + #define BEEP_FREQ 1000 /* 1kHz beep */ + fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, + dev->sdr_adc_freq); + + for (i = 0; i < plane_size; i += 2) { + dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); + dev->sdr_fixp_src_phase += fixp_src_phase_step; + + /* + * Transfer phases to [0 / 2xPI] in order to avoid variable + * overflow and make it suitable for cosine implementation + * used, which does not support negative angles. + */ + while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) + dev->sdr_fixp_mod_phase += (2 * FIXP_PI); + while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) + dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); + + while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) + dev->sdr_fixp_src_phase -= (2 * FIXP_PI); + + fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); + fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); + + /* convert 'fixp float' to u8 */ + /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ + fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; + fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + } +} diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h new file mode 100644 index 000000000000..79c1890de972 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-sdr-cap.h @@ -0,0 +1,34 @@ +/* + * vivid-sdr-cap.h - software defined radio support functions. + * + * Copyright 2014 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 _VIVID_SDR_CAP_H_ +#define _VIVID_SDR_CAP_H_ + +int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); +int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); +int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); + +extern const struct vb2_ops vivid_sdr_cap_qops; + +#endif -- cgit v1.2.3 From 1fc78bc9d4cd9714b995f61ef414645c0d54a0bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Sep 2014 17:52:07 -0300 Subject: [media] vivid: Don't mess with namespace adding a "get_format" function This fixes a compilation error with allyesconfig: drivers/media/platform/exynos-gsc/built-in.o: In function `get_format': (.text+0x12f5): multiple definition of `get_format' drivers/media/platform/vivid/built-in.o:(.text+0x4bf4): first defined here Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 14 +++++++------- drivers/media/platform/vivid/vivid-vid-common.c | 2 +- drivers/media/platform/vivid/vivid-vid-common.h | 2 +- drivers/media/platform/vivid/vivid-vid-out.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 52f24ea40af3..115437af1ee0 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -130,7 +130,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f */ if (mp->num_planes != planes) return -EINVAL; - vfmt = get_format(dev, mp->pixelformat); + vfmt = vivid_get_format(dev, mp->pixelformat); for (p = 0; p < planes; p++) { sizes[p] = mp->plane_fmt[p].sizeimage; if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h + @@ -531,12 +531,12 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, unsigned w, h; unsigned p; - fmt = get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, mp->pixelformat); if (!fmt) { dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", mp->pixelformat); mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, mp->pixelformat); } mp->field = vivid_field_cap(dev, mp->field); @@ -623,7 +623,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, return -EBUSY; } - dev->fmt_cap = get_format(dev, mp->pixelformat); + dev->fmt_cap = vivid_get_format(dev, mp->pixelformat); if (V4L2_FIELD_HAS_T_OR_B(mp->field)) factor = 2; @@ -1180,7 +1180,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, if (a->fmt.width < 48 || a->fmt.height < 32) return -EINVAL; - fmt = get_format(dev, a->fmt.pixelformat); + fmt = vivid_get_format(dev, a->fmt.pixelformat); if (!fmt || !fmt->can_do_overlay) return -EINVAL; if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8) @@ -1610,7 +1610,7 @@ int vidioc_enum_framesizes(struct file *file, void *fh, if (!vivid_is_webcam(dev) && !dev->has_scaler_cap) return -EINVAL; - if (get_format(dev, fsize->pixel_format) == NULL) + if (vivid_get_format(dev, fsize->pixel_format) == NULL) return -EINVAL; if (vivid_is_webcam(dev)) { if (fsize->index >= ARRAY_SIZE(webcam_sizes)) @@ -1639,7 +1639,7 @@ int vidioc_enum_frameintervals(struct file *file, void *priv, const struct vivid_fmt *fmt; int i; - fmt = get_format(dev, fival->pixel_format); + fmt = vivid_get_format(dev, fival->pixel_format); if (!fmt) return -EINVAL; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 7b981c176ad8..16cd6d2d2ed6 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -186,7 +186,7 @@ struct vivid_fmt vivid_formats[] = { /* There are 2 multiplanar formats in the list */ #define VIVID_MPLANAR_FORMATS 2 -const struct vivid_fmt *get_format(struct vivid_dev *dev, u32 pixelformat) +const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) { const struct vivid_fmt *fmt; unsigned k; diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 9563c327fe56..3ec4fa85c9b9 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -32,7 +32,7 @@ int fmt_sp2mp_func(struct file *file, void *priv, extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap; -const struct vivid_fmt *get_format(struct vivid_dev *dev, u32 pixelformat); +const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat); bool vivid_vid_can_loop(struct vivid_dev *dev); void vivid_send_source_change(struct vivid_dev *dev, unsigned type); diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 3078bd2fdc01..9fd803592864 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -340,12 +340,12 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, unsigned w, h; unsigned p; - fmt = get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, mp->pixelformat); if (!fmt) { dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", mp->pixelformat); mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, mp->pixelformat); } mp->field = vivid_field_out(dev, mp->field); @@ -440,7 +440,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, if (vb2_is_busy(q)) goto set_colorspace; - dev->fmt_out = get_format(dev, mp->pixelformat); + dev->fmt_out = vivid_get_format(dev, mp->pixelformat); if (V4L2_FIELD_HAS_T_OR_B(mp->field)) factor = 2; -- cgit v1.2.3 From e75420dd25bc9d7b6f4e3b4c4f6c778b610c8cda Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:06:34 -0300 Subject: [media] vivid: enable the vivid driver Update the Kconfig and Makefile files so this driver can be compiled. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 3 +++ drivers/media/platform/Makefile | 2 ++ drivers/media/platform/vivid/Kconfig | 19 +++++++++++++++++++ drivers/media/platform/vivid/Makefile | 6 ++++++ 4 files changed, 30 insertions(+) create mode 100644 drivers/media/platform/vivid/Kconfig create mode 100644 drivers/media/platform/vivid/Makefile diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ae021faf7a42..33858f3dfa5e 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -264,6 +264,9 @@ menuconfig V4L_TEST_DRIVERS depends on MEDIA_CAMERA_SUPPORT if V4L_TEST_DRIVERS + +source "drivers/media/platform/vivid/Kconfig" + config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index b598b3bb2645..848b5e62f055 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -15,8 +15,10 @@ obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o + obj-$(CONFIG_VIDEO_VIVI) += vivi.o +obj-$(CONFIG_VIDEO_VIVID) += vivid/ obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/ diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig new file mode 100644 index 000000000000..d71139a2ae00 --- /dev/null +++ b/drivers/media/platform/vivid/Kconfig @@ -0,0 +1,19 @@ +config VIDEO_VIVID + tristate "Virtual Video Test Driver" + depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 + select FONT_SUPPORT + select FONT_8x16 + select VIDEOBUF2_VMALLOC + default n + ---help--- + Enables a virtual video driver. This driver emulates a webcam, + TV, S-Video and HDMI capture hardware, including VBI support for + the SDTV inputs. Also video output, VBI output, radio receivers, + transmitters and software defined radio capture is emulated. + + It is highly configurable and is ideal for testing applications. + Error injection is supported to test rare errors that are hard + to reproduce in real hardware. + + Say Y here if you want to test video apps or debug V4L devices. + When in doubt, say N. diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile new file mode 100644 index 000000000000..756fc12851df --- /dev/null +++ b/drivers/media/platform/vivid/Makefile @@ -0,0 +1,6 @@ +vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ + vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ + vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ + vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ + vivid-osd.o vivid-tpg.o vivid-tpg-colors.o +obj-$(CONFIG_VIDEO_VIVID) += vivid.o -- cgit v1.2.3 From 077af28c639be01d50e607754a84a3fada09ae9c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:49:53 -0300 Subject: [media] vivi: remove driver, it's replaced by vivid The vivid driver is a vastly superior test driver, so just drop the old vivi driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 14 - drivers/media/platform/Makefile | 2 - drivers/media/platform/vivi.c | 1542 --------------------------------------- 3 files changed, 1558 deletions(-) delete mode 100644 drivers/media/platform/vivi.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 33858f3dfa5e..9037b8cf0a4b 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -267,20 +267,6 @@ if V4L_TEST_DRIVERS source "drivers/media/platform/vivid/Kconfig" -config VIDEO_VIVI - tristate "Virtual Video Driver" - depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 - select FONT_SUPPORT - select FONT_8x16 - select VIDEOBUF2_VMALLOC - default n - ---help--- - Enables a virtual video driver. This device shows a color bar - and a timestamp, as a real device would generate by using V4L2 - api. - Say Y here if you want to test video apps or debug V4L devices. - In doubt, say N. - config VIDEO_MEM2MEM_TESTDEV tristate "Virtual test device for mem2mem framework" depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 848b5e62f055..8d3fcfef099c 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -16,8 +16,6 @@ obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o -obj-$(CONFIG_VIDEO_VIVI) += vivi.o - obj-$(CONFIG_VIDEO_VIVID) += vivid/ obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c deleted file mode 100644 index 80333714ffa7..000000000000 --- a/drivers/media/platform/vivi.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* - * Virtual Video driver - This code emulates a real video device with v4l2 api - * - * Copyright (c) 2006 by: - * Mauro Carvalho Chehab - * Ted Walther - * John Sokol - * http://v4l.videotechnology.com/ - * - * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski - * Copyright (c) 2010 Samsung Electronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the BSD Licence, 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 - -#define VIVI_MODULE_NAME "vivi" - -/* Maximum allowed frame rate - * - * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range. - * - * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that - * might hit application errors when they manipulate these values. - * - * Besides, for tpf < 1ms image-generation logic should be changed, to avoid - * producing frames with equal content. - */ -#define FPS_MAX 1000 - -#define MAX_WIDTH 1920 -#define MAX_HEIGHT 1200 - -#define VIVI_VERSION "0.8.1" - -MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); -MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(VIVI_VERSION); - -static unsigned video_nr = -1; -module_param(video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); - -static unsigned n_devs = 1; -module_param(n_devs, uint, 0644); -MODULE_PARM_DESC(n_devs, "number of video devices to create"); - -static unsigned debug; -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -/* Global font descriptor */ -static const u8 *font8x16; - -/* timeperframe: min/max and default */ -static const struct v4l2_fract - tpf_min = {.numerator = 1, .denominator = FPS_MAX}, - tpf_max = {.numerator = FPS_MAX, .denominator = 1}, - tpf_default = {.numerator = 1001, .denominator = 30000}; /* NTSC */ - -#define dprintk(dev, level, fmt, arg...) \ - v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) - -/* ------------------------------------------------------------------ - Basic structures - ------------------------------------------------------------------*/ - -struct vivi_fmt { - const char *name; - u32 fourcc; /* v4l2 format id */ - u8 depth; - bool is_yuv; -}; - -static const struct vivi_fmt formats[] = { - { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .is_yuv = true, - }, - { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .is_yuv = true, - }, - { - .name = "4:2:2, packed, YVYU", - .fourcc = V4L2_PIX_FMT_YVYU, - .depth = 16, - .is_yuv = true, - }, - { - .name = "4:2:2, packed, VYUY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = 16, - .is_yuv = true, - }, - { - .name = "RGB565 (LE)", - .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, - }, - { - .name = "RGB565 (BE)", - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .depth = 16, - }, - { - .name = "RGB555 (LE)", - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, - }, - { - .name = "RGB555 (BE)", - .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ - .depth = 16, - }, - { - .name = "RGB24 (LE)", - .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ - .depth = 24, - }, - { - .name = "RGB24 (BE)", - .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ - .depth = 24, - }, - { - .name = "RGB32 (LE)", - .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ - .depth = 32, - }, - { - .name = "RGB32 (BE)", - .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ - .depth = 32, - }, -}; - -static const struct vivi_fmt *__get_format(u32 pixelformat) -{ - const struct vivi_fmt *fmt; - unsigned int k; - - for (k = 0; k < ARRAY_SIZE(formats); k++) { - fmt = &formats[k]; - if (fmt->fourcc == pixelformat) - break; - } - - if (k == ARRAY_SIZE(formats)) - return NULL; - - return &formats[k]; -} - -static const struct vivi_fmt *get_format(struct v4l2_format *f) -{ - return __get_format(f->fmt.pix.pixelformat); -} - -/* buffer for one video frame */ -struct vivi_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_buffer vb; - struct list_head list; -}; - -struct vivi_dmaqueue { - struct list_head active; - - /* thread for generating video stream*/ - struct task_struct *kthread; - wait_queue_head_t wq; - /* Counters to control fps rate */ - int frame; - int ini_jiffies; -}; - -static LIST_HEAD(vivi_devlist); - -struct vivi_dev { - struct list_head vivi_devlist; - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; - struct video_device vdev; - - /* controls */ - struct v4l2_ctrl *brightness; - struct v4l2_ctrl *contrast; - struct v4l2_ctrl *saturation; - struct v4l2_ctrl *hue; - struct { - /* autogain/gain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct v4l2_ctrl *volume; - struct v4l2_ctrl *alpha; - struct v4l2_ctrl *button; - struct v4l2_ctrl *boolean; - struct v4l2_ctrl *int32; - struct v4l2_ctrl *int64; - struct v4l2_ctrl *menu; - struct v4l2_ctrl *string; - struct v4l2_ctrl *bitmask; - struct v4l2_ctrl *int_menu; - - spinlock_t slock; - struct mutex mutex; - - struct vivi_dmaqueue vidq; - - /* Several counters */ - unsigned ms; - unsigned long jiffies; - unsigned button_pressed; - - int mv_count; /* Controls bars movement */ - - /* Input Number */ - int input; - - /* video capture */ - const struct vivi_fmt *fmt; - struct v4l2_fract timeperframe; - unsigned int width, height; - struct vb2_queue vb_vidq; - unsigned int seq_count; - - u8 bars[9][3]; - u8 line[MAX_WIDTH * 8] __attribute__((__aligned__(4))); - unsigned int pixelsize; - u8 alpha_component; - u32 textfg, textbg; -}; - -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ - -/* Bars and Colors should match positions */ - -enum colors { - WHITE, - AMBER, - CYAN, - GREEN, - MAGENTA, - RED, - BLUE, - BLACK, - TEXT_BLACK, -}; - -/* R G B */ -#define COLOR_WHITE {204, 204, 204} -#define COLOR_AMBER {208, 208, 0} -#define COLOR_CYAN { 0, 206, 206} -#define COLOR_GREEN { 0, 239, 0} -#define COLOR_MAGENTA {239, 0, 239} -#define COLOR_RED {205, 0, 0} -#define COLOR_BLUE { 0, 0, 255} -#define COLOR_BLACK { 0, 0, 0} - -struct bar_std { - u8 bar[9][3]; -}; - -/* Maximum number of bars are 10 - otherwise, the input print code - should be modified */ -static const struct bar_std bars[] = { - { /* Standard ITU-R color bar sequence */ - { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, - COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, - COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, - COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, - COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } - }, -}; - -#define NUM_INPUTS ARRAY_SIZE(bars) - -#define TO_Y(r, g, b) \ - (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) -/* RGB to V(Cr) Color transform */ -#define TO_V(r, g, b) \ - (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) -/* RGB to U(Cb) Color transform */ -#define TO_U(r, g, b) \ - (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) - -/* precalculate color bar values to speed up rendering */ -static void precalculate_bars(struct vivi_dev *dev) -{ - u8 r, g, b; - int k, is_yuv; - - for (k = 0; k < 9; k++) { - r = bars[dev->input].bar[k][0]; - g = bars[dev->input].bar[k][1]; - b = bars[dev->input].bar[k][2]; - is_yuv = dev->fmt->is_yuv; - - switch (dev->fmt->fourcc) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - r >>= 3; - g >>= 2; - b >>= 3; - break; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB555X: - r >>= 3; - g >>= 3; - b >>= 3; - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - break; - } - - if (is_yuv) { - dev->bars[k][0] = TO_Y(r, g, b); /* Luma */ - dev->bars[k][1] = TO_U(r, g, b); /* Cb */ - dev->bars[k][2] = TO_V(r, g, b); /* Cr */ - } else { - dev->bars[k][0] = r; - dev->bars[k][1] = g; - dev->bars[k][2] = b; - } - } -} - -/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ -static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd) -{ - u8 r_y, g_u, b_v; - u8 alpha = dev->alpha_component; - int color; - u8 *p; - - r_y = dev->bars[colorpos][0]; /* R or precalculated Y */ - g_u = dev->bars[colorpos][1]; /* G or precalculated U */ - b_v = dev->bars[colorpos][2]; /* B or precalculated V */ - - for (color = 0; color < dev->pixelsize; color++) { - p = buf + color; - - switch (dev->fmt->fourcc) { - case V4L2_PIX_FMT_YUYV: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = odd ? b_v : g_u; - break; - } - break; - case V4L2_PIX_FMT_UYVY: - switch (color) { - case 0: - *p = odd ? b_v : g_u; - break; - case 1: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_YVYU: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = odd ? g_u : b_v; - break; - } - break; - case V4L2_PIX_FMT_VYUY: - switch (color) { - case 0: - *p = odd ? g_u : b_v; - break; - case 1: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_RGB565: - switch (color) { - case 0: - *p = (g_u << 5) | b_v; - break; - case 1: - *p = (r_y << 3) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB565X: - switch (color) { - case 0: - *p = (r_y << 3) | (g_u >> 3); - break; - case 1: - *p = (g_u << 5) | b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB555: - switch (color) { - case 0: - *p = (g_u << 5) | b_v; - break; - case 1: - *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB555X: - switch (color) { - case 0: - *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); - break; - case 1: - *p = (g_u << 5) | b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB24: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = g_u; - break; - case 2: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_BGR24: - switch (color) { - case 0: - *p = b_v; - break; - case 1: - *p = g_u; - break; - case 2: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_RGB32: - switch (color) { - case 0: - *p = alpha; - break; - case 1: - *p = r_y; - break; - case 2: - *p = g_u; - break; - case 3: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_BGR32: - switch (color) { - case 0: - *p = b_v; - break; - case 1: - *p = g_u; - break; - case 2: - *p = r_y; - break; - case 3: - *p = alpha; - break; - } - break; - } - } -} - -static void precalculate_line(struct vivi_dev *dev) -{ - unsigned pixsize = dev->pixelsize; - unsigned pixsize2 = 2*pixsize; - int colorpos; - u8 *pos; - - for (colorpos = 0; colorpos < 16; ++colorpos) { - u8 pix[8]; - int wstart = colorpos * dev->width / 8; - int wend = (colorpos+1) * dev->width / 8; - int w; - - gen_twopix(dev, &pix[0], colorpos % 8, 0); - gen_twopix(dev, &pix[pixsize], colorpos % 8, 1); - - for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2) - memcpy(pos, pix, pixsize2); - } -} - -/* need this to do rgb24 rendering */ -typedef struct { u16 __; u8 _; } __attribute__((packed)) x24; - -static void gen_text(struct vivi_dev *dev, char *basep, - int y, int x, char *text) -{ - int line; - unsigned int width = dev->width; - - /* Checks if it is possible to show string */ - if (y + 16 >= dev->height || x + strlen(text) * 8 >= width) - return; - - /* Print stream time */ -#define PRINTSTR(PIXTYPE) do { \ - PIXTYPE fg; \ - PIXTYPE bg; \ - memcpy(&fg, &dev->textfg, sizeof(PIXTYPE)); \ - memcpy(&bg, &dev->textbg, sizeof(PIXTYPE)); \ - \ - for (line = 0; line < 16; line++) { \ - PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) ); \ - u8 *s; \ - \ - for (s = text; *s; s++) { \ - u8 chr = font8x16[*s * 16 + line]; \ - \ - pos[0] = (chr & (0x01 << 7) ? fg : bg); \ - pos[1] = (chr & (0x01 << 6) ? fg : bg); \ - pos[2] = (chr & (0x01 << 5) ? fg : bg); \ - pos[3] = (chr & (0x01 << 4) ? fg : bg); \ - pos[4] = (chr & (0x01 << 3) ? fg : bg); \ - pos[5] = (chr & (0x01 << 2) ? fg : bg); \ - pos[6] = (chr & (0x01 << 1) ? fg : bg); \ - pos[7] = (chr & (0x01 << 0) ? fg : bg); \ - \ - pos += 8; \ - } \ - } \ -} while (0) - - switch (dev->pixelsize) { - case 2: - PRINTSTR(u16); break; - case 4: - PRINTSTR(u32); break; - case 3: - PRINTSTR(x24); break; - } -} - -static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) -{ - int stride = dev->width * dev->pixelsize; - int hmax = dev->height; - void *vbuf = vb2_plane_vaddr(&buf->vb, 0); - unsigned ms; - char str[100]; - int h, line = 1; - u8 *linestart; - s32 gain; - - if (!vbuf) - return; - - linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize; - - for (h = 0; h < hmax; h++) - memcpy(vbuf + h * stride, linestart, stride); - - /* Updates stream time */ - - gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0); - gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0); - - dev->ms += jiffies_to_msecs(jiffies - dev->jiffies); - dev->jiffies = jiffies; - ms = dev->ms; - snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ", - (ms / (60 * 60 * 1000)) % 24, - (ms / (60 * 1000)) % 60, - (ms / 1000) % 60, - ms % 1000); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " %dx%d, input %d ", - dev->width, dev->height, dev->input); - gen_text(dev, vbuf, line++ * 16, 16, str); - - gain = v4l2_ctrl_g_ctrl(dev->gain); - mutex_lock(dev->ctrl_handler.lock); - snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", - dev->brightness->cur.val, - dev->contrast->cur.val, - dev->saturation->cur.val, - dev->hue->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ", - dev->autogain->cur.val, gain, dev->volume->cur.val, - dev->alpha->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", - dev->int32->cur.val, - *dev->int64->p_cur.p_s64, - dev->bitmask->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", - dev->boolean->cur.val, - dev->menu->qmenu[dev->menu->cur.val], - dev->string->p_cur.p_char); - gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " integer_menu %lld, value %d ", - dev->int_menu->qmenu_int[dev->int_menu->cur.val], - dev->int_menu->cur.val); - gen_text(dev, vbuf, line++ * 16, 16, str); - mutex_unlock(dev->ctrl_handler.lock); - if (dev->button_pressed) { - dev->button_pressed--; - snprintf(str, sizeof(str), " button pressed!"); - gen_text(dev, vbuf, line++ * 16, 16, str); - } - - dev->mv_count += 2; - - buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; - buf->vb.v4l2_buf.sequence = dev->seq_count++; - v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); -} - -static void vivi_thread_tick(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - struct vivi_buffer *buf; - unsigned long flags = 0; - - dprintk(dev, 1, "Thread tick\n"); - - spin_lock_irqsave(&dev->slock, flags); - if (list_empty(&dma_q->active)) { - dprintk(dev, 1, "No active queue to serve\n"); - spin_unlock_irqrestore(&dev->slock, flags); - return; - } - - buf = list_entry(dma_q->active.next, struct vivi_buffer, list); - list_del(&buf->list); - spin_unlock_irqrestore(&dev->slock, flags); - - v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); - - /* Fill buffer */ - vivi_fillbuff(dev, buf); - dprintk(dev, 1, "filled buffer %p\n", buf); - - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); - dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); -} - -#define frames_to_ms(dev, frames) \ - ((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator) - -static void vivi_sleep(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - int timeout; - DECLARE_WAITQUEUE(wait, current); - - dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, - (unsigned long)dma_q); - - add_wait_queue(&dma_q->wq, &wait); - if (kthread_should_stop()) - goto stop_task; - - /* Calculate time to wake up */ - timeout = msecs_to_jiffies(frames_to_ms(dev, 1)); - - vivi_thread_tick(dev); - - schedule_timeout_interruptible(timeout); - -stop_task: - remove_wait_queue(&dma_q->wq, &wait); - try_to_freeze(); -} - -static int vivi_thread(void *data) -{ - struct vivi_dev *dev = data; - - dprintk(dev, 1, "thread started\n"); - - set_freezable(); - - for (;;) { - vivi_sleep(dev); - - if (kthread_should_stop()) - break; - } - dprintk(dev, 1, "thread: exit\n"); - return 0; -} - -static int vivi_start_generating(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - - dprintk(dev, 1, "%s\n", __func__); - - /* Resets frame counters */ - dev->ms = 0; - dev->mv_count = 0; - dev->jiffies = jiffies; - - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - dma_q->kthread = kthread_run(vivi_thread, dev, "%s", - dev->v4l2_dev.name); - - if (IS_ERR(dma_q->kthread)) { - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - return PTR_ERR(dma_q->kthread); - } - /* Wakes thread */ - wake_up_interruptible(&dma_q->wq); - - dprintk(dev, 1, "returning from %s\n", __func__); - return 0; -} - -static void vivi_stop_generating(struct vivi_dev *dev) -{ - struct vivi_dmaqueue *dma_q = &dev->vidq; - - dprintk(dev, 1, "%s\n", __func__); - - /* shutdown control thread */ - if (dma_q->kthread) { - kthread_stop(dma_q->kthread); - dma_q->kthread = NULL; - } - - /* - * Typical driver might need to wait here until dma engine stops. - * In this case we can abort imiedetly, so it's just a noop. - */ - - /* Release all active buffers */ - while (!list_empty(&dma_q->active)) { - struct vivi_buffer *buf; - buf = list_entry(dma_q->active.next, struct vivi_buffer, list); - list_del(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); - } -} -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - unsigned long size; - - size = dev->width * dev->height * dev->pixelsize; - if (fmt) { - if (fmt->fmt.pix.sizeimage < size) - return -EINVAL; - size = fmt->fmt.pix.sizeimage; - /* check against insane over 8K resolution buffers */ - if (size > 7680 * 4320 * dev->pixelsize) - return -EINVAL; - } - - *nplanes = 1; - - sizes[0] = size; - - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - - dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, - *nbuffers, size); - - return 0; -} - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - unsigned long size; - - dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); - - BUG_ON(NULL == dev->fmt); - - /* - * Theses properties only change when queue is idle, see s_fmt. - * The below checks should not be performed here, on each - * buffer_prepare (i.e. on each qbuf). Most of the code in this function - * should thus be moved to buffer_init and s_fmt. - */ - if (dev->width < 48 || dev->width > MAX_WIDTH || - dev->height < 32 || dev->height > MAX_HEIGHT) - return -EINVAL; - - size = dev->width * dev->height * dev->pixelsize; - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(&buf->vb, 0, size); - - precalculate_bars(dev); - precalculate_line(dev); - - return 0; -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - struct vivi_dmaqueue *vidq = &dev->vidq; - unsigned long flags = 0; - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock_irqsave(&dev->slock, flags); - list_add_tail(&buf->list, &vidq->active); - spin_unlock_irqrestore(&dev->slock, flags); -} - -static int start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - int err; - - dprintk(dev, 1, "%s\n", __func__); - dev->seq_count = 0; - err = vivi_start_generating(dev); - if (err) { - struct vivi_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void stop_streaming(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - dprintk(dev, 1, "%s\n", __func__); - vivi_stop_generating(dev); -} - -static void vivi_lock(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - mutex_lock(&dev->mutex); -} - -static void vivi_unlock(struct vb2_queue *vq) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vq); - mutex_unlock(&dev->mutex); -} - - -static const struct vb2_ops vivi_video_qops = { - .queue_setup = queue_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, - .wait_prepare = vivi_unlock, - .wait_finish = vivi_lock, -}; - -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vivi_dev *dev = video_drvdata(file); - - strcpy(cap->driver, "vivi"); - strcpy(cap->card, "vivi"); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev->v4l2_dev.name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - const struct vivi_fmt *fmt; - - if (f->index >= ARRAY_SIZE(formats)) - return -EINVAL; - - fmt = &formats[f->index]; - - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.pixelformat = dev->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * dev->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - if (dev->fmt->is_yuv) - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - else - f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - const struct vivi_fmt *fmt; - - fmt = get_format(f); - if (!fmt) { - dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", - f->fmt.pix.pixelformat); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - fmt = get_format(f); - } - - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, - &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - if (fmt->is_yuv) - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - else - f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivi_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; - - int ret = vidioc_try_fmt_vid_cap(file, priv, f); - if (ret < 0) - return ret; - - if (vb2_is_busy(q)) { - dprintk(dev, 1, "%s device busy\n", __func__); - return -EBUSY; - } - - dev->fmt = get_format(f); - dev->pixelsize = dev->fmt->depth / 8; - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - - return 0; -} - -static int vidioc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - static const struct v4l2_frmsize_stepwise sizes = { - 48, MAX_WIDTH, 4, - 32, MAX_HEIGHT, 1 - }; - int i; - - if (fsize->index) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fsize->pixel_format) - break; - if (i == ARRAY_SIZE(formats)) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = sizes; - return 0; -} - -/* only one input in this sample driver */ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index >= NUM_INPUTS) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - sprintf(inp->name, "Camera %u", inp->index); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct vivi_dev *dev = video_drvdata(file); - - *i = dev->input; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct vivi_dev *dev = video_drvdata(file); - - if (i >= NUM_INPUTS) - return -EINVAL; - - if (i == dev->input) - 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; -} - -/* timeperframe is arbitrary and continuous */ -static int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) -{ - const struct vivi_fmt *fmt; - - if (fival->index) - return -EINVAL; - - fmt = __get_format(fival->pixel_format); - if (!fmt) - return -EINVAL; - - /* check for valid width/height */ - if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3)) - return -EINVAL; - if (fival->height < 32 || fival->height > MAX_HEIGHT) - return -EINVAL; - - fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - - /* fill in stepwise (step=1.0 is required by V4L2 spec) */ - fival->stepwise.min = tpf_min; - fival->stepwise.max = tpf_max; - fival->stepwise.step = (struct v4l2_fract) {1, 1}; - - return 0; -} - -static int vidioc_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivi_dev *dev = video_drvdata(file); - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.timeperframe = dev->timeperframe; - parm->parm.capture.readbuffers = 1; - return 0; -} - -#define FRACT_CMP(a, OP, b) \ - ((u64)(a).numerator * (b).denominator OP (u64)(b).numerator * (a).denominator) - -static int vidioc_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivi_dev *dev = video_drvdata(file); - struct v4l2_fract tpf; - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - tpf = parm->parm.capture.timeperframe; - - /* tpf: {*, 0} resets timing; clip to [min, max]*/ - tpf = tpf.denominator ? tpf : tpf_default; - tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf; - tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf; - - dev->timeperframe = tpf; - parm->parm.capture.timeperframe = tpf; - parm->parm.capture.readbuffers = 1; - return 0; -} - -/* --- controls ---------------------------------------------- */ - -static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); - - if (ctrl == dev->autogain) - dev->gain->val = jiffies & 0xff; - return 0; -} - -static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_ALPHA_COMPONENT: - dev->alpha_component = ctrl->val; - break; - default: - if (ctrl == dev->button) - dev->button_pressed = 30; - break; - } - return 0; -} - -/* ------------------------------------------------------------------ - File operations for the device - ------------------------------------------------------------------*/ - -static const struct v4l2_ctrl_ops vivi_ctrl_ops = { - .g_volatile_ctrl = vivi_g_volatile_ctrl, - .s_ctrl = vivi_s_ctrl, -}; - -#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) - -static const struct v4l2_ctrl_config vivi_ctrl_button = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 0, - .name = "Button", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_boolean = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 1, - .name = "Boolean", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .min = 0, - .max = 1, - .step = 1, - .def = 1, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_int32 = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 2, - .name = "Integer 32 Bits", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = -0x80000000LL, - .max = 0x7fffffff, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_int64 = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 3, - .name = "Integer 64 Bits", - .type = V4L2_CTRL_TYPE_INTEGER64, - .min = LLONG_MIN, - .max = LLONG_MAX, - .step = 1, -}; - -static const char * const vivi_ctrl_menu_strings[] = { - "Menu Item 0 (Skipped)", - "Menu Item 1", - "Menu Item 2 (Skipped)", - "Menu Item 3", - "Menu Item 4", - "Menu Item 5 (Skipped)", - NULL, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_menu = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 4, - .name = "Menu", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .max = 4, - .def = 3, - .menu_skip_mask = 0x04, - .qmenu = vivi_ctrl_menu_strings, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_string = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 5, - .name = "String", - .type = V4L2_CTRL_TYPE_STRING, - .min = 2, - .max = 4, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_bitmask = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 6, - .name = "Bitmask", - .type = V4L2_CTRL_TYPE_BITMASK, - .def = 0x80002000, - .min = 0, - .max = 0x80402010, - .step = 0, -}; - -static const s64 vivi_ctrl_int_menu_values[] = { - 1, 1, 2, 3, 5, 8, 13, 21, 42, -}; - -static const struct v4l2_ctrl_config vivi_ctrl_int_menu = { - .ops = &vivi_ctrl_ops, - .id = VIVI_CID_CUSTOM_BASE + 7, - .name = "Integer menu", - .type = V4L2_CTRL_TYPE_INTEGER_MENU, - .min = 1, - .max = 8, - .def = 4, - .menu_skip_mask = 0x02, - .qmenu_int = vivi_ctrl_int_menu_values, -}; - -static const struct v4l2_file_operations vivi_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_ioctl_ops vivi_ioctl_ops = { - .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_enum_framesizes = vidioc_enum_framesizes, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .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 vivi_template = { - .name = "vivi", - .fops = &vivi_fops, - .ioctl_ops = &vivi_ioctl_ops, - .release = video_device_release_empty, -}; - -/* ----------------------------------------------------------------- - Initialization and module stuff - ------------------------------------------------------------------*/ - -static int vivi_release(void) -{ - struct vivi_dev *dev; - struct list_head *list; - - while (!list_empty(&vivi_devlist)) { - list = vivi_devlist.next; - list_del(list); - dev = list_entry(list, struct vivi_dev, vivi_devlist); - - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->vdev)); - video_unregister_device(&dev->vdev); - v4l2_device_unregister(&dev->v4l2_dev); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - } - - return 0; -} - -static int __init vivi_create_instance(int inst) -{ - struct vivi_dev *dev; - struct video_device *vfd; - struct v4l2_ctrl_handler *hdl; - struct vb2_queue *q; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), - "%s-%03d", VIVI_MODULE_NAME, inst); - ret = v4l2_device_register(NULL, &dev->v4l2_dev); - if (ret) - goto free_dev; - - dev->fmt = &formats[0]; - dev->timeperframe = tpf_default; - dev->width = 640; - dev->height = 480; - dev->pixelsize = dev->fmt->depth / 8; - hdl = &dev->ctrl_handler; - v4l2_ctrl_handler_init(hdl, 11); - dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); - dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); - dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 16); - dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 127); - dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_GAIN, 0, 255, 1, 100); - dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, - V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); - dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL); - dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL); - dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL); - dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL); - dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL); - dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL); - dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL); - dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL); - if (hdl->error) { - ret = hdl->error; - goto unreg_dev; - } - v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); - dev->v4l2_dev.ctrl_handler = hdl; - - /* initialize locks */ - spin_lock_init(&dev->slock); - - /* initialize queue */ - q = &dev->vb_vidq; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivi_buffer); - q->ops = &vivi_video_qops; - q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - ret = vb2_queue_init(q); - if (ret) - goto unreg_dev; - - mutex_init(&dev->mutex); - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - init_waitqueue_head(&dev->vidq.wq); - - vfd = &dev->vdev; - *vfd = vivi_template; - vfd->debug = debug; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = q; - - /* - * Provide a mutex to v4l2 core. It will be used to protect - * all fops and v4l2 ioctls. - */ - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) - goto unreg_dev; - - /* Now that everything is fine, let's add it to device list */ - list_add_tail(&dev->vivi_devlist, &vivi_devlist); - - v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", - video_device_node_name(vfd)); - return 0; - -unreg_dev: - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); - return ret; -} - -/* This routine allocates from 1 to n_devs virtual drivers. - - The real maximum number of virtual drivers will depend on how many drivers - will succeed. This is limited to the maximum number of devices that - videodev supports, which is equal to VIDEO_NUM_DEVICES. - */ -static int __init vivi_init(void) -{ - const struct font_desc *font = find_font("VGA8x16"); - int ret = 0, i; - - if (font == NULL) { - printk(KERN_ERR "vivi: could not find font\n"); - return -ENODEV; - } - font8x16 = font->data; - - if (n_devs <= 0) - n_devs = 1; - - for (i = 0; i < n_devs; i++) { - ret = vivi_create_instance(i); - if (ret) { - /* If some instantiations succeeded, keep driver */ - if (i) - ret = 0; - break; - } - } - - if (ret < 0) { - printk(KERN_ERR "vivi: error %d while loading driver\n", ret); - return ret; - } - - printk(KERN_INFO "Video Technology Magazine Virtual Video " - "Capture Board ver %s successfully loaded.\n", - VIVI_VERSION); - - /* n_devs will reflect the actual number of allocated devices */ - n_devs = i; - - return ret; -} - -static void __exit vivi_exit(void) -{ - vivi_release(); -} - -module_init(vivi_init); -module_exit(vivi_exit); -- cgit v1.2.3 From 96ec7d2a6632d0757e2b83bd75c5784d4cc4a456 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Sep 2014 17:57:34 -0300 Subject: [media] vivid: add some missing headers That remove a few warnings: drivers/media/platform/vivid/vivid-kthread-out.c:226:5: warning: no previous prototype for 'vivid_start_generating_vid_out' [-Wmissing-prototypes] int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) ^ drivers/media/platform/vivid/vivid-kthread-out.c:260:6: warning: no previous prototype for 'vivid_stop_generating_vid_out' [-Wmissing-prototypes] void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) ^ drivers/media/platform/vivid/vivid-kthread-cap.c:806:5: warning: no previous prototype for 'vivid_start_generating_vid_cap' [-Wmissing-prototypes] int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) ^ drivers/media/platform/vivid/vivid-kthread-cap.c:841:6: warning: no previous prototype for 'vivid_stop_generating_vid_cap' [-Wmissing-prototypes] void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-kthread-cap.c | 1 + drivers/media/platform/vivid/vivid-kthread-out.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 33ab1dfe81c7..39a67cfae120 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -49,6 +49,7 @@ #include "vivid-vbi-out.h" #include "vivid-osd.h" #include "vivid-ctrls.h" +#include "vivid-kthread-cap.h" static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) { diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index 190575577948..d9f36ccd7efb 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -49,6 +49,7 @@ #include "vivid-vbi-out.h" #include "vivid-osd.h" #include "vivid-ctrls.h" +#include "vivid-kthread-out.h" static void vivid_thread_vid_out_tick(struct vivid_dev *dev) { -- cgit v1.2.3 From 20504fa92d072d427d1eaaa47f71f9fb60d6c43a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Sep 2014 17:58:59 -0300 Subject: [media] vivid: Don't declare .vidioc_overlay twice Removes the following warnings: drivers/media/platform/vivid/vivid-core.c:581:2: warning: initialized field overwritten [-Woverride-init] .vidioc_overlay = vidioc_overlay, ^ drivers/media/platform/vivid/vivid-core.c:581:2: warning: (near initialization for 'vivid_ioctl_ops.vidioc_overlay') [-Woverride-init] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 708b0530d9cf..fb3b0aad33ed 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -578,7 +578,6 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_out_overlay, .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay, .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_out_overlay, - .vidioc_overlay = vidioc_overlay, .vidioc_g_fbuf = vidioc_g_fbuf, .vidioc_s_fbuf = vidioc_s_fbuf, -- cgit v1.2.3 From 6c1c423a54b5b3a6c9c9561c7ef32aee0fda7253 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 2 Sep 2014 18:01:05 -0300 Subject: [media] vivid: comment the unused g_edid/s_edid functions Those non-static functions aren't used anywhere yet. Comment them while they're unused. Solves the following warnings: drivers/media/platform/vivid/vivid-vid-out.c:1120:5: warning: no previous prototype for 'vivid_vid_out_g_edid' [-Wmissing-prototypes] int vivid_vid_out_g_edid(struct file *file, void *_fh, ^ drivers/media/platform/vivid/vivid-vid-out.c:1152:5: warning: no previous prototype for 'vivid_vid_out_s_edid' [-Wmissing-prototypes] int vivid_vid_out_s_edid(struct file *file, void *_fh, ^ Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-out.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 9fd803592864..c983461f29d5 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1117,6 +1117,7 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, return 0; } +#if 0 int vivid_vid_out_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid) { @@ -1171,6 +1172,7 @@ int vivid_vid_out_s_edid(struct file *file, void *_fh, memcpy(dev->edid, edid->edid, edid->blocks * 128); return 0; } +#endif int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) -- cgit v1.2.3 From a7d3eabd77402828a5d5a84604626cb824571e0b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 04:50:14 -0300 Subject: [media] cx23885: fix querycap Set device_caps to fix the v4l2-compliance QUERYCAP complaints. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 91e4cb457296..2666ac415ec2 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1146,19 +1146,22 @@ static int vidioc_s_fmt_vid_cap(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 cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; + cap->device_caps |= V4L2_CAP_TUNER; + 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_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From d43be757b945b292402edc28aa67cf53581d3428 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 05:24:58 -0300 Subject: [media] cx23885: fix audio input handling Fix a bunch of v4l2-compliance errors relating to audio input handling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2666ac415ec2..79de4acbf533 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1153,7 +1153,7 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; if (vdev->vfl_type == VFL_TYPE_VBI) @@ -1302,16 +1302,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); + i->std = CX23885_NORMS; if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || (CX23885_VMUX_CABLE == INPUT(n)->type)) { i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX23885_NORMS; + i->audioset = 4; + } else { + /* Two selectable audio inputs for non-tv inputs */ + i->audioset = 3; } - /* Two selectable audio inputs for non-tv inputs */ - if (INPUT(n)->type != CX23885_VMUX_TELEVISION) - i->audioset = 0x3; - if (dev->input == n) { /* enum'd input matches our configured input. * Ask the video decoder to process the call @@ -1397,19 +1397,19 @@ static int cx23885_query_audinput(struct file *file, void *priv, static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", + [2] = "TV", }; unsigned int n; dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 2) + if (n >= 3) return -EINVAL; memset(i, 0, sizeof(*i)); i->index = n; strcpy(i->name, iname[n]); - i->capability = V4L2_AUDCAP_STEREO; - i->mode = V4L2_AUDMODE_AVL; + i->capability = V4L2_AUDCAP_STEREO; return 0; } @@ -1425,7 +1425,11 @@ static int vidioc_g_audinput(struct file *file, void *priv, { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - i->index = dev->audinput; + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) + i->index = 2; + else + i->index = dev->audinput; dprintk(1, "%s(input=%d)\n", __func__, i->index); return cx23885_query_audinput(file, priv, i); @@ -1435,7 +1439,12 @@ static int vidioc_s_audinput(struct file *file, void *priv, const struct v4l2_audio *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - if (i->index >= 2) + + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) { + return i->index != 2 ? -EINVAL : 0; + } + if (i->index > 1) return -EINVAL; dprintk(1, "%s(%d)\n", __func__, i->index); -- cgit v1.2.3 From 86dd9831aea494e3e5c565c697df60484f55780c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 05:32:58 -0300 Subject: [media] cx23885: support v4l2_fh and g/s_priority Add support for struct v4l2_fh and priority handling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 5 +++++ drivers/media/pci/cx23885/cx23885-video.c | 6 +++++- drivers/media/pci/cx23885/cx23885.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index bf89fc88692e..b65de33a6e23 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1550,6 +1550,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int mpeg_open(struct file *file) { + struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; @@ -1560,6 +1561,7 @@ static int mpeg_open(struct file *file) if (!fh) return -ENOMEM; + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; @@ -1569,6 +1571,7 @@ static int mpeg_open(struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct cx23885_buffer), fh, NULL); + v4l2_fh_add(&fh->fh); return 0; } @@ -1601,6 +1604,8 @@ static int mpeg_release(struct file *file) videobuf_read_stop(&fh->mpegq); videobuf_mmap_free(&fh->mpegq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 79de4acbf533..d575bfc8ac41 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -883,7 +883,8 @@ static int video_open(struct file *file) if (NULL == fh) return -ENOMEM; - file->private_data = fh; + v4l2_fh_init(&fh->fh, vdev); + file->private_data = &fh->fh; fh->dev = dev; fh->radio = radio; fh->type = type; @@ -905,6 +906,7 @@ static int video_open(struct file *file) sizeof(struct cx23885_buffer), fh, NULL); + v4l2_fh_add(&fh->fh); dprintk(1, "post videobuf_queue_init()\n"); @@ -1003,6 +1005,8 @@ static int video_release(struct file *file) videobuf_mmap_free(&fh->vidq); videobuf_mmap_free(&fh->vbiq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0e086c03da67..de164c986b1d 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -147,6 +148,7 @@ struct cx23885_tvnorm { }; struct cx23885_fh { + struct v4l2_fh fh; struct cx23885_dev *dev; enum v4l2_buf_type type; int radio; -- cgit v1.2.3 From 24a8f7b5648ff8dfd8d26f8444ab4b04286dba98 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 11:29:55 -0300 Subject: [media] cx23885: use core locking, switch to unlocked_ioctl Enable core locking which allows us to safely switch to unlocked_ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 5 ++-- drivers/media/pci/cx23885/cx23885-video.c | 43 +++++++------------------------ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index b65de33a6e23..395f7a987d61 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1235,9 +1235,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) dev->encodernorm = cx23885_tvnorms[i]; /* Have the drier core notify the subdevices */ - mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, id); - mutex_unlock(&dev->lock); return 0; } @@ -1661,7 +1659,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 = { @@ -1770,6 +1768,7 @@ int cx23885_417_register(struct cx23885_dev *dev) dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); video_set_drvdata(dev->v4l_device, dev); + dev->v4l_device->lock = &dev->lock; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index d575bfc8ac41..ba93e29bf158 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -345,6 +345,7 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; + vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); @@ -381,17 +382,14 @@ static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, return 1; /* is it free? */ - mutex_lock(&dev->lock); if (dev->resources & bit) { /* no, someone else uses it */ - mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); return 1; } @@ -411,11 +409,9 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, BUG_ON((fh->resources & bits) != bits); dprintk(1, "%s()\n", __func__); - mutex_lock(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); } int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) @@ -1272,9 +1268,7 @@ 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); - mutex_unlock(&dev->lock); return 0; } @@ -1364,13 +1358,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i) if (INPUT(i)->type == 0) return -EINVAL; - mutex_lock(&dev->lock); cx23885_video_mux(dev, i); /* By default establish the default audio input for the card also */ /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ cx23885_audio_mux(dev, i); - mutex_unlock(&dev->lock); return 0; } @@ -1544,7 +1536,6 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ @@ -1561,8 +1552,6 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency ctrl.value = 0; cx23885_set_control(dev, &ctrl); - mutex_unlock(&dev->lock); - return 0; } @@ -1580,7 +1569,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, .frequency = f->frequency }; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ @@ -1594,7 +1582,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { - mutex_unlock(&dev->lock); return -EINVAL; } @@ -1619,8 +1606,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, ctrl.value = 0; cx23885_set_control(dev, &ctrl); - mutex_unlock(&dev->lock); - return 0; } @@ -1742,7 +1727,7 @@ static const struct v4l2_file_operations video_fops = { .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1791,14 +1776,6 @@ static struct video_device cx23885_video_template = { .tvnorms = CX23885_NORMS, }; -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, -}; - - void cx23885_video_unregister(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); @@ -1909,6 +1886,14 @@ int cx23885_video_register(struct cx23885_dev *dev) } } + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + init_controls(dev); + cx23885_video_mux(dev, 0); + cx23885_audio_mux(dev, 0); + mutex_unlock(&dev->lock); + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); @@ -1938,14 +1923,6 @@ int cx23885_video_register(struct cx23885_dev *dev) /* Register ALSA audio device */ dev->audio_dev = cx23885_audio_register(dev); - /* initial device configuration */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); - cx23885_video_mux(dev, 0); - cx23885_audio_mux(dev, 0); - mutex_unlock(&dev->lock); - return 0; fail_unreg: -- cgit v1.2.3 From da59a4deb2e2430aac82e775bb2b0a67cbb48f11 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 06:34:44 -0300 Subject: [media] cx23885: convert to the control framework This is part 1, converting the uncompressed video/vbi nodes to use the control framework. The next patch converts the compressed video node as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 20 --- drivers/media/pci/cx23885/cx23885-core.c | 17 ++- drivers/media/pci/cx23885/cx23885-video.c | 246 +++++------------------------- drivers/media/pci/cx23885/cx23885.h | 12 +- 4 files changed, 51 insertions(+), 244 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 395f7a987d61..d44395ca3b77 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1313,22 +1313,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, return cx23885_set_frequency(file, priv, f); } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1672,8 +1656,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .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_g_ctrl = vidioc_g_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, @@ -1689,8 +1671,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .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, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, .vidioc_g_register = cx23885_g_register, diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index edcd79db1e4e..075b28eda8de 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2087,6 +2087,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct cx23885_dev *dev; + struct v4l2_ctrl_handler *hdl; int err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -2097,6 +2098,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev, if (err < 0) goto fail_free; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 6); + if (hdl->error) { + err = hdl->error; + goto fail_ctrl; + } + dev->v4l2_dev.ctrl_handler = hdl; + /* Prepare to handle notifications from subdevices */ cx23885_v4l2_dev_notify_init(dev); @@ -2104,12 +2113,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev, dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { err = -EIO; - goto fail_unreg; + goto fail_ctrl; } if (cx23885_dev_setup(dev) < 0) { err = -EINVAL; - goto fail_unreg; + goto fail_ctrl; } /* print pci info */ @@ -2157,7 +2166,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev, fail_irq: cx23885_dev_unregister(dev); -fail_unreg: +fail_ctrl: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); fail_free: kfree(dev); @@ -2180,6 +2190,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev) free_irq(pci_dev->irq, dev); cx23885_dev_unregister(dev); + v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(v4l2_dev); kfree(dev); } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index ba93e29bf158..090d48b427fd 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -35,6 +35,7 @@ #include "cx23885-video.h" #include #include +#include #include "cx23885-ioctl.h" #include "tuner-xc2028.h" @@ -170,119 +171,6 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) /* ------------------------------------------------------------------- */ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx23885_ctrl cx23885_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 = 0x7f, - .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 = -127, - .maximum = 128, - .step = 1, - .default_value = 0x0, - .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 = 0x7f, - .step = 1, - .default_value = 0x3f, - .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 = 65535, - .step = 65535 / 100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); - -/* Must be sorted from low to high control ID! */ -static const u32 cx23885_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx23885_user_ctrls, - NULL -}; - void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { @@ -352,24 +240,6 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -static int cx23885_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 < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == qctrl->id) - break; - if (i == CX23885_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx23885_ctls[i].v; - return 0; -} - /* ------------------------------------------------------------------- */ /* resource management */ @@ -936,12 +806,20 @@ static unsigned int video_poll(struct file *file, { struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; - unsigned int rc = POLLERR; + unsigned long req_events = poll_requested_events(wait); + unsigned int rc = 0; + + if (v4l2_event_pending(&fh->fh)) + rc = POLLPRI; + else + poll_wait(file, &fh->fh.wait, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return rc; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); + return rc | POLLERR; + return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } mutex_lock(&fh->vidq.vb_lock); @@ -960,9 +838,7 @@ static unsigned int video_poll(struct file *file, poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; + rc |= POLLIN | POLLRDNORM; done: mutex_unlock(&fh->vidq.vb_lock); return rc; @@ -1021,39 +897,6 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) return videobuf_mmap_mapper(get_queue(fh), vma); } -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -int cx23885_get_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); - call_all(dev, core, g_ctrl, ctl); - return 0; -} - -int cx23885_set_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); - call_all(dev, core, s_ctrl, ctl); - - return 0; -} - -static void init_controls(struct cx23885_dev *dev) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX23885_CTLS; i++) { - ctrl.id = cx23885_ctls[i].v.id; - ctrl.value = cx23885_ctls[i].v.default_value; - - cx23885_set_control(dev, &ctrl); - } -} - /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -1453,31 +1296,6 @@ static int vidioc_s_audinput(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx23885_ctrl_query(qctrl); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1529,7 +1347,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; + struct v4l2_ctrl *mute; + int old_mute_val = 1; if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1539,9 +1358,12 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } call_all(dev, tuner, s_frequency, f); @@ -1549,8 +1371,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1558,7 +1380,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; + struct v4l2_ctrl *mute; + int old_mute_val = 1; struct videobuf_dvb_frontend *vfe; struct dvb_frontend *fe; @@ -1572,9 +1395,12 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } /* If HVR1850 */ dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, @@ -1603,8 +1429,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1749,9 +1575,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_log_status = vidioc_log_status, - .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, @@ -1766,6 +1589,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enumaudio = vidioc_enum_audinput, .vidioc_g_audio = vidioc_g_audinput, .vidioc_s_audio = vidioc_s_audinput, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx23885_vbi_template; @@ -1889,7 +1714,6 @@ int cx23885_video_register(struct cx23885_dev *dev) /* initial device configuration */ mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); cx23885_video_mux(dev, 0); cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index de164c986b1d..516435c021e4 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -132,14 +133,6 @@ struct cx23885_fmt { u32 cxformat; }; -struct cx23885_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - struct cx23885_tvnorm { char *name; v4l2_std_id id; @@ -370,6 +363,7 @@ struct cx23885_audio_dev { struct cx23885_dev { atomic_t refcount; struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; /* pci stuff */ struct pci_dev *pci; @@ -597,8 +591,6 @@ 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, 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); /* ----------------------------------------------------------- */ -- cgit v1.2.3 From 5150392cd94c5a5a89b92e58ddc579f0de2d1a89 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:02:15 -0300 Subject: [media] cx23885: convert 417 to the control framework Convert the -417 source to the control framework as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 133 +++++------------------------- drivers/media/pci/cx23885/cx23885-video.c | 6 -- drivers/media/pci/cx23885/cx23885.h | 2 +- 3 files changed, 20 insertions(+), 121 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index d44395ca3b77..4142c15b259e 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -865,6 +865,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev, return err; } +static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + return cx23885_mbox_func(priv, cmd, in, out, data); +} + static int cx23885_find_mailbox(struct cx23885_dev *dev) { u32 signature[4] = { @@ -1033,12 +1038,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_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_params.is_50hz = + dev->cxhdl.width = dev->ts1.width; + dev->cxhdl.height = dev->ts1.height; + dev->cxhdl.is_50hz = (dev->encodernorm.id & V4L2_STD_625_50) != 0; - cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); + cx2341x_handler_setup(&dev->cxhdl); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); @@ -1182,36 +1187,6 @@ static struct videobuf_queue_ops cx23885_qops = { /* ------------------------------------------------------------------ */ -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; - -static int cx23885_queryctrl(struct cx23885_dev *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 cx23885_querymenu(struct cx23885_dev *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx23885_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 *priv, v4l2_std_id *id) { struct cx23885_fh *fh = file->private_data; @@ -1445,55 +1420,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->mpegq); } -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - 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 cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - - if (err == 0) { - err = cx2341x_update(dev, cx23885_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 cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - 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); - return err; -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_fh *fh = priv; @@ -1501,35 +1427,11 @@ static int vidioc_log_status(struct file *file, void *priv) char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); - printk(KERN_INFO - "%s/2: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - printk(KERN_INFO - "%s/2: ============= END LOG STATUS =============\n", - dev->name); + v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); return 0; } -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_queryctrl(dev, c); -} - static int mpeg_open(struct file *file) { struct video_device *vdev = video_devdata(file); @@ -1667,9 +1569,6 @@ 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, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, @@ -1694,6 +1593,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev) video_unregister_device(dev->v4l_device); else video_device_release(dev->v4l_device); + v4l2_ctrl_handler_free(&dev->cxhdl.hdl); dev->v4l_device = NULL; } } @@ -1740,9 +1640,14 @@ int cx23885_417_register(struct cx23885_dev *dev) tsport->height = 576; tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); - - dev->mpeg_params.port = CX2341X_PORT_SERIAL; + dev->cxhdl.port = CX2341X_PORT_SERIAL; + err = cx2341x_handler_init(&dev->cxhdl, 50); + if (err) + return err; + dev->cxhdl.priv = dev; + dev->cxhdl.func = cx23885_api_func; + cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576); + v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL); /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 090d48b427fd..116ce34c5168 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1219,13 +1219,7 @@ static int vidioc_log_status(struct file *file, void *priv) struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; - printk(KERN_INFO - "%s/0: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - printk(KERN_INFO - "%s/0: ============= END LOG STATUS =============\n", - dev->name); return 0; } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 516435c021e4..2d57af74b692 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -439,7 +439,7 @@ struct cx23885_dev { /* MPEG Encoder ONLY settings */ u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; + struct cx2341x_handler cxhdl; struct video_device *v4l_device; atomic_t v4l_reader_count; struct cx23885_tvnorm encodernorm; -- cgit v1.2.3 From 1af2ddd8b3fab054c908d24e00cb41f6b2b7d719 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:11:49 -0300 Subject: [media] cx23885: fix format colorspace compliance error Fix v4l2-compliance failure relating to formatting. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 116ce34c5168..ad02912e9ac3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -913,6 +913,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fh->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -957,6 +958,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (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; return 0; } -- cgit v1.2.3 From 200e0841ee4a05d06041fb25a8931a5dfb15c767 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:18:12 -0300 Subject: [media] cx23885: map invalid fields to a valid field If field format is not valid, map it as V4L2_FIELD_INTERLACED, instead of pretending to support an invalid format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index ad02912e9ac3..9bb19fdfac02 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -948,7 +948,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, case V4L2_FIELD_INTERLACED: break; default: - return -EINVAL; + field = V4L2_FIELD_INTERLACED; + break; } f->fmt.pix.field = field; -- cgit v1.2.3 From 8696193320118ba55e6469f49b33b4526c5cd5fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:22:06 -0300 Subject: [media] cx23885: drop radio-related dead code Currently no radio device nodes are ever created, so remove the dead radio code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 15 +++------------ drivers/media/pci/cx23885/cx23885.h | 3 --- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 9bb19fdfac02..50694c6f13d3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -49,15 +49,12 @@ MODULE_LICENSE("GPL"); static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug; module_param(video_debug, int, 0644); @@ -727,7 +724,6 @@ static int video_open(struct file *file) struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; enum v4l2_buf_type type = 0; - int radio = 0; switch (vdev->vfl_type) { case VFL_TYPE_GRABBER: @@ -736,13 +732,10 @@ static int video_open(struct file *file) case VFL_TYPE_VBI: type = V4L2_BUF_TYPE_VBI_CAPTURE; break; - case VFL_TYPE_RADIO: - radio = 1; - break; } - dprintk(1, "open dev=%s radio=%d type=%s\n", - video_device_node_name(vdev), radio, v4l2_type_names[type]); + dprintk(1, "open dev=%s type=%s\n", + video_device_node_name(vdev), v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -752,7 +745,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->radio = radio; fh->type = type; fh->width = 320; fh->height = 240; @@ -1333,8 +1325,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->type = V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; call_all(dev, tuner, g_frequency, f); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 2d57af74b692..94ab000ca16b 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -144,7 +144,6 @@ struct cx23885_fh { struct v4l2_fh fh; struct cx23885_dev *dev; enum v4l2_buf_type type; - int radio; u32 resources; /* video overlay */ @@ -413,7 +412,6 @@ struct cx23885_dev { unsigned int tuner_bus; unsigned int radio_type; unsigned char radio_addr; - unsigned int has_radio; struct v4l2_subdev *sd_cx25840; struct work_struct cx25840_work; @@ -431,7 +429,6 @@ struct cx23885_dev { u32 freq; struct video_device *video_dev; struct video_device *vbi_dev; - struct video_device *radio_dev; struct cx23885_dmaqueue vidq; struct cx23885_dmaqueue vbiq; -- cgit v1.2.3 From 1f159c77d068aff4c8ee7f7c84312b64ebef121c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:35:54 -0300 Subject: [media] cx23885: drop type field from struct cx23885_fh This information is available elsewhere as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 89 ++++++++++++++----------------- drivers/media/pci/cx23885/cx23885.h | 1 - 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 50694c6f13d3..a68ab59b39f7 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -692,28 +692,31 @@ static struct videobuf_queue_ops cx23885_video_qops = { .buf_release = buffer_release, }; -static struct videobuf_queue *get_queue(struct cx23885_fh *fh) +static struct videobuf_queue *get_queue(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + struct cx23885_fh *fh = file->private_data; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return &fh->vbiq; default: - BUG(); + WARN_ON(1); return NULL; } } -static int get_resource(struct cx23885_fh *fh) +static int get_resource(u32 type) { - switch (fh->type) { + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: return RESOURCE_VIDEO; case V4L2_BUF_TYPE_VBI_CAPTURE: return RESOURCE_VBI; default: - BUG(); + WARN_ON(1); return 0; } } @@ -723,19 +726,9 @@ static int video_open(struct file *file) struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; - enum v4l2_buf_type type = 0; - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - } - - dprintk(1, "open dev=%s type=%s\n", - video_device_node_name(vdev), v4l2_type_names[type]); + dprintk(1, "open dev=%s\n", + video_device_node_name(vdev)); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -745,7 +738,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->type = type; fh->width = 320; fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); @@ -774,28 +766,29 @@ static int video_open(struct file *file) static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = file->private_data; - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: if (res_locked(fh->dev, RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: if (!res_get(fh->dev, fh, RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, file->f_flags & O_NONBLOCK); default: - BUG(); - return 0; + return -EINVAL; } } static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; unsigned long req_events = poll_requested_events(wait); @@ -808,7 +801,7 @@ static unsigned int video_poll(struct file *file, if (!(req_events & (POLLIN | POLLRDNORM))) return rc; - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (vdev->vfl_type == VFL_TYPE_VBI) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) return rc | POLLERR; return rc | videobuf_poll_stream(file, &fh->vbiq, wait); @@ -884,9 +877,7 @@ static int video_release(struct file *file) static int video_mmap(struct file *file, struct vm_area_struct *vma) { - struct cx23885_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); + return videobuf_mmap_mapper(get_queue(file), vma); } /* ------------------------------------------------------------------ */ @@ -1019,73 +1010,73 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct cx23885_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); + return videobuf_reqbufs(get_queue(file), p); } static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); + return videobuf_querybuf(get_queue(file), p); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); + return videobuf_qbuf(get_queue(file), p); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_dqbuf(get_queue(fh), p, + return videobuf_dqbuf(get_queue(file), p, file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + if (vdev->vfl_type == VFL_TYPE_VBI && + i != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; - if (unlikely(i != fh->type)) + if (vdev->vfl_type == VFL_TYPE_GRABBER && + i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (unlikely(!res_get(dev, fh, get_resource(fh)))) + if (unlikely(!res_get(dev, fh, get_resource(i)))) return -EBUSY; /* Don't start VBI streaming unless vida streaming * has already started. */ - if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && + if ((i == V4L2_BUF_TYPE_VBI_CAPTURE) && ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) return -EINVAL; - return videobuf_streamon(get_queue(fh)); + return videobuf_streamon(get_queue(file)); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; int err, res; dprintk(1, "%s()\n", __func__); - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + if (vdev->vfl_type == VFL_TYPE_VBI && + i != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; - if (i != fh->type) + if (vdev->vfl_type == VFL_TYPE_GRABBER && + i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - res = get_resource(fh); - err = videobuf_streamoff(get_queue(fh)); + res = get_resource(i); + err = videobuf_streamoff(get_queue(file)); if (err < 0) return err; res_free(dev, fh, res); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 94ab000ca16b..aba1e6af41d6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -143,7 +143,6 @@ struct cx23885_tvnorm { struct cx23885_fh { struct v4l2_fh fh; struct cx23885_dev *dev; - enum v4l2_buf_type type; u32 resources; /* video overlay */ -- cgit v1.2.3 From e749c6e64c6a8b1323fad2330d73855cf072a3b9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:37:35 -0300 Subject: [media] cx23885: drop unused clip fields from struct cx23885_fh There is no overlay support, so drop these unused fields. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index aba1e6af41d6..a88e951a91b8 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -145,11 +145,6 @@ struct cx23885_fh { struct cx23885_dev *dev; u32 resources; - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - /* video capture */ struct cx23885_fmt *fmt; unsigned int width, height; -- cgit v1.2.3 From 91d2d6745205774b712727ede2a35c91e1eb4c48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:52:07 -0300 Subject: [media] cx23885: fmt, width and height are global, not per-fh Move these fields from cx23885_fh to cx23885_dev. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 125 +++++++----------------------- drivers/media/pci/cx23885/cx23885.h | 8 +- 2 files changed, 34 insertions(+), 99 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index a68ab59b39f7..3dcee0a01787 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -77,77 +77,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); /* static data */ #define FORMAT_FLAGS_PACKED 0x01 -#if 0 static struct cx23885_fmt formats[] = { { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .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, - }, -}; -#else -static struct cx23885_fmt formats[] = { - { -#if 0 - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { -#endif .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, } }; -#endif static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) { @@ -156,13 +93,6 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) return formats+i; - - printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, - (fourcc & 0xff), - ((fourcc >> 8) & 0xff), - ((fourcc >> 16) & 0xff), - ((fourcc >> 24) & 0xff) - ); return NULL; } @@ -502,8 +432,9 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; - *size = fh->fmt->depth*fh->width*fh->height >> 3; + *size = (dev->fmt->depth * dev->width * dev->height) >> 3; if (0 == *count) *count = 32; if (*size * *count > vid_limit * 1024 * 1024) @@ -523,21 +454,23 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int field_tff; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) + if (WARN_ON(NULL == dev->fmt)) + return -EINVAL; + + if (dev->width < 48 || dev->width > norm_maxw(dev->tvnorm) || + dev->height < 32 || dev->height > norm_maxh(dev->tvnorm)) return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + buf->vb.size = (dev->width * dev->height * dev->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 || + if (buf->fmt != dev->fmt || + buf->vb.width != dev->width || + buf->vb.height != dev->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; + buf->fmt = dev->fmt; + buf->vb.width = dev->width; + buf->vb.height = dev->height; buf->vb.field = field; init_buffer = 1; } @@ -612,7 +545,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } 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, + dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; @@ -738,9 +671,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, @@ -887,13 +817,14 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; + (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -951,7 +882,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = fh->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -960,12 +891,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; fh->vidq.field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - fh->width, fh->height, fh->vidq.field); + dev->width, dev->height, fh->vidq.field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); @@ -976,7 +907,8 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, @@ -1619,6 +1551,9 @@ int cx23885_video_register(struct cx23885_dev *dev) strcpy(cx23885_vbi_template.name, "cx23885-vbi"); dev->tvnorm = V4L2_STD_NTSC_M; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); + dev->width = norm_maxw(dev->tvnorm); + dev->height = norm_maxh(dev->tvnorm); /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index a88e951a91b8..260d17712ab4 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -145,10 +145,6 @@ struct cx23885_fh { struct cx23885_dev *dev; u32 resources; - /* video capture */ - struct cx23885_fmt *fmt; - unsigned int width, height; - /* vbi capture */ struct videobuf_queue vidq; struct videobuf_queue vbiq; @@ -424,6 +420,10 @@ struct cx23885_dev { struct video_device *video_dev; struct video_device *vbi_dev; + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + struct cx23885_dmaqueue vidq; struct cx23885_dmaqueue vbiq; spinlock_t slock; -- cgit v1.2.3 From 9529a4b0cf49163e489446ec159a2dfb64f78df8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 08:27:00 -0300 Subject: [media] cx23885: drop videobuf abuse in cx23885-alsa The alsa driver uses videobuf low-level functions that are not available in vb2, so replace them by driver-specific functions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-alsa.c | 96 ++++++++++++++++++++++++++++---- drivers/media/pci/cx23885/cx23885.h | 7 ++- 2 files changed, 88 insertions(+), 15 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 554798dcedd0..31dbf0c64578 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -84,6 +84,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); #define AUD_INT_MCHG_IRQ (1 << 21) #define GP_COUNT_CONTROL_RESET 0x3 +static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) +{ + struct cx23885_audio_buffer *buf = chip->buf; + struct page *pg; + int i; + + buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == buf->vaddr) { + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); + return -ENOMEM; + } + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)buf->vaddr, + nr_pages << PAGE_SHIFT); + + memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); + buf->nr_pages = nr_pages; + + buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + if (NULL == buf->sglist) + goto vzalloc_err; + + sg_init_table(buf->sglist, buf->nr_pages); + for (i = 0; i < buf->nr_pages; i++) { + pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); + if (NULL == pg) + goto vmalloc_to_page_err; + sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); + } + return 0; + +vmalloc_to_page_err: + vfree(buf->sglist); + buf->sglist = NULL; +vzalloc_err: + vfree(buf->vaddr); + buf->vaddr = NULL; + return -ENOMEM; +} + +static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, + buf->nr_pages, PCI_DMA_FROMDEVICE); + + if (0 == buf->sglen) { + pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + if (!buf->sglen) + return 0; + + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + buf->sglen = 0; + return 0; +} + +static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf) +{ + vfree(buf->sglist); + buf->sglist = NULL; + vfree(buf->vaddr); + buf->vaddr = NULL; + return 0; +} + /* * BOARD Specific: Sets audio DMA */ @@ -201,12 +277,12 @@ static int dsp_buffer_free(struct cx23885_audio_dev *chip) BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); + cx23885_alsa_dma_unmap(chip); + cx23885_alsa_dma_free(chip->buf); btcx_riscmem_free(chip->pci, &chip->buf->risc); kfree(chip->buf); - chip->dma_risc = NULL; + chip->buf = NULL; chip->dma_size = 0; return 0; @@ -289,6 +365,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream) return 0; } + /* * hw_params callback */ @@ -296,8 +373,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - struct cx23885_audio_buffer *buf; int ret; @@ -319,18 +394,16 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->bpl = chip->period_size; - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + ret = cx23885_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_dma_map(&chip->pci->dev, dma); + ret = cx23885_alsa_dma_map(chip); if (ret < 0) goto error; - ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist, + ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist, chip->period_size, chip->num_periods, 1); if (ret < 0) goto error; @@ -341,9 +414,8 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ chip->buf = buf; - chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 260d17712ab4..9cd2b1b31cec 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -324,7 +324,10 @@ struct cx23885_kernel_ir { struct cx23885_audio_buffer { unsigned int bpl; struct btcx_riscmem risc; - struct videobuf_dmabuf dma; + void *vaddr; + struct scatterlist *sglist; + int sglen; + int nr_pages; }; struct cx23885_audio_dev { @@ -342,8 +345,6 @@ struct cx23885_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf *dma_risc; - struct cx23885_audio_buffer *buf; struct snd_pcm_substream *substream; -- cgit v1.2.3 From 568f44a18e9b63fbb44fcb3292c3530087ae527b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 08:43:51 -0300 Subject: [media] cx23885: use video_drvdata to get cx23885_dev pointer Use video_drvdata(file) instead of fh->dev to get the cx23885_dev pointer. This prepares for the vb2 conversion where fh->dev (renamed to fh->q_dev in this patch) will be removed completely. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 56 +++++++++++++---------------- drivers/media/pci/cx23885/cx23885-ioctl.c | 6 ++-- drivers/media/pci/cx23885/cx23885-vbi.c | 7 ++-- drivers/media/pci/cx23885/cx23885-video.c | 60 +++++++++++++++---------------- drivers/media/pci/cx23885/cx23885.h | 2 +- 5 files changed, 60 insertions(+), 71 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 4142c15b259e..0948b44b1c5e 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1147,10 +1147,10 @@ static int bb_buf_setup(struct videobuf_queue *q, { struct cx23885_fh *fh = q->priv_data; - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; + fh->q_dev->ts1.ts_packet_size = mpeglinesize; + fh->q_dev->ts1.ts_packet_count = mpeglines; - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + *size = fh->q_dev->ts1.ts_packet_size * fh->q_dev->ts1.ts_packet_count; *count = mpegbufs; return 0; @@ -1160,7 +1160,7 @@ static int bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->dev->ts1, + return cx23885_buf_prepare(q, &fh->q_dev->ts1, (struct cx23885_buffer *)vb, field); } @@ -1169,7 +1169,7 @@ static void bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); + cx23885_buf_queue(&fh->q_dev->ts1, (struct cx23885_buffer *)vb); } static void bb_buf_release(struct videobuf_queue *q, @@ -1189,8 +1189,7 @@ static struct videobuf_queue_ops cx23885_qops = { static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); *id = dev->tvnorm; return 0; @@ -1198,8 +1197,7 @@ static int vidioc_g_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; + struct cx23885_dev *dev = video_drvdata(file); unsigned int i; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) @@ -1218,7 +1216,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } @@ -1236,8 +1234,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1254,8 +1251,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 cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1269,8 +1265,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 cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1291,8 +1286,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_tsport *tsport = &dev->ts1; strlcpy(cap->driver, dev->name, sizeof(cap->driver)); @@ -1325,8 +1319,8 @@ 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 *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1344,8 +1338,8 @@ 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 *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1360,8 +1354,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 *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1422,8 +1415,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); @@ -1434,8 +1426,8 @@ static int vidioc_log_status(struct file *file, void *priv) static int mpeg_open(struct file *file) { - struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh; dprintk(2, "%s()\n", __func__); @@ -1447,7 +1439,7 @@ static int mpeg_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; - fh->dev = dev; + fh->q_dev = dev; videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, &dev->pci->dev, &dev->ts1.slock, @@ -1461,8 +1453,8 @@ static int mpeg_open(struct file *file) static int mpeg_release(struct file *file) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); @@ -1471,14 +1463,14 @@ static int mpeg_release(struct file *file) if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { if (atomic_dec_return(&dev->v4l_reader_count) == 0) { /* stop mpeg capture */ - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, CX23885_END_NOW, CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); msleep(500); cx23885_417_check_encoder(dev); - cx23885_cancel_buffers(&fh->dev->ts1); + cx23885_cancel_buffers(&dev->ts1); } } @@ -1499,8 +1491,8 @@ static int mpeg_release(struct file *file) static ssize_t mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); @@ -1520,8 +1512,8 @@ static ssize_t mpeg_read(struct file *file, char __user *data, static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s\n", __func__); @@ -1530,8 +1522,8 @@ static unsigned int mpeg_poll(struct file *file, static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 271d69d1ca8c..9c16786371a2 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -28,7 +28,7 @@ int cx23885_g_chip_info(struct file *file, void *fh, struct v4l2_dbg_chip_info *chip) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (chip->match.addr > 1) return -EINVAL; @@ -64,7 +64,7 @@ static int cx23417_g_register(struct cx23885_dev *dev, int cx23885_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; @@ -96,7 +96,7 @@ static int cx23417_s_register(struct cx23885_dev *dev, int cx23885_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index a1154f035bc1..1cb67d38022a 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -50,8 +50,7 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ @@ -201,7 +200,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); @@ -242,7 +241,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vbiq; /* add jump to stopper */ diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 3dcee0a01787..b3740038cefb 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -432,7 +432,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; *size = (dev->fmt->depth * dev->width * dev->height) >> 3; if (0 == *count) @@ -446,7 +446,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); int rc, init_buffer = 0; @@ -562,7 +562,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct cx23885_buffer, vb); struct cx23885_buffer *prev; struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vidq; /* add jump to stopper */ @@ -670,7 +670,7 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; - fh->dev = dev; + fh->q_dev = dev; videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, @@ -697,16 +697,17 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; switch (vdev->vfl_type) { case VFL_TYPE_GRABBER: - if (res_locked(fh->dev, RESOURCE_VIDEO)) + if (res_locked(dev, RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); case VFL_TYPE_VBI: - if (!res_get(fh->dev, fh, RESOURCE_VBI)) + if (!res_get(dev, fh, RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, file->f_flags & O_NONBLOCK); @@ -719,6 +720,7 @@ static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; unsigned long req_events = poll_requested_events(wait); @@ -732,7 +734,7 @@ static unsigned int video_poll(struct file *file, return rc; if (vdev->vfl_type == VFL_TYPE_VBI) { - if (!res_get(fh->dev, fh, RESOURCE_VBI)) + if (!res_get(dev, fh, RESOURCE_VBI)) return rc | POLLERR; return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } @@ -761,8 +763,8 @@ done: static int video_release(struct file *file) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { @@ -816,8 +818,8 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -835,7 +837,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 *f) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; @@ -881,8 +883,8 @@ 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 *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -906,9 +908,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, @@ -967,9 +968,9 @@ static int vidioc_dqbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); if (vdev->vfl_type == VFL_TYPE_VBI && @@ -994,9 +995,9 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; int err, res; dprintk(1, "%s()\n", __func__); @@ -1017,7 +1018,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); *id = dev->tvnorm; @@ -1026,7 +1027,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); cx23885_set_tvnorm(dev, tvnorms); @@ -1086,14 +1087,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); *i = dev->input; dprintk(1, "%s() returns %d\n", __func__, *i); @@ -1107,7 +1108,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) int cx23885_set_input(struct file *file, void *priv, unsigned int i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s(%d)\n", __func__, i); @@ -1134,8 +1135,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); call_all(dev, core, log_status); return 0; @@ -1144,7 +1144,7 @@ static int vidioc_log_status(struct file *file, void *priv) static int cx23885_query_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", @@ -1174,7 +1174,7 @@ static int vidioc_enum_audinput(struct file *file, void *priv, static int vidioc_g_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) @@ -1189,7 +1189,7 @@ static int vidioc_g_audinput(struct file *file, void *priv, static int vidioc_s_audinput(struct file *file, void *priv, const struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) { @@ -1211,7 +1211,7 @@ static int vidioc_s_audinput(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1227,7 +1227,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 cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1242,8 +1242,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 cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1349,8 +1348,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); int ret; switch (dev->board) { diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 9cd2b1b31cec..95f8c422a3d6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -142,8 +142,8 @@ struct cx23885_tvnorm { struct cx23885_fh { struct v4l2_fh fh; - struct cx23885_dev *dev; u32 resources; + struct cx23885_dev *q_dev; /* vbi capture */ struct videobuf_queue vidq; -- cgit v1.2.3 From 0310539723fb173c398ad1a0da2683d41d20dba5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 20:43:16 -0300 Subject: [media] cx23885: remove FSF address as per checkpatch These addresses are usually out-of-date and the top-level license will always have the right address. So drop it from these sources. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/altera-ci.c | 4 ---- drivers/media/pci/cx23885/altera-ci.h | 4 ---- drivers/media/pci/cx23885/cimax2.c | 4 ---- drivers/media/pci/cx23885/cimax2.h | 4 ---- drivers/media/pci/cx23885/cx23885-417.c | 4 ---- drivers/media/pci/cx23885/cx23885-alsa.c | 4 ---- drivers/media/pci/cx23885/cx23885-av.c | 5 ----- drivers/media/pci/cx23885/cx23885-av.h | 5 ----- drivers/media/pci/cx23885/cx23885-cards.c | 6 ------ drivers/media/pci/cx23885/cx23885-core.c | 4 ---- drivers/media/pci/cx23885/cx23885-dvb.c | 5 ----- drivers/media/pci/cx23885/cx23885-f300.c | 4 ---- drivers/media/pci/cx23885/cx23885-i2c.c | 12 ------------ drivers/media/pci/cx23885/cx23885-input.c | 5 ----- drivers/media/pci/cx23885/cx23885-input.h | 5 ----- drivers/media/pci/cx23885/cx23885-ioctl.c | 4 ---- drivers/media/pci/cx23885/cx23885-ioctl.h | 4 ---- drivers/media/pci/cx23885/cx23885-ir.c | 5 ----- drivers/media/pci/cx23885/cx23885-ir.h | 5 ----- drivers/media/pci/cx23885/cx23885-reg.h | 4 ---- drivers/media/pci/cx23885/cx23885-vbi.c | 4 ---- drivers/media/pci/cx23885/cx23885-video.c | 5 ----- drivers/media/pci/cx23885/cx23885-video.h | 5 ----- drivers/media/pci/cx23885/cx23885.h | 4 ---- drivers/media/pci/cx23885/cx23888-ir.c | 5 ----- drivers/media/pci/cx23885/cx23888-ir.h | 5 ----- drivers/media/pci/cx23885/netup-eeprom.c | 4 ---- drivers/media/pci/cx23885/netup-eeprom.h | 4 ---- drivers/media/pci/cx23885/netup-init.c | 4 ---- drivers/media/pci/cx23885/netup-init.h | 4 ---- 30 files changed, 141 deletions(-) diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 2926f7fadccd..8302d444a0ba 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -16,10 +16,6 @@ * 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. */ /* diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 4998c96caebe..5028f0cf83f4 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -16,10 +16,6 @@ * 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 __ALTERA_CI_H #define __ALTERA_CI_H diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 16fa7ea4d4aa..631e4f24aea6 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -17,10 +17,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h index 518744a4c8a5..565e958f6f8d 100644 --- a/drivers/media/pci/cx23885/cimax2.h +++ b/drivers/media/pci/cx23885/cimax2.h @@ -17,10 +17,6 @@ * 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 CIMAX2_H diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 0948b44b1c5e..56673b52c559 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -18,10 +18,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 31dbf0c64578..c17e4740d47c 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -15,10 +15,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c index c443b7ac5adf..877dad89107e 100644 --- a/drivers/media/pci/cx23885/cx23885-av.c +++ b/drivers/media/pci/cx23885/cx23885-av.c @@ -14,11 +14,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h index d2915c3e53a2..97f232f8efb9 100644 --- a/drivers/media/pci/cx23885/cx23885-av.h +++ b/drivers/media/pci/cx23885/cx23885-av.h @@ -14,11 +14,6 @@ * 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 _CX23885_AV_H_ diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c2b608007190..21e500b0a220 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -13,10 +13,6 @@ * 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 @@ -1970,5 +1966,3 @@ void cx23885_card_setup(struct cx23885_dev *dev) } } } - -/* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 075b28eda8de..0b6bbac6990f 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 968fecc32f9c..ccf413f3c4ff 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -13,10 +13,6 @@ * 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 @@ -1668,4 +1664,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } - diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 5444cc526008..6f817d8732da 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -22,10 +22,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 4887314339cb..fd71306af6e2 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -13,10 +13,6 @@ * 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 @@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable) i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); } - -/* ----------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 1940c18e186c..9d37fe661691 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -28,11 +28,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h index 87dc44e69977..6199c7e86e83 100644 --- a/drivers/media/pci/cx23885/cx23885-input.h +++ b/drivers/media/pci/cx23885/cx23885-input.h @@ -14,11 +14,6 @@ * 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 _CX23885_INPUT_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 9c16786371a2..d2cdd40f79f5 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -15,10 +15,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h index 92d9f0774366..cc5dbb6c1afc 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.h +++ b/drivers/media/pci/cx23885/cx23885-ioctl.h @@ -15,10 +15,6 @@ * 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 _CX23885_IOCTL_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c index bfef19359291..89dc4cc3e1ce 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.c +++ b/drivers/media/pci/cx23885/cx23885-ir.c @@ -14,11 +14,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h index 0c9d8bda9e28..8e93d1f10ae0 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.h +++ b/drivers/media/pci/cx23885/cx23885-ir.h @@ -14,11 +14,6 @@ * 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 _CX23885_IR_H_ diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h index a99936e0cbc2..2d3cbafe2402 100644 --- a/drivers/media/pci/cx23885/cx23885-reg.h +++ b/drivers/media/pci/cx23885/cx23885-reg.h @@ -13,10 +13,6 @@ * 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 _CX23885_REG_H_ diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 1cb67d38022a..23790fadc6d5 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index b3740038cefb..9cd8cf48334b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -13,10 +13,6 @@ * 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 @@ -1665,4 +1661,3 @@ fail_unreg: cx23885_video_unregister(dev); return err; } - diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h index c961a2b0de0f..291e8f3189f0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.h +++ b/drivers/media/pci/cx23885/cx23885-video.h @@ -12,11 +12,6 @@ * 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 _CX23885_VIDEO_H_ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 95f8c422a3d6..5f5d8e8aa472 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index c2ff5fc01157..c1aa888af705 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -14,11 +14,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h index d2de41caaf1d..ff74a93575d6 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.h +++ b/drivers/media/pci/cx23885/cx23888-ir.h @@ -14,11 +14,6 @@ * 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 _CX23888_IR_H_ diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c index 98a48f500684..b6542ee4385b 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.c +++ b/drivers/media/pci/cx23885/netup-eeprom.c @@ -17,10 +17,6 @@ * 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. */ # diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h index 13926e18feba..90cac5b655d5 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.h +++ b/drivers/media/pci/cx23885/netup-eeprom.h @@ -16,10 +16,6 @@ * 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 NETUP_EEPROM_H diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c index 0044fef7ca24..76d9487aafc8 100644 --- a/drivers/media/pci/cx23885/netup-init.c +++ b/drivers/media/pci/cx23885/netup-init.c @@ -17,10 +17,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h index d26ae4b1590e..daaa212adfba 100644 --- a/drivers/media/pci/cx23885/netup-init.h +++ b/drivers/media/pci/cx23885/netup-init.h @@ -17,9 +17,5 @@ * 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. */ extern void netup_initialize(struct cx23885_dev *dev); -- cgit v1.2.3 From 3ee733ea9c3d7c31469ec4f88319d32f019b8d09 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 18:55:23 -0300 Subject: [media] img-ir: fix sparse warnings drivers/media/rc/img-ir/img-ir-nec.c:111:23: warning: symbol 'img_ir_nec' was not declared. Should it be static? drivers/media/rc/img-ir/img-ir-jvc.c:54:23: warning: symbol 'img_ir_jvc' was not declared. Should it be static? drivers/media/rc/img-ir/img-ir-sony.c:120:23: warning: symbol 'img_ir_sony' was not declared. Should it be static? drivers/media/rc/img-ir/img-ir-sharp.c:75:23: warning: symbol 'img_ir_sharp' was not declared. Should it be static? drivers/media/rc/img-ir/img-ir-sanyo.c:82:23: warning: symbol 'img_ir_sanyo' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-hw.c | 6 ------ drivers/media/rc/img-ir/img-ir-hw.h | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index bfb282a714e8..ec49f94425fc 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -25,12 +25,6 @@ /* Decoders lock (only modified to preprocess them) */ static DEFINE_SPINLOCK(img_ir_decoders_lock); -extern struct img_ir_decoder img_ir_nec; -extern struct img_ir_decoder img_ir_jvc; -extern struct img_ir_decoder img_ir_sony; -extern struct img_ir_decoder img_ir_sharp; -extern struct img_ir_decoder img_ir_sanyo; - static bool img_ir_decoders_preprocessed; static struct img_ir_decoder *img_ir_decoders[] = { #ifdef CONFIG_IR_IMG_NEC diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 3e40ce87b898..8fcc16c32c5b 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -168,6 +168,12 @@ struct img_ir_decoder { struct img_ir_filter *out, u64 protocols); }; +extern struct img_ir_decoder img_ir_nec; +extern struct img_ir_decoder img_ir_jvc; +extern struct img_ir_decoder img_ir_sony; +extern struct img_ir_decoder img_ir_sharp; +extern struct img_ir_decoder img_ir_sanyo; + /** * struct img_ir_reg_timings - Reg values for decoder timings at clock rate. * @ctrl: Processed control register value. -- cgit v1.2.3 From c44b6484db6e285cbc63bb8d400b5e8873e3a8d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:27:38 -0300 Subject: [media] solo6x10: fix sparse warnings drivers/media/pci/solo6x10/solo6x10-disp.c:184:24: warning: incorrect type in assignment (different base types) drivers/media/pci/solo6x10/solo6x10-disp.c:223:32: warning: incorrect type in assignment (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-disp.c | 4 ++-- drivers/media/pci/solo6x10/solo6x10-eeprom.c | 8 ++++---- drivers/media/pci/solo6x10/solo6x10.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c index 5ea9cac03968..11c98f0625e4 100644 --- a/drivers/media/pci/solo6x10/solo6x10-disp.c +++ b/drivers/media/pci/solo6x10/solo6x10-disp.c @@ -172,7 +172,7 @@ static void solo_vout_config(struct solo_dev *solo_dev) static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, u16 val, int reg_size) { - u16 *buf; + __le16 *buf; const int n = 64, size = n * sizeof(*buf); int i, ret = 0; @@ -211,7 +211,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, { const unsigned size = sizeof(u16) * 64; u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; - u16 *buf; + __le16 *buf; int x, y; int ret = 0; diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c index af40b3aba410..da25ce4a6952 100644 --- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c +++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c @@ -100,7 +100,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) return retval; } -unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) +__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc) { int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); unsigned short retval = 0; @@ -117,11 +117,11 @@ unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) solo_eeprom_reg_write(solo_dev, ~EE_CS); - return retval; + return (__force __be16)retval; } int solo_eeprom_write(struct solo_dev *solo_dev, int loc, - unsigned short data) + __be16 data) { int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); unsigned int retval; @@ -130,7 +130,7 @@ int solo_eeprom_write(struct solo_dev *solo_dev, int loc, solo_eeprom_cmd(solo_dev, write_cmd); for (i = 15; i >= 0; i--) { - unsigned int dataval = (data >> i) & 1; + unsigned int dataval = ((__force unsigned)data >> i) & 1; solo_eeprom_reg_write(solo_dev, EE_ENB); solo_eeprom_reg_write(solo_dev, diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index c6154b00fcbd..72017b7f0a75 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -394,9 +394,9 @@ 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); +__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc); int solo_eeprom_write(struct solo_dev *solo_dev, int loc, - unsigned short data); + __be16 data); /* JPEG Qp functions */ void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, -- cgit v1.2.3 From 6c5c680b85deb98e1b90b5b3e112a6fa82c70b12 Mon Sep 17 00:00:00 2001 From: Zhaowei Yuan Date: Tue, 5 Aug 2014 22:22:08 -0300 Subject: [media] media: s5p_mfc: Release ctx->ctx if failed to allocate ctx->shm ctx->ctx should be released if the following allocation for ctx->shm gets failed. Signed-off-by: Zhaowei Yuan Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 1 + 1 file changed, 1 insertion(+) 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 31688cddfead..f88290556e2a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -228,6 +228,7 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->shm); if (ret) { mfc_err("Failed to allocate shared memory buffer\n"); + s5p_mfc_release_priv_buf(dev->mem_dev_l, &ctx->ctx); return ret; } -- cgit v1.2.3 From e47ccb1de5db8723b222149004584279a299571f Mon Sep 17 00:00:00 2001 From: Zhaowei Yuan Date: Wed, 13 Aug 2014 23:11:47 -0300 Subject: [media] media: s5p-mfc: correct improper logs This patch corrects improper logs within the code initializing hardware. Signed-off-by: Zhaowei Yuan Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 5289b8696c1e..23d247d535a0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -258,9 +258,9 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_off(); return ret; } - mfc_debug(2, "Ok, now will write a command to init the system\n"); + mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { - mfc_err("Failed to load firmware\n"); + mfc_err("Failed to init hardware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); return -EIO; -- cgit v1.2.3 From 0c2272170d78f826f6e97f99fb8a67fc17feef07 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 27 Aug 2014 09:36:28 -0300 Subject: [media] media: s5p-mfc: rename special clock to sclk_mfc Commit d19f405a5a8d2ed942b40f8cf7929a5a50d0cc59 ("[media] s5p-mfc: Fix selective sclk_mfc init") added support for special clock handling (named "sclk-mfc"). However this clock is not defined yet on any platform, so before adding it to all Exynos platform, better rename it to "sclk_mfc" to match the scheme used for all other special clocks on Exynos platform. Signed-off-by: Marek Szyprowski Acked-by: Sylwester Nawrocki Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index b6a8be97a96c..826c48945bf5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -21,7 +21,7 @@ #include "s5p_mfc_pm.h" #define MFC_GATE_CLK_NAME "mfc" -#define MFC_SCLK_NAME "sclk-mfc" +#define MFC_SCLK_NAME "sclk_mfc" #define MFC_SCLK_RATE (200 * 1000000) #define CLK_DEBUG -- cgit v1.2.3 From 0cd9b21ed5453055752e7f8ef4887fbc409b77dc Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 1 Sep 2014 10:05:49 -0300 Subject: [media] s5p-jpeg: Avoid assigning readl result Avoid gcc warning when -Wunused-but-set-variable is enabled. The readl return value need not to be assigned to any variable as the reading itself is just a part of a sequence required for clearing the interrupt flag. Signed-off-by: Jacek Anaszewski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index 0d37bed088df..e3b8e67e005f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -324,11 +324,9 @@ int s5p_jpeg_stream_stat_ok(void __iomem *regs) void s5p_jpeg_clear_int(void __iomem *regs) { - unsigned long reg; - readl(regs + S5P_JPGINTST); writel(S5P_INT_RELEASE, regs + S5P_JPGCOM); - reg = readl(regs + S5P_JPGOPR); + readl(regs + S5P_JPGOPR); } unsigned int s5p_jpeg_compressed_size(void __iomem *regs) -- cgit v1.2.3 From 37a4bd757ce19a6f58339f8c3b85551f43911764 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 1 Sep 2014 10:05:50 -0300 Subject: [media] s5p-jpeg: remove stray call to readl There is no need to read INT_EN_REG before enabling interrupts. Signed-off-by: Jacek Anaszewski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index da8d6a1a984f..2de81c7d38d1 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -151,9 +151,6 @@ void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt) void exynos4_jpeg_set_interrupt(void __iomem *base) { - unsigned int reg; - - reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK; writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG); } -- cgit v1.2.3 From d727ff4241e4ed2f4f93816460b2af0567f0e3c1 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 1 Sep 2014 10:05:51 -0300 Subject: [media] s5p-jpeg: avoid overwriting JPEG_CNTL register settings Take into account the JPEG_CNTL register value read before setting SYS_INT_EN bit field. Signed-off-by: Jacek Anaszewski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index 2de81c7d38d1..d9ce40f8fbb0 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -193,9 +193,9 @@ void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value) reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN); if (value == 1) - writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); + writel(reg | EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); else - writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); + writel(reg & ~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG); } void exynos4_jpeg_set_stream_buf_address(void __iomem *base, -- cgit v1.2.3 From 5da74fc66b58a943e32e8c8b59e8e7c719ab611b Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 1 Sep 2014 10:05:52 -0300 Subject: [media] s5p-jpeg: fix HUF_TBL_EN bit clearing path Use proper bitwise operator while clearing HUF_TBL_EN bit. Signed-off-by: Jacek Anaszewski Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index d9ce40f8fbb0..e51c078360f5 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -182,7 +182,7 @@ void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value) writel(reg | EXYNOS4_HUF_TBL_EN, base + EXYNOS4_JPEG_CNTL_REG); else - writel(reg | ~EXYNOS4_HUF_TBL_EN, + writel(reg & ~EXYNOS4_HUF_TBL_EN, base + EXYNOS4_JPEG_CNTL_REG); } -- cgit v1.2.3 From 4bf167a373bbbd31efddd9c00adc97ecc69fdb67 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 1 Sep 2014 10:18:02 -0300 Subject: [media] v4l: vsp1: fix driver dependencies Renesas VSP1 Video Processing Engine support should be available only on Renesas ARM SoCs. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Cc: Simon Horman Cc: Magnus Damm Acked-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9037b8cf0a4b..bee9074ebc13 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -231,7 +231,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on HAS_DMA + depends on ARCH_SHMOBILE || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. -- cgit v1.2.3 From b565e71dd2805f6efb99cfb31b1f116cdea974d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:32:26 -0300 Subject: [media] dibusb: fix sparse warnings drivers/media/usb/dvb-usb/dibusb-common.c:261:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dibusb-common.c:262:52: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dibusb-common.c:300:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dibusb-common.c:301:44: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dibusb-common.c:313:47: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dibusb-common.c:314:47: warning: restricted __le16 degrades to integer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dibusb-common.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index 6d68af0c49c8..ef3a8f75f82e 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -258,8 +258,8 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) { - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == + if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && + le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) { msleep(1000); } @@ -297,8 +297,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *tun_i2c; // First IF calibration for Liteon Sticks - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { + if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON && + le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) { dibusb_read_eeprom_byte(adap->dev,0x7E,&a); dibusb_read_eeprom_byte(adap->dev,0x7F,&b); @@ -310,8 +310,8 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) else warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); - } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && - adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { + } else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM && + le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) { u8 desc; dibusb_read_eeprom_byte(adap->dev, 7, &desc); if (desc == 2) { -- cgit v1.2.3 From 744263246d8cdb838db5bc7743f9220de016f7dc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:34:27 -0300 Subject: [media] af9015: fix sparse warning drivers/media/usb/dvb-usb-v2/af9015.c:422:38: warning: cast to restricted __le32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 5ca738ab44e0..16c0b7d4f8e7 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -419,7 +419,7 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d) /* calculate checksum */ for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) { state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; - state->eeprom_sum += le32_to_cpu(((u32 *)buf)[i]); + state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]); } for (i = 0; i < AF9015_EEPROM_SIZE; i += 16) -- cgit v1.2.3 From 7754622baa7220d7048a5b97435adff1dfb15dbb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:40:00 -0300 Subject: [media] radio-tea5764: fix sparse warnings drivers/media/radio/radio-tea5764.c:168:24: warning: cast to restricted __be16 drivers/media/radio/radio-tea5764.c:168:24: warning: cast to restricted __be16 drivers/media/radio/radio-tea5764.c:168:24: warning: cast to restricted __be16 drivers/media/radio/radio-tea5764.c:168:24: warning: cast to restricted __be16 drivers/media/radio/radio-tea5764.c:185:20: warning: incorrect type in assignment (different base types) drivers/media/radio/radio-tea5764.c:186:20: warning: incorrect type in assignment (different base types) drivers/media/radio/radio-tea5764.c:187:20: warning: incorrect type in assignment (different base types) drivers/media/radio/radio-tea5764.c:188:20: warning: incorrect type in assignment (different base types) drivers/media/radio/radio-tea5764.c:189:20: warning: incorrect type in assignment (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-tea5764.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 925049654c5b..cc3990111411 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -124,11 +124,11 @@ struct tea5764_regs { struct tea5764_write_regs { u8 intreg; /* INTMSK */ - u16 frqset; /* FRQSETMSB & FRQSETLSB */ - u16 tnctrl; /* TNCTRL1 & TNCTRL2 */ - u16 testreg; /* TESTBITS & TESTMODE */ - u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ - u16 rdsbbl; /* PAUSEDET & RDSBBL */ + __be16 frqset; /* FRQSETMSB & FRQSETLSB */ + __be16 tnctrl; /* TNCTRL1 & TNCTRL2 */ + __be16 testreg; /* TESTBITS & TESTMODE */ + __be16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */ + __be16 rdsbbl; /* PAUSEDET & RDSBBL */ } __attribute__ ((packed)); #ifdef CONFIG_RADIO_TEA5764_XTAL @@ -165,7 +165,7 @@ static int tea5764_i2c_read(struct tea5764_device *radio) if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1) return -EIO; for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++) - p[i] = __be16_to_cpu(p[i]); + p[i] = __be16_to_cpu((__force __be16)p[i]); return 0; } -- cgit v1.2.3 From 1ad5d0645ec8c2b4b1ca9d146530bf9b755d8920 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:45:27 -0300 Subject: [media] dw2102: fix sparse warnings drivers/media/usb/dvb-usb/dw2102.c:670:65: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1601:32: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1644:40: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/dw2102.c:1904:34: warning: symbol 'p1100' was not declared. Should it be static? drivers/media/usb/dvb-usb/dw2102.c:1911:34: warning: symbol 's660' was not declared. Should it be static? drivers/media/usb/dvb-usb/dw2102.c:1930:34: warning: symbol 'p7500' was not declared. Should it be static? drivers/media/usb/dvb-usb/dw2102.c:1937:34: warning: symbol 's421' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 2add8c507ec9..1a3df10d6bad 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -667,7 +667,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); dw210x_op_rw(d->udev, - udev->descriptor.idProduct == + le16_to_cpu(udev->descriptor.idProduct) == 0x7500 ? 0x92 : 0x90, 0, 0, obuf, msg[j].len + 2, DW210X_WRITE_MSG); @@ -1598,7 +1598,7 @@ static int dw2102_load_firmware(struct usb_device *dev, u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; const struct firmware *fw; - switch (dev->descriptor.idProduct) { + switch (le16_to_cpu(dev->descriptor.idProduct)) { case 0x2101: ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev); if (ret != 0) { @@ -1641,7 +1641,7 @@ static int dw2102_load_firmware(struct usb_device *dev, ret = -EINVAL; } /* init registers */ - switch (dev->descriptor.idProduct) { + switch (le16_to_cpu(dev->descriptor.idProduct)) { case USB_PID_TEVII_S650: dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC; case USB_PID_DW2104: @@ -1901,14 +1901,14 @@ static struct dvb_usb_device_properties s6x0_properties = { } }; -struct dvb_usb_device_properties *p1100; +static struct dvb_usb_device_properties *p1100; static struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", {&dw2102_table[PROF_1100], NULL}, {NULL}, }; -struct dvb_usb_device_properties *s660; +static struct dvb_usb_device_properties *s660; static struct dvb_usb_device_description d660 = { "TeVii S660 USB", {&dw2102_table[TEVII_S660], NULL}, @@ -1927,14 +1927,14 @@ static struct dvb_usb_device_description d480_2 = { {NULL}, }; -struct dvb_usb_device_properties *p7500; +static struct dvb_usb_device_properties *p7500; static struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", {&dw2102_table[PROF_7500], NULL}, {NULL}, }; -struct dvb_usb_device_properties *s421; +static struct dvb_usb_device_properties *s421; static struct dvb_usb_device_description d421 = { "TeVii S421 PCI", {&dw2102_table[TEVII_S421], NULL}, -- cgit v1.2.3 From ed26716521a2fc7e41b6c98e046987f8f00a3155 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:48:07 -0300 Subject: [media] mxl111sf: fix sparse warnings drivers/media/usb/dvb-usb-v2/mxl111sf.c:34:5: warning: symbol 'dvb_usb_mxl111sf_isoc' was not declared. Should it be static? drivers/media/usb/dvb-usb-v2/mxl111sf.c:38:5: warning: symbol 'dvb_usb_mxl111sf_spi' was not declared. Should it be static? drivers/media/usb/dvb-usb-v2/mxl111sf.c:46:5: warning: symbol 'dvb_usb_mxl111sf_rfswitch' was not declared. Should it be static? drivers/media/usb/dvb-usb-v2/mxl111sf.c:890:22: warning: symbol 'mxl111sf_i2c_algo' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index b8a707e57b99..c3447eaf1104 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -31,11 +31,11 @@ module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level " "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); -int dvb_usb_mxl111sf_isoc; +static int dvb_usb_mxl111sf_isoc; module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); -int dvb_usb_mxl111sf_spi; +static int dvb_usb_mxl111sf_spi; module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644); MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); @@ -43,7 +43,7 @@ MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi)."); #define ANT_PATH_EXTERNAL 1 #define ANT_PATH_INTERNAL 2 -int dvb_usb_mxl111sf_rfswitch = +static int dvb_usb_mxl111sf_rfswitch = #if 0 ANT_PATH_AUTO; #else @@ -887,7 +887,7 @@ static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -struct i2c_algorithm mxl111sf_i2c_algo = { +static struct i2c_algorithm mxl111sf_i2c_algo = { .master_xfer = mxl111sf_i2c_xfer, .functionality = mxl111sf_i2c_func, #ifdef NEED_ALGO_CONTROL -- cgit v1.2.3 From 18d6a28ac0613d86241c7271aab3f6562d6c8995 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:50:21 -0300 Subject: [media] opera1: fix sparse warnings drivers/media/usb/dvb-usb/opera1.c:557:29: warning: restricted __le16 degrades to integer drivers/media/usb/dvb-usb/opera1.c:558:33: warning: restricted __le16 degrades to integer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/opera1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c index 16ba90acf539..14a2119912ba 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -554,8 +554,8 @@ static int opera1_probe(struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); - if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM && - udev->descriptor.idVendor == USB_VID_OPERA1 && + if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM && + le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 && opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0 ) { return -EINVAL; -- cgit v1.2.3 From ee40d32fc2a8749a89c1a372a46d619158c2d367 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:53:30 -0300 Subject: [media] pctv452e: fix sparse warnings drivers/media/usb/dvb-usb/pctv452e.c:886:64: warning: Using plain integer as NULL pointer drivers/media/usb/dvb-usb/pctv452e.c:903:63: warning: Using plain integer as NULL pointer drivers/media/usb/dvb-usb/pctv452e.c:968:19: warning: Using plain integer as NULL pointer drivers/media/usb/dvb-usb/pctv452e.c:1026:19: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/pctv452e.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index bdfe8963591c..d17618fe8f5c 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -883,7 +883,7 @@ static int pctv452e_frontend_attach(struct dvb_usb_adapter *a) if (!a->fe_adap[0].fe) return -ENODEV; if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe, - &a->dev->i2c_adap)) == 0) + &a->dev->i2c_adap)) == NULL) err("Cannot attach lnbp22\n"); id = a->dev->desc->warm_ids[0]; @@ -900,7 +900,7 @@ static int pctv452e_tuner_attach(struct dvb_usb_adapter *a) if (!a->fe_adap[0].fe) return -ENODEV; if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config, - &a->dev->i2c_adap) == 0) { + &a->dev->i2c_adap) == NULL) { err("%s failed\n", __func__); return -ENODEV; } @@ -965,7 +965,7 @@ static struct dvb_usb_device_properties pctv452e_properties = { .cold_ids = { NULL, NULL }, /* this is a warm only device */ .warm_ids = { &pctv452e_usb_table[0], NULL } }, - { 0 }, + { NULL }, } }; @@ -1023,7 +1023,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { .cold_ids = { NULL, NULL }, .warm_ids = { &pctv452e_usb_table[2], NULL } }, - { 0 }, + { NULL }, } }; -- cgit v1.2.3 From 616e3506a95d7ec7e308876cc3fd6144da59dece Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:55:35 -0300 Subject: [media] go7007: fix sparse warnings drivers/media/usb/go7007/go7007-usb.c:699:30: warning: cast to restricted __le16 drivers/media/usb/go7007/go7007-usb.c:769:38: warning: cast to restricted __le16 drivers/media/usb/go7007/go7007-usb.c:770:39: warning: cast to restricted __le16 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/go7007/go7007-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index ece27ece8115..3f986e1178ce 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -696,7 +696,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, sizeof(status_reg), timeout); if (r < 0) break; - status_reg = le16_to_cpu(*((u16 *)go->usb_buf)); + status_reg = le16_to_cpu(*((__le16 *)go->usb_buf)); if (!(status_reg & 0x0010)) break; msleep(10); @@ -751,7 +751,7 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, static void go7007_usb_readinterrupt_complete(struct urb *urb) { struct go7007 *go = (struct go7007 *)urb->context; - u16 *regs = (u16 *)urb->transfer_buffer; + __le16 *regs = (__le16 *)urb->transfer_buffer; int status = urb->status; if (status) { -- cgit v1.2.3 From 18ef20da8f0ad4e867a9556d285a9c22b08f5a58 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:58:35 -0300 Subject: [media] dib7000p: fix sparse warning drivers/media/dvb-frontends/dib7000p.c:2562:5: warning: symbol 'dib7090_set_diversity_in' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib7000p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 661760d60232..589134e95175 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2559,7 +2559,7 @@ static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) dib7000p_write_word(state, 1288, reg_1288); } -int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) { struct dib7000p_state *state = fe->demodulator_priv; u16 reg_1287; -- cgit v1.2.3 From 6cde2904df44049dd58b5d71639a2c720c658f50 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:05:17 -0300 Subject: [media] kinect: fix sparse warnings drivers/media/usb/gspca/kinect.c:151:19: warning: incorrect type in assignment (different base types) drivers/media/usb/gspca/kinect.c:152:19: warning: incorrect type in assignment (different base types) drivers/media/usb/gspca/kinect.c:153:19: warning: incorrect type in assignment (different base types) drivers/media/usb/gspca/kinect.c:191:13: warning: restricted __le16 degrades to integer drivers/media/usb/gspca/kinect.c:217:16: warning: incorrect type in assignment (different base types) drivers/media/usb/gspca/kinect.c:218:16: warning: incorrect type in assignment (different base types) Note that this fixes a real bug where cpu_to_le16 was used instead of the correct le16_to_cpu. Signed-off-by: Hans Verkuil Acked-by: Antonio Ospite Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/kinect.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c index 45bc1f51c5d8..3cb30a37d6ac 100644 --- a/drivers/media/usb/gspca/kinect.c +++ b/drivers/media/usb/gspca/kinect.c @@ -51,9 +51,9 @@ struct pkt_hdr { struct cam_hdr { uint8_t magic[2]; - uint16_t len; - uint16_t cmd; - uint16_t tag; + __le16 len; + __le16 cmd; + __le16 tag; }; /* specific webcam descriptor */ @@ -188,9 +188,9 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, rhdr->tag, chdr->tag); return -1; } - if (cpu_to_le16(rhdr->len) != (actual_len/2)) { + if (le16_to_cpu(rhdr->len) != (actual_len/2)) { pr_err("send_cmd: Bad len %04x != %04x\n", - cpu_to_le16(rhdr->len), (int)(actual_len/2)); + le16_to_cpu(rhdr->len), (int)(actual_len/2)); return -1; } @@ -211,7 +211,7 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, uint16_t data) { uint16_t reply[2]; - uint16_t cmd[2]; + __le16 cmd[2]; int res; cmd[0] = cpu_to_le16(reg); -- cgit v1.2.3 From b5c00cc5a56ce0060fb17380cc606514eb5bcd9e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:25:00 -0300 Subject: [media] ddbridge: fix sparse warnings drivers/media/pci/ddbridge/ddbridge-core.c:88:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:93:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:95:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:99:15: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:117:58: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:119:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:123:68: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:130:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:131:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:136:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:138:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:152:22: warning: symbol 'ddb_i2c_algo' was not declared. Should it be static? drivers/media/pci/ddbridge/ddbridge-core.c:183:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:184:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:246:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:247:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:255:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:256:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:269:35: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:358:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:359:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:360:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:362:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:366:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:368:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:369:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:370:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:380:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:381:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:393:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:394:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:395:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:396:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:397:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:401:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:403:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:404:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:406:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:416:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:417:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:475:36: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:484:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:494:20: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:501:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:524:36: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:534:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:852:21: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:973:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ddbridge/ddbridge-core.c:974:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ddbridge/ddbridge-core.c:978:20: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:982:20: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1003:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1006:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1009:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1015:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1017:39: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1035:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1041:20: warning: symbol 'cxd_cfg' was not declared. Should it be static? drivers/media/pci/ddbridge/ddbridge-core.c:1130:44: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1183:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1188:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1193:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1198:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1213:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1214:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1215:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1216:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1231:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1232:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1233:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1289:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1333:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1295:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1347:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1353:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1354:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1359:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1361:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1373:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1374:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1378:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1382:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1385:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1386:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1388:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1393:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1394:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1395:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1398:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1399:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1451:42: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1462:45: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1467:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1538:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1550:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1561:31: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1585:19: warning: incorrect type in assignment (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1591:47: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1591:60: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1607:9: warning: too many warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-core.c | 30 ++++++++++++++---------------- drivers/media/pci/ddbridge/ddbridge.h | 12 +++++------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index da8f848be3b8..c82e855a0814 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -149,7 +149,7 @@ static u32 ddb_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -struct i2c_algorithm ddb_i2c_algo = { +static struct i2c_algorithm ddb_i2c_algo = { .master_xfer = ddb_i2c_master_xfer, .functionality = ddb_i2c_functionality, }; @@ -266,7 +266,7 @@ static void io_free(struct pci_dev *pdev, u8 **vbuf, for (i = 0; i < num; i++) { if (vbuf[i]) { pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); - vbuf[i] = 0; + vbuf[i] = NULL; } } } @@ -440,7 +440,7 @@ static u32 ddb_output_free(struct ddb_output *output) } static ssize_t ddb_output_write(struct ddb_output *output, - const u8 *buf, size_t count) + const __user u8 *buf, size_t count) { struct ddb *dev = output->port->dev; u32 idx, off, stat = output->stat; @@ -506,7 +506,7 @@ static u32 ddb_input_avail(struct ddb_input *input) return 0; } -static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) +static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count) { struct ddb *dev = input->port->dev; u32 left = count; @@ -849,7 +849,7 @@ static int dvb_input_attach(struct ddb_input *input) return ret; input->attached = 4; - input->fe = 0; + input->fe = NULL; switch (port->type) { case DDB_TUNER_DVBS_ST: if (demod_attach_stv0900(input, 0) < 0) @@ -895,7 +895,7 @@ static int dvb_input_attach(struct ddb_input *input) /****************************************************************************/ /****************************************************************************/ -static ssize_t ts_write(struct file *file, const char *buf, +static ssize_t ts_write(struct file *file, const __user char *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -920,7 +920,7 @@ static ssize_t ts_write(struct file *file, const char *buf, return (left == count) ? -EAGAIN : (count - left); } -static ssize_t ts_read(struct file *file, char *buf, +static ssize_t ts_read(struct file *file, __user char *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -975,11 +975,9 @@ static const struct file_operations ci_fops = { .open = dvb_generic_open, .release = dvb_generic_release, .poll = ts_poll, - .mmap = 0, }; static struct dvb_device dvbdev_ci = { - .priv = 0, .readers = -1, .writers = -1, .users = -1, @@ -1038,7 +1036,7 @@ static void output_tasklet(unsigned long data) } -struct cxd2099_cfg cxd_cfg = { +static struct cxd2099_cfg cxd_cfg = { .bitrate = 62000, .adr = 0x40, .polarity = 1, @@ -1127,7 +1125,7 @@ static void ddb_ports_detach(struct ddb *dev) ddb_output_stop(port->output); dvb_ca_en50221_release(port->en); kfree(port->en); - port->en = 0; + port->en = NULL; dvb_unregister_adapter(&port->output->adap); } break; @@ -1413,9 +1411,9 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) #define DDB_MAGIC 'd' struct ddb_flashio { - __u8 *write_buf; + __user __u8 *write_buf; __u32 write_len; - __u8 *read_buf; + __user __u8 *read_buf; __u32 read_len; }; @@ -1439,7 +1437,7 @@ static int ddb_open(struct inode *inode, struct file *file) static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ddb *dev = file->private_data; - void *parg = (void *)arg; + __user void *parg = (__user void *)arg; int res; switch (cmd) { @@ -1558,7 +1556,7 @@ static void ddb_remove(struct pci_dev *pdev) ddb_device_destroy(dev); ddb_unmap(dev); - pci_set_drvdata(pdev, 0); + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); } @@ -1637,7 +1635,7 @@ fail1: fail: printk(KERN_ERR "fail\n"); ddb_unmap(dev); - pci_set_drvdata(pdev, 0); + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); return -1; } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 8b1b41d2a52d..be87fbd90456 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -156,7 +156,7 @@ struct ddb_port { struct ddb { struct pci_dev *pdev; - unsigned char *regs; + unsigned char __iomem *regs; struct ddb_port port[DDB_MAX_PORT]; struct ddb_i2c i2c[DDB_MAX_I2C]; struct ddb_input input[DDB_MAX_INPUT]; @@ -173,12 +173,10 @@ struct ddb { /****************************************************************************/ #define ddbwritel(_val, _adr) writel((_val), \ - (char *) (dev->regs+(_adr))) -#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) -#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ - (dev->regs+(_adr)), (_src), (_count)) -#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ - (dev->regs+(_adr)), (_count)) + dev->regs+(_adr)) +#define ddbreadl(_adr) readl(dev->regs+(_adr)) +#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count)) +#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count)) /****************************************************************************/ -- cgit v1.2.3 From c463c9797c43dd66b72daa397716d6c6675087b8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:43:22 -0300 Subject: [media] ngene: fix sparse warnings drivers/media/pci/ngene/ngene-core.c:188:27: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:190:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:199:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:260:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:263:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:282:32: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:283:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:284:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:285:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:286:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:287:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:288:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:292:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:293:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:294:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:295:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:296:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:297:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:303:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:316:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:368:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:372:9: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1160:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1199:20: warning: incorrect type in assignment (different address spaces) drivers/media/pci/ngene/ngene-core.c:1213:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1214:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1223:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1225:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1227:31: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1296:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1297:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1298:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1299:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1300:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1301:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1302:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1363:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1365:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1376:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1391:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1596:18: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-core.c:1615:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-cards.c:699:29: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:32: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:35: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:38: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-dvb.c:84:59: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-dvb.c:93:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ngene/ngene-dvb.c:94:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ngene/ngene-dvb.c:100:20: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 2 +- drivers/media/pci/ngene/ngene-core.c | 14 ++++++-------- drivers/media/pci/ngene/ngene-dvb.c | 5 ++--- drivers/media/pci/ngene/ngene.h | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 9e82d2105d53..039bed3cc919 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -696,7 +696,7 @@ static struct ngene_info ngene_info_m780 = { .demod_attach = { NULL, demod_attach_lg330x }, /* Ensure these are NULL else the frame will call them (as funcs) */ - .tuner_attach = { 0, 0, 0, 0 }, + .tuner_attach = { NULL, NULL, NULL, NULL }, .fe_config = { NULL, &aver_m780 }, .avf = { 0 }, diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 4930b55fd5f4..e29bc3af4baf 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -57,15 +57,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define dprintk if (debug) printk -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) +#define ngwritel(dat, adr) writel((dat), dev->iomem + (adr)) +#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) #define ngreadl(adr) readl(dev->iomem + (adr)) #define ngreadb(adr) readb(dev->iomem + (adr)) -#define ngcpyto(adr, src, count) memcpy_toio((char *) \ - (dev->iomem + (adr)), (src), (count)) -#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ - (dev->iomem + (adr)), (count)) +#define ngcpyto(adr, src, count) memcpy_toio(dev->iomem + (adr), (src), (count)) +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count)) /****************************************************************************/ /* nGene interrupt handler **************************************************/ @@ -1592,7 +1590,7 @@ static void cxd_detach(struct ngene *dev) dvb_ca_en50221_release(ci->en); kfree(ci->en); - ci->en = 0; + ci->en = NULL; } /***********************************/ diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index fcb16a615aab..a8a4045f66d7 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -47,7 +47,7 @@ /* COMMAND API interface ****************************************************/ /****************************************************************************/ -static ssize_t ts_write(struct file *file, const char *buf, +static ssize_t ts_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -64,7 +64,7 @@ static ssize_t ts_write(struct file *file, const char *buf, return count; } -static ssize_t ts_read(struct file *file, char *buf, +static ssize_t ts_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -97,7 +97,6 @@ static const struct file_operations ci_fops = { }; struct dvb_device ngene_dvbdev_ci = { - .priv = 0, .readers = -1, .writers = -1, .users = -1, diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 22c39ff6bfa0..51e2fbd18b1b 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -737,7 +737,7 @@ typedef void (tx_cb_t)(struct ngene *, u32); struct ngene { int nr; struct pci_dev *pci_dev; - unsigned char *iomem; + unsigned char __iomem *iomem; /*struct i2c_adapter i2c_adapter;*/ -- cgit v1.2.3 From 4182438e658dbf01c37a3b0fa035f08c303403ab Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:53:39 -0300 Subject: [media] drxj: fix sparse warnings drivers/media/dvb-frontends/drx39xyj/drxj.c:11768:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11768:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11768:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11768:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11770:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11770:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11770:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11770:25: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11794:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11796:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11796:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11796:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11796:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11798:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11798:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11798:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11798:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11800:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11800:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11800:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11800:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11605:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11605:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11605:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11605:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11632:29: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11632:29: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11632:29: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11632:29: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11650:34: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11652:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11652:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11652:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11652:34: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11654:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11654:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11654:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11654:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11656:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11656:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11656:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11656:33: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11670:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11670:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11670:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11670:35: warning: cast to restricted __be16 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11678:47: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11680:46: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 drivers/media/dvb-frontends/drx39xyj/drxj.c:11682:51: warning: cast to restricted __be32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 7ca7a21df183..5ec221ffdfca 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -2174,7 +2174,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr, u32 addr, u32 *data, u32 flags) { - u8 buf[sizeof(*data)]; + u8 buf[sizeof(*data)] = { 0 }; int rc = -EIO; u32 word = 0; @@ -4193,7 +4193,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr, u32 addr, u16 *data, u32 flags) { - u8 buf[2]; + u8 buf[2] = { 0 }; int rc = -EIO; u16 word = 0; @@ -10667,7 +10667,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod, enum drx_standard standard = ext_attr->standard; int rc; u32 ber, cnt, err, pkt; - u16 mer, strength; + u16 mer, strength = 0; rc = get_sig_strength(demod, &strength); if (rc < 0) { @@ -11602,7 +11602,7 @@ static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words) u32 carry = 0; while (i < nr_words) { - crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data)); + crc_word |= (u32)be16_to_cpu(*(__be16 *)(block_data)); for (j = 0; j < 16; j++) { crc_word <<= 1; if (carry != 0) @@ -11629,7 +11629,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, int i; unsigned count = 2 * sizeof(u16); u32 mc_dev_type, mc_version, mc_base_version; - u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16))); + u16 mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data + sizeof(u16))); /* * Scan microcode blocks first for version info @@ -11647,13 +11647,13 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, goto eof; /* Process block header */ - block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data + count)); count += sizeof(u32); - block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); - block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); - block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n", @@ -11667,7 +11667,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, if (block_hdr.addr + sizeof(u16) > size) goto eof; - auxtype = be16_to_cpu(*(u32 *)(auxblk)); + auxtype = be16_to_cpu(*(__be16 *)(auxblk)); /* Aux block. Check type */ if (DRX_ISMCVERTYPE(auxtype)) { @@ -11675,11 +11675,11 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, goto eof; auxblk += sizeof(u16); - mc_dev_type = be32_to_cpu(*(u32 *)(auxblk)); + mc_dev_type = be32_to_cpu(*(__be32 *)(auxblk)); auxblk += sizeof(u32); - mc_version = be32_to_cpu(*(u32 *)(auxblk)); + mc_version = be32_to_cpu(*(__be32 *)(auxblk)); auxblk += sizeof(u32); - mc_base_version = be32_to_cpu(*(u32 *)(auxblk)); + mc_base_version = be32_to_cpu(*(__be32 *)(auxblk)); DRX_ATTR_MCRECORD(demod).aux_type = auxtype; DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type; @@ -11765,9 +11765,9 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, mc_data = (void *)mc_data_init; /* Check data */ - mc_magic_word = be16_to_cpu(*(u32 *)(mc_data)); + mc_magic_word = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data)); + mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) { @@ -11791,13 +11791,13 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, u16 mc_block_nr_bytes = 0; /* Process block header */ - block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data)); + block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data)); mc_data += sizeof(u32); - block_hdr.size = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n", -- cgit v1.2.3 From d71b0b348f0ac68c7a330ceb97b80d9e37f14545 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:58:38 -0300 Subject: [media] uvc: fix sparse warning drivers/media/usb/uvc/uvc_video.c:1466:38: warning: incorrect type in return expression (different base types) Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 9144a2f3ed82..7e350d788fe1 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1463,7 +1463,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, switch (dev->speed) { case USB_SPEED_SUPER: - return ep->ss_ep_comp.wBytesPerInterval; + return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); case USB_SPEED_HIGH: psize = usb_endpoint_maxp(&ep->desc); return (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); -- cgit v1.2.3 From 6fbf4d0412d5084d555a5ffca31e683de7fcf9be Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 18:03:53 -0300 Subject: [media] usbtv: fix sparse warnings drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:285:14: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:287:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:288:15: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 drivers/media/usb/usbtv/usbtv-video.c:289:20: warning: cast to restricted __be32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-video.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 692c7188a8a6..3d6ed1f7509e 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -253,7 +253,7 @@ static int usbtv_setup_capture(struct usbtv *usbtv) * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels. * Therefore, we break down the chunk into two halves before copyting, * so that we can interleave a line if needed. */ -static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd) +static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd) { int half; @@ -271,7 +271,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd) /* Called for each 256-byte image chunk. * First word identifies the chunk, followed by 240 words of image * data and padding. */ -static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) +static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk) { int frame_id, odd, chunk_no; u32 *frame; @@ -362,7 +362,7 @@ static void usbtv_iso_cb(struct urb *ip) for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++) usbtv_image_chunk(usbtv, - (u32 *)&data[USBTV_CHUNK_SIZE * offset]); + (__be32 *)&data[USBTV_CHUNK_SIZE * offset]); } resubmit: -- cgit v1.2.3 From ce08131c42164a4be37e6bb7f34185ab48f6bba4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 18:08:17 -0300 Subject: [media] mb86a16/mb86a20s: fix sparse warnings drivers/media/dvb-frontends/mb86a16.c:31:14: warning: symbol 'verbose' was not declared. Should it be static? drivers/media/dvb-frontends/mb86a20s.c:36:4: warning: symbol 'mb86a20s_subchannel' was not declared. Should it be static? drivers/media/dvb-frontends/mb86a20s.c:1333:24: warning: symbol 'cnr_qpsk_table' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a16.c | 2 +- drivers/media/dvb-frontends/mb86a20s.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 9ae40abfd71a..1827c0a29e95 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -28,7 +28,7 @@ #include "mb86a16.h" #include "mb86a16_priv.h" -unsigned int verbose = 5; +static unsigned int verbose = 5; module_param(verbose, int, 0644); #define ABS(x) ((x) < 0 ? (-x) : (x)) diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index b931179c70a4..e6f165a5b90d 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -33,7 +33,7 @@ enum mb86a20s_bandwidth { MB86A20S_3SEG = 3, }; -u8 mb86a20s_subchannel[] = { +static u8 mb86a20s_subchannel[] = { 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x00, 0x10, 0x20, }; @@ -1228,7 +1228,7 @@ struct linear_segments { * All tables below return a dB/1000 measurement */ -static struct linear_segments cnr_to_db_table[] = { +static const struct linear_segments cnr_to_db_table[] = { { 19648, 0}, { 18187, 1000}, { 16534, 2000}, @@ -1262,7 +1262,7 @@ static struct linear_segments cnr_to_db_table[] = { { 788, 30000}, }; -static struct linear_segments cnr_64qam_table[] = { +static const struct linear_segments cnr_64qam_table[] = { { 3922688, 0}, { 3920384, 1000}, { 3902720, 2000}, @@ -1296,7 +1296,7 @@ static struct linear_segments cnr_64qam_table[] = { { 388864, 30000}, }; -static struct linear_segments cnr_16qam_table[] = { +static const struct linear_segments cnr_16qam_table[] = { { 5314816, 0}, { 5219072, 1000}, { 5118720, 2000}, @@ -1330,7 +1330,7 @@ static struct linear_segments cnr_16qam_table[] = { { 95744, 30000}, }; -struct linear_segments cnr_qpsk_table[] = { +static const struct linear_segments cnr_qpsk_table[] = { { 2834176, 0}, { 2683648, 1000}, { 2536960, 2000}, @@ -1364,7 +1364,7 @@ struct linear_segments cnr_qpsk_table[] = { { 11520, 30000}, }; -static u32 interpolate_value(u32 value, struct linear_segments *segments, +static u32 interpolate_value(u32 value, const struct linear_segments *segments, unsigned len) { u64 tmp64; @@ -1448,7 +1448,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 mer, cnr; int rc, val, layer; - struct linear_segments *segs; + const struct linear_segments *segs; unsigned segs_len; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); -- cgit v1.2.3 From 967a37830573a1fa4b7bdb7ce203c7ea8a91e0c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 18:26:40 -0300 Subject: [media] mantis: fix sparse warnings drivers/media/pci/mantis/hopper_vp3028.c:37:23: warning: symbol 'hopper_vp3028_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1033.c:38:4: warning: symbol 'lgtdqcs001f_inittab' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1033.c:153:23: warning: symbol 'lgtdqcs001f_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1034.c:39:23: warning: symbol 'vp1034_mb86a16_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1041.c:266:23: warning: symbol 'vp1041_stb0899_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1041.c:303:23: warning: symbol 'vp1041_stb6100_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2033.c:40:24: warning: symbol 'vp2033_tda1002x_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2033.c:45:24: warning: symbol 'vp2033_tda10023_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2040.c:40:24: warning: symbol 'vp2040_tda1002x_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2040.c:45:24: warning: symbol 'vp2040_tda10023_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp3030.c:38:23: warning: symbol 'mantis_vp3030_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp3030.c:42:23: warning: symbol 'env57h12d5_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_dma.c:167:33: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:172:33: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:174:25: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:178:9: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:179:9: warning: incorrect type in assignment (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/mantis/hopper_vp3028.c | 2 +- drivers/media/pci/mantis/mantis_common.h | 2 +- drivers/media/pci/mantis/mantis_vp1033.c | 4 ++-- drivers/media/pci/mantis/mantis_vp1034.c | 2 +- drivers/media/pci/mantis/mantis_vp1041.c | 4 ++-- drivers/media/pci/mantis/mantis_vp2033.c | 4 ++-- drivers/media/pci/mantis/mantis_vp2040.c | 4 ++-- drivers/media/pci/mantis/mantis_vp3030.c | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c index 68a29f8bdf73..1032db6bb789 100644 --- a/drivers/media/pci/mantis/hopper_vp3028.c +++ b/drivers/media/pci/mantis/hopper_vp3028.c @@ -34,7 +34,7 @@ #include "mantis_dvb.h" #include "hopper_vp3028.h" -struct zl10353_config hopper_vp3028_config = { +static struct zl10353_config hopper_vp3028_config = { .demod_address = 0x0f, }; diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index f2410cf0a6bf..8ff448bb792d 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -127,7 +127,7 @@ struct mantis_pci { u32 last_block; u8 *buf_cpu; dma_addr_t buf_dma; - u32 *risc_cpu; + __le32 *risc_cpu; dma_addr_t risc_dma; struct tasklet_struct tasklet; diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c index 115003e8d19d..12a6adb2bd7e 100644 --- a/drivers/media/pci/mantis/mantis_vp1033.c +++ b/drivers/media/pci/mantis/mantis_vp1033.c @@ -35,7 +35,7 @@ #include "mantis_vp1033.h" #include "mantis_reg.h" -u8 lgtdqcs001f_inittab[] = { +static u8 lgtdqcs001f_inittab[] = { 0x01, 0x15, 0x02, 0x30, 0x03, 0x00, @@ -150,7 +150,7 @@ static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, return 0; } -struct stv0299_config lgtdqcs001f_config = { +static struct stv0299_config lgtdqcs001f_config = { .demod_address = 0x68, .inittab = lgtdqcs001f_inittab, .mclk = 88000000UL, diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c index 430ae84ce528..7c1bd167225c 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.c +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -36,7 +36,7 @@ #include "mantis_vp1034.h" #include "mantis_reg.h" -struct mb86a16_config vp1034_mb86a16_config = { +static struct mb86a16_config vp1034_mb86a16_config = { .demod_address = 0x08, .set_voltage = vp1034_set_voltage, }; diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c index 07a20748b707..7082fcbc94a1 100644 --- a/drivers/media/pci/mantis/mantis_vp1041.c +++ b/drivers/media/pci/mantis/mantis_vp1041.c @@ -263,7 +263,7 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { { 0xffff , 0xff }, }; -struct stb0899_config vp1041_stb0899_config = { +static struct stb0899_config vp1041_stb0899_config = { .init_dev = vp1041_stb0899_s1_init_1, .init_s2_demod = stb0899_s2_init_2, .init_s1_demod = vp1041_stb0899_s1_init_3, @@ -300,7 +300,7 @@ struct stb0899_config vp1041_stb0899_config = { .tuner_set_rfsiggain = NULL, }; -struct stb6100_config vp1041_stb6100_config = { +static struct stb6100_config vp1041_stb6100_config = { .tuner_address = 0x60, .refclock = 27000000, }; diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c index 1ca6837fbe46..8d48b5abe04a 100644 --- a/drivers/media/pci/mantis/mantis_vp2033.c +++ b/drivers/media/pci/mantis/mantis_vp2033.c @@ -37,12 +37,12 @@ #define MANTIS_MODEL_NAME "VP-2033" #define MANTIS_DEV_TYPE "DVB-C" -struct tda1002x_config vp2033_tda1002x_cu1216_config = { +static struct tda1002x_config vp2033_tda1002x_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; -struct tda10023_config vp2033_tda10023_cu1216_config = { +static struct tda10023_config vp2033_tda10023_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c index d480741afd78..8dd17d7c0881 100644 --- a/drivers/media/pci/mantis/mantis_vp2040.c +++ b/drivers/media/pci/mantis/mantis_vp2040.c @@ -37,12 +37,12 @@ #define MANTIS_MODEL_NAME "VP-2040" #define MANTIS_DEV_TYPE "DVB-C" -struct tda1002x_config vp2040_tda1002x_cu1216_config = { +static struct tda1002x_config vp2040_tda1002x_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; -struct tda10023_config vp2040_tda10023_cu1216_config = { +static struct tda10023_config vp2040_tda10023_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c index c09308cd3ac6..5c1dd925bdd5 100644 --- a/drivers/media/pci/mantis/mantis_vp3030.c +++ b/drivers/media/pci/mantis/mantis_vp3030.c @@ -35,11 +35,11 @@ #include "mantis_dvb.h" #include "mantis_vp3030.h" -struct zl10353_config mantis_vp3030_config = { +static struct zl10353_config mantis_vp3030_config = { .demod_address = 0x0f, }; -struct tda665x_config env57h12d5_config = { +static struct tda665x_config env57h12d5_config = { .name = "ENV57H12D5 (ET-50DT)", .addr = 0x60, .frequency_min = 47000000, -- cgit v1.2.3 From 2a8b7e5888f5f1306811f778a6678f78b7a98bcd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:20:12 -0300 Subject: [media] wl128x: fix sparse warnings drivers/media/radio/wl128x/fmdrv_common.c:598:32: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:598:32: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:598:32: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:598:32: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:767:38: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:767:38: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:767:38: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:767:38: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:992:21: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:992:21: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:992:21: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:992:21: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:443:41: warning: incorrect type in assignment (different base types) drivers/media/radio/wl128x/fmdrv_common.c:1359:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:39: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:39: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:39: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1359:39: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:25: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:25: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:25: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:25: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:47: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:47: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:47: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_common.c:1368:47: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:119:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:119:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:119:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:119:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:192:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:192:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:192:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:192:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:288:28: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:288:28: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:288:28: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:288:28: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:534:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:534:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:534:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:534:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:625:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:625:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:625:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_rx.c:625:17: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_tx.c:377:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_tx.c:377:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_tx.c:377:20: warning: cast to restricted __be16 drivers/media/radio/wl128x/fmdrv_tx.c:377:20: warning: cast to restricted __be16 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 11 ++++++----- drivers/media/radio/wl128x/fmdrv_rx.c | 10 +++++----- drivers/media/radio/wl128x/fmdrv_tx.c | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 4b2e9e8298e1..6f28f6e02ea5 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -440,7 +440,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, * command with u16 payload - convert to be16 */ if (payload != NULL) - *(u16 *)payload = cpu_to_be16(*(u16 *)payload); + *(__be16 *)payload = cpu_to_be16(*(u16 *)payload); } else if (payload != NULL) { fm_cb(skb)->fm_op = *((u8 *)payload + 2); @@ -595,7 +595,7 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) skb_pull(skb, sizeof(struct fm_event_msg_hdr)); memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); - fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); + fmdev->irq_info.flag = be16_to_cpu((__force __be16)fmdev->irq_info.flag); fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); /* Continue next function in interrupt handler table */ @@ -764,7 +764,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) * Extract PI code and store in local cache. * We need this during AF switch processing. */ - cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); + cur_picode = be16_to_cpu((__force __be16)rds_fmt.data.groupgeneral.pidata); if (fmdev->rx.stat_info.picode != cur_picode) fmdev->rx.stat_info.picode = cur_picode; @@ -989,7 +989,7 @@ static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) /* Skip header info and copy only response data */ skb_pull(skb, sizeof(struct fm_event_msg_hdr)); memcpy(&read_freq, skb->data, sizeof(read_freq)); - read_freq = be16_to_cpu(read_freq); + read_freq = be16_to_cpu((__force __be16)read_freq); curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; @@ -1317,7 +1317,8 @@ static int load_default_rx_configuration(struct fmdev *fmdev) /* Does FM power on sequence */ static int fm_power_up(struct fmdev *fmdev, u8 mode) { - u16 payload, asic_id, asic_ver; + u16 payload; + __be16 asic_id, asic_ver; int resp_len, ret; u8 fw_name[50]; diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index ebf09a3927de..09632cb26cb6 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -116,7 +116,7 @@ int fm_rx_set_freq(struct fmdev *fmdev, u32 freq) if (ret < 0) goto exit; - curr_frq = be16_to_cpu(curr_frq); + curr_frq = be16_to_cpu((__force __be16)curr_frq); curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); if (curr_frq_in_khz != freq) { @@ -189,7 +189,7 @@ int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, if (ret < 0) return ret; - curr_frq = be16_to_cpu(curr_frq); + curr_frq = be16_to_cpu((__force __be16)curr_frq); last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; /* Check the offset in order to be aligned to the channel spacing*/ @@ -285,7 +285,7 @@ again: if (ret < 0) return ret; - curr_frq = be16_to_cpu(curr_frq); + curr_frq = be16_to_cpu((__force __be16)curr_frq); fmdev->rx.freq = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); @@ -517,7 +517,7 @@ int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) /* Returns the signal strength level of current channel */ int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) { - u16 curr_rssi_lel; + __be16 curr_rssi_lel; u32 resp_len; int ret; @@ -608,7 +608,7 @@ int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) /* Gets current RX stereo/mono mode */ int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) { - u16 curr_mode; + __be16 curr_mode; u32 resp_len; int ret; diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c index 6ea33e09d63b..839970b0f313 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.c +++ b/drivers/media/radio/wl128x/fmdrv_tx.c @@ -374,7 +374,7 @@ int fm_tx_get_tune_cap_val(struct fmdev *fmdev) if (ret < 0) return ret; - curr_val = be16_to_cpu(curr_val); + curr_val = be16_to_cpu((__force __be16)curr_val); return curr_val; } -- cgit v1.2.3 From fba16a1eee5c2d93d010a5b7c41d9c4b478c7eb8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:22:18 -0300 Subject: [media] bcm3510: fix sparse warnings drivers/media/dvb-frontends/bcm3510.c:646:24: warning: cast to restricted __le16 drivers/media/dvb-frontends/bcm3510.c:647:24: warning: cast to restricted __le16 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/bcm3510.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 39a29dd29519..998d15031461 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -643,8 +643,8 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe) b = fw->data; for (i = 0; i < fw->size;) { - addr = le16_to_cpu( *( (u16 *)&b[i] ) ); - len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); + addr = le16_to_cpu(*((__le16 *)&b[i])); + len = le16_to_cpu(*((__le16 *)&b[i+2])); deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { err("firmware download failed: %d\n",ret); -- cgit v1.2.3 From ff3ec57df9e87bcb18e81157cbe3bef3159d76a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:25:34 -0300 Subject: [media] s2255drv: fix sparse warning drivers/media/usb/s2255/s2255drv.c:2248:20: warning: cast to restricted __le16 At the USB structs there are two different idProduct: usb_device_id::idProduct - already on CPU endiannes usb_device::descriptor.idProduct - with is LE16 In this specific case, the driver checks for the one at usb_device_id struct, with already have CPU endianness. So, no conversion is required. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2c901861034a..ccc00099b261 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -2245,7 +2245,7 @@ static int s2255_probe(struct usb_interface *interface, } atomic_set(&dev->num_channels, 0); - dev->pid = le16_to_cpu(id->idProduct); + dev->pid = id->idProduct; dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); if (!dev->fw_data) goto errorFWDATA1; -- cgit v1.2.3 From 6812667381d4e7d1baa93464af6fd02175db96de Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:26:47 -0300 Subject: [media] dvb_usb_core: fix sparse warning drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:24:5: warning: symbol 'dvb_usbv2_disable_rc_polling' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6c33d8525454..adca05f27fba 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -21,7 +21,7 @@ #include "dvb_usb_common.h" -int dvb_usbv2_disable_rc_polling; +static int dvb_usbv2_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)"); -- cgit v1.2.3 From 2954192529e9bb8158bb60f731b108f21c4017aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:28:02 -0300 Subject: [media] pwc: fix sparse warning drivers/media/usb/pwc/pwc-v4l.c:55:12: warning: symbol 'pwc_auto_whitebal_qmenu' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc-v4l.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c index aa7449eaca08..3d987984602f 100644 --- a/drivers/media/usb/pwc/pwc-v4l.c +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -52,7 +52,7 @@ enum { custom_autocontour, custom_contour, custom_noise_reduction, custom_awb_speed, custom_awb_delay, custom_save_user, custom_restore_user, custom_restore_factory }; -const char * const pwc_auto_whitebal_qmenu[] = { +static const char * const pwc_auto_whitebal_qmenu[] = { "Indoor (Incandescant Lighting) Mode", "Outdoor (Sunlight) Mode", "Indoor (Fluorescent Lighting) Mode", -- cgit v1.2.3 From 817d2fd4cb3686191a3f411275394c4c573e79e0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:30:33 -0300 Subject: [media] stv0367: fix sparse warnings drivers/media/dvb-frontends/stv0367.c:557:5: warning: symbol 'stv0367cab_RF_LookUp1' was not declared. Should it be static? drivers/media/dvb-frontends/stv0367.c:569:5: warning: symbol 'stv0367cab_RF_LookUp2' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0367.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 59b6e661acc0..764577218974 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -554,7 +554,7 @@ static struct st_register def0367ter[STV0367TER_NBREGS] = { #define RF_LOOKUP_TABLE_SIZE 31 #define RF_LOOKUP_TABLE2_SIZE 16 /* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { +static const s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { {/*AGC1*/ 48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, @@ -566,7 +566,7 @@ s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { } }; /* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { +static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { {/*AGC2*/ 28, 29, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, -- cgit v1.2.3 From e73c7bfea0770ce9e908fc4b9093752c22155d1d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:32:03 -0300 Subject: [media] si2165: fix sparse warning drivers/media/dvb-frontends/si2165.c:329:16: warning: odd constant _Bool cast (ffffffffffffffea becomes 1) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2165.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 3a2d6c5aded6..4386092975d0 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -312,7 +312,7 @@ static u32 si2165_get_fe_clk(struct si2165_state *state) return state->adc_clk; } -static bool si2165_wait_init_done(struct si2165_state *state) +static int si2165_wait_init_done(struct si2165_state *state) { int ret = -EINVAL; u8 val = 0; -- cgit v1.2.3 From d778d258b7850cf803378211011d38255f11107b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:34:33 -0300 Subject: [media] imon: fix sparse warnings drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1343:44: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1407:36: warning: cast to restricted __be32 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1512:28: warning: cast to restricted __be64 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 drivers/media/rc/imon.c:1516:28: warning: cast to restricted __be32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3d8f515be3c1..cd511a7b4cab 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1438,7 +1438,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) } buf[2] = dir & 0xFF; buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); } } else { /* @@ -1502,7 +1502,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) } buf[2] = dir & 0xFF; buf[3] = (dir >> 8) & 0xFF; - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); } else { /* * Hack alert: instead of using keycodes, we have @@ -1607,12 +1607,12 @@ static void imon_incoming_packet(struct imon_context *ictx, /* Figure out what key was pressed */ if (len == 8 && buf[7] == 0xee) { - scancode = be64_to_cpu(*((u64 *)buf)); + scancode = be64_to_cpu(*((__be64 *)buf)); ktype = IMON_KEY_PANEL; kc = imon_panel_key_lookup(ictx, scancode); ictx->release_code = false; } else { - scancode = be32_to_cpu(*((u32 *)buf)); + scancode = be32_to_cpu(*((__be32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { ktype = IMON_KEY_IMON; if (buf[0] == 0x80) -- cgit v1.2.3 From 4d1afa51e957a48db9663e74816c411e70b8d15e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:37:53 -0300 Subject: [media] v4l2-ioctl: fix sparse warnings drivers/media/v4l2-core/v4l2-ioctl.c:1156:53: warning: incorrect type in initializer (different address spaces) drivers/media/v4l2-core/v4l2-ioctl.c:1158:42: warning: incorrect type in initializer (different address spaces) drivers/media/v4l2-core/v4l2-ioctl.c:1161:34: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-ioctl.c:1163:35: warning: incorrect type in assignment (different address spaces) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d15e16737eef..46f4c0413d7d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1153,9 +1153,9 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { - struct v4l2_clip *clips = p->fmt.win.clips; + struct v4l2_clip __user *clips = p->fmt.win.clips; u32 clipcount = p->fmt.win.clipcount; - void *bitmap = p->fmt.win.bitmap; + void __user *bitmap = p->fmt.win.bitmap; memset(&p->fmt, 0, sizeof(p->fmt)); p->fmt.win.clips = clips; -- cgit v1.2.3 From 60519af3fd0e75a97036075fc657f1ebe87e0f0d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 19:41:03 -0300 Subject: [media] lirc_dev: fix sparse warnings drivers/media/rc/lirc_dev.c:598:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:606:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:616:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:625:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:634:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:643:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/lirc_dev.c:739:45: warning: cast removes address space of expression drivers/media/rc/lirc_dev.c:739:58: warning: incorrect type in argument 1 (different address spaces) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index dc5cbffcd5a2..249d2fbc8f37 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -595,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case LIRC_GET_FEATURES: - result = put_user(ir->d.features, (__u32 *)arg); + result = put_user(ir->d.features, (__u32 __user *)arg); break; case LIRC_GET_REC_MODE: if (!(ir->d.features & LIRC_CAN_REC_MASK)) { @@ -605,7 +605,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = put_user(LIRC_REC2MODE (ir->d.features & LIRC_CAN_REC_MASK), - (__u32 *)arg); + (__u32 __user *)arg); break; case LIRC_SET_REC_MODE: if (!(ir->d.features & LIRC_CAN_REC_MASK)) { @@ -613,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - result = get_user(mode, (__u32 *)arg); + result = get_user(mode, (__u32 __user *)arg); if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) result = -EINVAL; /* @@ -622,7 +622,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ break; case LIRC_GET_LENGTH: - result = put_user(ir->d.code_length, (__u32 *)arg); + result = put_user(ir->d.code_length, (__u32 __user *)arg); break; case LIRC_GET_MIN_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || @@ -631,7 +631,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - result = put_user(ir->d.min_timeout, (__u32 *)arg); + result = put_user(ir->d.min_timeout, (__u32 __user *)arg); break; case LIRC_GET_MAX_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || @@ -640,7 +640,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - result = put_user(ir->d.max_timeout, (__u32 *)arg); + result = put_user(ir->d.max_timeout, (__u32 __user *)arg); break; default: result = -EINVAL; @@ -736,7 +736,7 @@ ssize_t lirc_dev_fop_read(struct file *file, } } else { lirc_buffer_read(ir->buf, buf); - ret = copy_to_user((void *)buffer+written, buf, + ret = copy_to_user((void __user *)buffer+written, buf, ir->buf->chunk_size); if (!ret) written += ir->buf->chunk_size; -- cgit v1.2.3 From a7547af7d295bae3853accde5c746159b3e0e9de Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:06:36 -0300 Subject: [media] via-camera: fix sparse warning drivers/media/platform/via-camera.c:445:34: warning: incorrect type in assignment (different address spaces) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/via-camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 2ac870438493..00d431293190 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -82,7 +82,7 @@ struct via_camera { * live in frame buffer memory, so we don't call them "DMA". */ unsigned int cb_offsets[3]; /* offsets into fb mem */ - u8 *cb_addrs[3]; /* Kernel-space addresses */ + u8 __iomem *cb_addrs[3]; /* Kernel-space addresses */ int n_cap_bufs; /* How many are we using? */ int next_buf; struct videobuf_queue vb_queue; -- cgit v1.2.3 From 38b2b8794d0ae7e086199e6077d2f234a3b69ab8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:26:29 -0300 Subject: [media] cx25821: fix sparse warning drivers/media/pci/cx25821/cx25821-video-upstream.c:334:25: warning: incorrect type in argument 2 (different address spaces) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video-upstream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 1f43be0b04c8..a664997e1958 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan, if (frame_size - curpos < count) count = frame_size - curpos; - memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos, - data, count); + if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos, + data, count)) + return -EFAULT; curpos += count; if (curpos == frame_size) { out->_frame_count++; -- cgit v1.2.3 From 3f9280a8b4aa57186555e2d39587d13a6844ab98 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:34:02 -0300 Subject: [media] cx231xx: fix sparse warnings drivers/media/usb/cx231xx/cx231xx-avcore.c:2226:15: warning: cast to restricted __le32 drivers/media/usb/cx231xx/cx231xx-avcore.c:2447:15: warning: cast to restricted __le32 drivers/media/usb/cx231xx/cx231xx-avcore.c:2475:15: warning: cast to restricted __le32 drivers/media/usb/cx231xx/cx231xx-avcore.c:2500:15: warning: cast to restricted __le32 drivers/media/usb/cx231xx/cx231xx-avcore.c:2647:18: warning: incorrect type in assignment (different base types) drivers/media/usb/cx231xx/cx231xx-avcore.c:2659:21: warning: cast to restricted __le32 drivers/media/usb/cx231xx/cx231xx-dvb.c:743:57: warning: Using plain integer as NULL pointer drivers/media/usb/cx231xx/cx231xx-dvb.c:776:57: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-avcore.c | 12 ++++++------ drivers/media/usb/cx231xx/cx231xx-core.c | 2 +- drivers/media/usb/cx231xx/cx231xx-dvb.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index a428c10e1a16..51872b9f75a1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2223,7 +2223,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) if (status < 0) return status; - tmp = le32_to_cpu(*((u32 *) value)); + tmp = le32_to_cpu(*((__le32 *) value)); switch (mode) { case POLARIS_AVMODE_ENXTERNAL_AV: @@ -2444,7 +2444,7 @@ int cx231xx_power_suspend(struct cx231xx *dev) if (status > 0) return status; - tmp = le32_to_cpu(*((u32 *) value)); + tmp = le32_to_cpu(*((__le32 *) value)); tmp &= (~PWR_MODE_MASK); value[0] = (u8) tmp; @@ -2472,7 +2472,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask) if (status < 0) return status; - tmp = le32_to_cpu(*((u32 *) value)); + tmp = le32_to_cpu(*((__le32 *) value)); tmp |= ep_mask; value[0] = (u8) tmp; value[1] = (u8) (tmp >> 8); @@ -2497,7 +2497,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask) if (status < 0) return status; - tmp = le32_to_cpu(*((u32 *) value)); + tmp = le32_to_cpu(*((__le32 *) value)); tmp &= (~ep_mask); value[0] = (u8) tmp; value[1] = (u8) (tmp >> 8); @@ -2644,7 +2644,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val) { int status = 0; - gpio_val = cpu_to_le32(gpio_val); + gpio_val = (__force u32)cpu_to_le32(gpio_val); status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0); return status; @@ -2652,7 +2652,7 @@ static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val) static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val) { - u32 tmp; + __le32 tmp; int status = 0; status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1); diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 513194aa6561..180103e48036 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1491,7 +1491,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode) if (status < 0) return status; - tmp = le32_to_cpu(*((u32 *) value)); + tmp = le32_to_cpu(*((__le32 *) value)); tmp |= mode; value[0] = (u8) tmp; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 1fa79741d199..2adfecf70236 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -740,7 +740,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dev->dvb->frontend->ops.i2c_gate_ctrl = 0; + dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ dvb->frontend->callback = cx231xx_tuner_callback; @@ -773,7 +773,7 @@ static int dvb_init(struct cx231xx *dev) goto out_free; } - dev->dvb->frontend->ops.i2c_gate_ctrl = 0; + dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ dvb->frontend->callback = cx231xx_tuner_callback; -- cgit v1.2.3 From 888bd5dcb68437273ffc3752c4976f851205b25d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:50:34 -0300 Subject: [media] dm1105: fix sparse warning drivers/media/pci/dm1105/dm1105.c:617:9: warning: incorrect type in argument 1 (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/dm1105/dm1105.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index e8826c535ccd..ed11716731e9 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -614,7 +614,7 @@ static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) static void dm1105_set_dma_addr(struct dm1105_dev *dev) { - dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); + dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr)); } static int dm1105_dma_map(struct dm1105_dev *dev) -- cgit v1.2.3 From 41150cb9f51df07e78d82c196931c913633c95a0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:55:00 -0300 Subject: [media] cxusb: fix sparse warning drivers/media/usb/dvb-usb/cxusb.c:178:40: warning: restricted __le16 degrades to integer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 187d52942ebb..356abb369c20 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -176,7 +176,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], for (i = 0; i < num; i++) { - if (d->udev->descriptor.idVendor == USB_VID_MEDION) + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION) switch (msg[i].addr) { case 0x63: cxusb_gpio_tuner(d, 0); -- cgit v1.2.3 From 711c31192057689e59c2a2095d3a7e0fadbfd213 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:56:42 -0300 Subject: [media] cx23885: fix sparse warning drivers/media/pci/cx23885/cx23885-dvb.c:1494:72: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index ccf413f3c4ff..d71d59f6c6d6 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1487,7 +1487,7 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr4400_si2165_config, &i2c_bus->i2c_adap); if (fe0->dvb.frontend != NULL) { - fe0->dvb.frontend->ops.i2c_gate_ctrl = 0; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (!dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &i2c_bus2->i2c_adap, -- cgit v1.2.3 From 3efb8ab6d4f0f38440a819d8302be18596899ebf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:31:51 -0300 Subject: [media] ivtv: fix sparse warnings drivers/media/pci/ivtv/ivtv-irq.c:195:25: warning: incorrect type in argument 1 (different base types) drivers/media/pci/ivtv/ivtv-irq.c:199:25: warning: incorrect type in argument 1 (different base types) drivers/media/pci/ivtv/ivtv-irq.c:278:35: warning: restricted __le32 degrades to integer drivers/media/pci/ivtv/ivtv-irq.c:281:51: warning: restricted __le32 degrades to integer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-irq.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index 19a7c9b990a3..ab6d5d25aa6f 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -192,11 +192,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); - write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); + write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET); } else { s->pending_backup = read_enc(offset); - write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); + write_enc_sync(DMA_MAGIC_COOKIE, offset); } s->pending_offset = offset; } @@ -275,13 +275,11 @@ static void dma_post(struct ivtv_stream *s) if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; - if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) + if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE) { - for (offset = 0; offset < 64; offset++) { - if (u32buf[offset] == DMA_MAGIC_COOKIE) { + for (offset = 0; offset < 64; offset++) + if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE) break; - } - } offset *= 4; if (offset == 256) { IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); -- cgit v1.2.3 From 39fd44607a5ec904b84ecd92bf1710a9ecb3f68c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:38:04 -0300 Subject: [media] cx18: fix sparse warnings /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:169:32: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:170:32: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:171:31: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:172:31: warning: cast to restricted __le32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index a1c1cec05f98..53a7578d525b 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; while (offset + sizeof(seghdr) < fw->size) { - const u32 *shptr = src + offset / 4; + const __le32 *shptr = (__force __le32 *)src + offset / 4; seghdr.sync1 = le32_to_cpu(shptr[0]); seghdr.sync2 = le32_to_cpu(shptr[1]); -- cgit v1.2.3 From 4a9e512afa31fc1af2a93467aa4363db97f815b5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:43:03 -0300 Subject: [media] em28xx: fix sparse warnings drivers/media/usb/em28xx/em28xx-core.c:297:16: warning: cast to restricted __le16 drivers/media/usb/em28xx/em28xx-cards.c:2249:20: warning: symbol 'em28xx_bcount' was not declared. Should it be static? Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 +- drivers/media/usb/em28xx/em28xx-core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index a7e24848f6c8..230d6a21b6d3 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2246,7 +2246,7 @@ struct em28xx_board em28xx_boards[] = { }; EXPORT_SYMBOL_GPL(em28xx_boards); -const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); +static const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table[] = { diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 523d7e92bf47..225a73518cf2 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -279,7 +279,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg) { int ret; u8 addr = (reg & 0x7f) | 0x80; - u16 val; + __le16 val; ret = em28xx_is_ac97_ready(dev); if (ret < 0) -- cgit v1.2.3 From eadf9e26fab7f9841adcc36f3559dbce7604fcd5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:49:16 -0300 Subject: [media] videodev2.h: add __user to v4l2_ext_control pointers These are not copied to kernel space by video_usercopy, so mark them as __user. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 778a3298fb34..0b1ba5c6a8d2 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1285,11 +1285,11 @@ struct v4l2_ext_control { union { __s32 value; __s64 value64; - char *string; - __u8 *p_u8; - __u16 *p_u16; - __u32 *p_u32; - void *ptr; + char __user *string; + __u8 __user *p_u8; + __u16 __user *p_u16; + __u32 __user *p_u32; + void __user *ptr; }; } __attribute__ ((packed)); -- cgit v1.2.3 From 8ae632b11775254c5e555ee8c42b7d19baeb1473 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 17:07:21 -0300 Subject: [media] v4l2-compat-ioctl32: fix sparse warnings A lot of these warnings are caused by the fact that we don't generally use __user in videodev2.h. Normally the video_usercopy function will copy anything pointed to by pointers into kernel space, so having __user in the struct will only cause lots of warnings in the drivers. But the flip side of that is that you need to add __force casts here. drivers/media/v4l2-core/v4l2-compat-ioctl32.c:337:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:337:30: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:338:31: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:338:49: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:343:21: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:346:21: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:349:35: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:349:46: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:352:35: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:352:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:363:26: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:363:32: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:364:31: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:364:51: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:371:35: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:371:56: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:376:35: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:376:48: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:430:30: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:433:48: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:433:56: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:501:24: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:507:48: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:507:56: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:565:18: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:670:22: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:680:29: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:692:55: warning: incorrect type in initializer (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:773:18: warning: incorrect type in assignment (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:786:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:786:44: warning: incorrect type in argument 2 (different address spaces) drivers/media/v4l2-core/v4l2-compat-ioctl32.c:674:37: warning: dereference of noderef expression drivers/media/v4l2-core/v4l2-compat-ioctl32.c:718:37: warning: dereference of noderef expression Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 30 +++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index cca6c2f76b3a..e502a5fb2994 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -328,7 +328,7 @@ struct v4l2_buffer32 { __u32 reserved; }; -static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, +static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { void __user *up_pln; @@ -357,7 +357,7 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, return 0; } -static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, +static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32, enum v4l2_memory memory) { if (copy_in_user(up32, up, 2 * sizeof(__u32)) || @@ -427,7 +427,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user * by passing a very big num_planes value */ uplane = compat_alloc_user_space(num_planes * sizeof(struct v4l2_plane)); - kp->m.planes = uplane; + kp->m.planes = (__force struct v4l2_plane *)uplane; while (--num_planes >= 0) { ret = get_v4l2_plane32(uplane, uplane32, kp->memory); @@ -498,7 +498,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (num_planes == 0) return 0; - uplane = kp->m.planes; + uplane = (__force struct v4l2_plane __user *)kp->m.planes; if (get_user(p, &up->m.planes)) return -EFAULT; uplane32 = compat_ptr(p); @@ -562,7 +562,7 @@ static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame get_user(kp->flags, &up->flags) || copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt))) return -EFAULT; - kp->base = compat_ptr(tmp); + kp->base = (__force void *)compat_ptr(tmp); return 0; } @@ -667,11 +667,15 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); - kp->controls = kcontrols; + kp->controls = (__force struct v4l2_ext_control *)kcontrols; while (--n >= 0) { + u32 id; + if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; - if (ctrl_is_pointer(kcontrols->id)) { + if (get_user(id, &kcontrols->id)) + return -EFAULT; + if (ctrl_is_pointer(id)) { void __user *s; if (get_user(p, &ucontrols->string)) @@ -689,7 +693,8 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up) { struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols = kp->controls; + struct v4l2_ext_control __user *kcontrols = + (__force struct v4l2_ext_control __user *)kp->controls; int n = kp->count; compat_caddr_t p; @@ -711,11 +716,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext while (--n >= 0) { unsigned size = sizeof(*ucontrols); + u32 id; + if (get_user(id, &kcontrols->id)) + return -EFAULT; /* Do not modify the pointer when copying a pointer control. The contents of the pointer was changed, not the pointer itself. */ - if (ctrl_is_pointer(kcontrols->id)) + if (ctrl_is_pointer(id)) size -= sizeof(ucontrols->value64); if (copy_in_user(ucontrols, kcontrols, size)) return -EFAULT; @@ -770,7 +778,7 @@ static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) get_user(tmp, &up->edid) || copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - kp->edid = compat_ptr(tmp); + kp->edid = (__force u8 *)compat_ptr(tmp); return 0; } @@ -783,7 +791,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up) put_user(kp->start_block, &up->start_block) || put_user(kp->blocks, &up->blocks) || put_user(tmp, &up->edid) || - copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved))) + copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) return -EFAULT; return 0; } -- cgit v1.2.3 From fe10b84e7f6c4c8c3dc8cf63be324bc13f5acd68 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:01:23 -0300 Subject: [media] mt2063: fix sparse warnings drivers/media/tuners/mt2063.c:1238:56: warning: cast truncates bits from constant value (ffffff0f becomes f) drivers/media/tuners/mt2063.c:1313:62: warning: cast truncates bits from constant value (ffffff7f becomes 7f) drivers/media/tuners/mt2063.c:1321:62: warning: cast truncates bits from constant value (ffffff7f becomes 7f) Cast to u8 is unnecessary. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mt2063.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index f640dcf4a81d..9e9c5eb4cb66 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1216,7 +1216,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, if (status >= 0) { val = (state-> - reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] + reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode] ? 0x40 : 0x00); if (state->reg[MT2063_REG_PD1_TGT] != val) @@ -1225,7 +1225,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* LNARin */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | + u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) | (LNARIN[Mode] & 0x03); if (state->reg[MT2063_REG_CTRL_2C] != val) status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); @@ -1235,19 +1235,19 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, if (status >= 0) { val = (state-> - reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | + reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) | (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); /* trigger FIFF calibration, needed after changing FIFFQ */ val = - (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); + (state->reg[MT2063_REG_FIFF_CTRL] | 0x01); status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); val = (state-> - reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); + reg[MT2063_REG_FIFF_CTRL] & ~0x01); status |= mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); } @@ -1259,7 +1259,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* acLNAmax */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | + u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) | (ACLNAMAX[Mode] & 0x1F); if (state->reg[MT2063_REG_LNA_OV] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); @@ -1267,7 +1267,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* LNATGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) | (LNATGT[Mode] & 0x3F); if (state->reg[MT2063_REG_LNA_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); @@ -1275,7 +1275,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* ACRF */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | + u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) | (ACRFMAX[Mode] & 0x1F); if (state->reg[MT2063_REG_RF_OV] != val) status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); @@ -1283,7 +1283,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* PD1TGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) | (PD1TGT[Mode] & 0x3F); if (state->reg[MT2063_REG_PD1_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); @@ -1294,7 +1294,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, u8 val = ACFIFMAX[Mode]; if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) val = 5; - val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | + val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) | (val & 0x1F); if (state->reg[MT2063_REG_FIF_OV] != val) status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); @@ -1302,7 +1302,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* PD2TGT */ if (status >= 0) { - u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | + u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) | (PD2TGT[Mode] & 0x3F); if (state->reg[MT2063_REG_PD2_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); @@ -1310,7 +1310,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* Ignore ATN Overload */ if (status >= 0) { - val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | + val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) | (RFOVDIS[Mode] ? 0x80 : 0x00); if (state->reg[MT2063_REG_LNA_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); @@ -1318,7 +1318,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, /* Ignore FIF Overload */ if (status >= 0) { - val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | + val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) | (FIFOVDIS[Mode] ? 0x80 : 0x00); if (state->reg[MT2063_REG_PD1_TGT] != val) status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); -- cgit v1.2.3 From 313ddec45cf1a7b3778eaa9fd3acb31f994b2e88 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 14:32:26 -0300 Subject: [media] dmxdev: don't use before checking file->private_data As reported by smatch: drivers/media/dvb-core/dmxdev.c:1091 dvb_demux_poll() warn: variable dereferenced before check 'dmxdevfilter' (see line 1088) This was introduced by changeset d102cac8097c. We need to test before using it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 42b5e70d5ca7..abff803ad69a 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1085,10 +1085,9 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd, static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; - struct dmxdev *dmxdev = dmxdevfilter->dev; unsigned int mask = 0; - if ((!dmxdevfilter) || (dmxdev->exit)) + if ((!dmxdevfilter) || dmxdevfilter->dev->exit) return POLLERR; poll_wait(file, &dmxdevfilter->buffer.queue, wait); -- cgit v1.2.3 From a7459a9d3ab932209e3340d5ae4dadf73147e8d5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:44:54 -0300 Subject: [media] marvel-ccic: don't initialize static vars with 0 alloc_bufs_at_read is static. No need to initialize with zero, as the Kernel will cleanup the data memory already. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index be4b51212106..7a86c77bffa0 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -67,7 +67,7 @@ MODULE_PARM_DESC(dma_buf_size, "parameters require larger buffers, an attempt to reallocate " "will be made."); #else /* MCAM_MODE_VMALLOC */ -static const bool alloc_bufs_at_read = 0; +static const bool alloc_bufs_at_read; static const int n_dma_bufs = 3; /* Used by S/G_PARM */ #endif /* MCAM_MODE_VMALLOC */ -- cgit v1.2.3 From 93623c87a38533be4d8a636f29e58dbd01d3841b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 14:55:19 -0300 Subject: [media] soc_camera: use kmemdup() Instead of calling kzalloc and then copying, use kmemdup(). That avoids zeroing the data structure before copying. Found by coccinelle. Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index f4308fed5431..ee8cdc95a9f9 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1347,13 +1347,11 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, return -ENODEV; } - ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL); + ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL); if (!ssdd) { ret = -ENOMEM; goto ealloc; } - - memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd)); /* * In synchronous case we request regulators ourselves in * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try -- cgit v1.2.3 From 0282969190495950564fb0a7e6905881339a1ebc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 14:57:30 -0300 Subject: [media] vivid-vid-out: use memdup_user() Instead of allocating and coping from __user, do it using one atomic call. That makes the code simpler. Found by coccinelle. Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-out.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index c983461f29d5..8ed9f6d9f505 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -897,14 +897,10 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, return ret; if (win->bitmap) { - new_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + new_bitmap = memdup_user(win->bitmap, bitmap_size); - if (new_bitmap == NULL) - return -ENOMEM; - if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { - kfree(new_bitmap); - return -EFAULT; - } + if (IS_ERR(new_bitmap)) + return PTR_ERR(new_bitmap); } dev->overlay_out_top = win->w.top; -- cgit v1.2.3 From bc39d69ae18816577f20b122d8b2fca120cd2f4f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:15:53 -0300 Subject: [media] s5k5baf: remove an uneeded semicolon We don't use semicolons after curly braces in the middle of the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5k5baf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 564f05f2c9ef..0e461a6fd065 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -816,7 +816,7 @@ static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state) "error setting frame interval: %d\n", err); state->error = -EINVAL; } - }; + } v4l2_err(&state->sd, "cannot find correct frame interval\n"); state->error = -ERANGE; } -- cgit v1.2.3 From c3142a61e62481c8f7a4f19b92ff735516b54f87 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:32:07 -0300 Subject: [media] bttv-driver: remove an uneeded semicolon We don't use semicolons after curly braces in the middle of the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 970e542d3a51..750bdab8aacb 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3856,7 +3856,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), BT848_INT_MASK); - }; + } bttv_print_irqbits(stat,astat); -- cgit v1.2.3 From c611c908bb389b700501d028644b9feb8faa20f7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:51:45 -0300 Subject: [media] soc_camera: remove uneeded semicolons We don't use semicolons after curly braces in the middle of the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/pxa_camera.c | 2 +- drivers/media/platform/soc_camera/rcar_vin.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 64dc80ccd6f9..66178fc9f9eb 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1694,7 +1694,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, break; default: break; - }; + } if (ep.bus.parallel.flags & V4L2_MBUS_MASTER) pcdev->platform_flags |= PXA_CAMERA_MASTER; diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 85d579f65f52..b122c2cf5b85 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1502,7 +1502,7 @@ static int rcar_vin_probe(struct platform_device *pdev) } else { priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin"); priv->chip = (enum chip_id)match->data; - }; + } spin_lock_init(&priv->lock); INIT_LIST_HEAD(&priv->capture); -- cgit v1.2.3 From 49bc89623d4f7d7c5540083622459122e0ad2312 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:11:54 -0300 Subject: [media] stv0900_core: don't allocate a temporary var The error return code STV0900_NO_ERROR happens only once, at the end of the functions. So, just return it directly. This driver should actually be fixed to return standard Linux error codes, instead of its own macros, but this should be done on a separate patchset. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0900_core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index e5a87b57d855..2c88abfab531 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1270,7 +1270,6 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, enum fe_stv0900_demod_mode LDPC_Mode, enum fe_stv0900_demod_num demod) { - enum fe_stv0900_error error = STV0900_NO_ERROR; s32 reg_ind; dprintk("%s\n", __func__); @@ -1337,7 +1336,7 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, break; } - return error; + return STV0900_NO_ERROR; } static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, @@ -1555,8 +1554,6 @@ static int stv0900_status(struct stv0900_internal *intp, static int stv0900_set_mis(struct stv0900_internal *intp, enum fe_stv0900_demod_num demod, int mis) { - enum fe_stv0900_error error = STV0900_NO_ERROR; - dprintk("%s\n", __func__); if (mis < 0 || mis > 255) { @@ -1569,7 +1566,7 @@ static int stv0900_set_mis(struct stv0900_internal *intp, stv0900_write_reg(intp, ISIBITENA, 0xff); } - return error; + return STV0900_NO_ERROR; } -- cgit v1.2.3 From 7e6c8c1981b675c90820f55e5c03b83ae4ac3a43 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:06:13 -0300 Subject: [media] em28xx: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 6 +++--- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index ed843bd221ea..e978a2ae6f21 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -609,17 +609,17 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) static void em28xx_init_buttons(struct em28xx *dev) { u8 i = 0, j = 0; - bool addr_new = 0; + bool addr_new = false; dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL; while (dev->board.buttons[i].role >= 0 && dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) { struct em28xx_button *button = &dev->board.buttons[i]; /* Check if polling address is already on the list */ - addr_new = 1; + addr_new = true; for (j = 0; j < dev->num_button_polling_addresses; j++) { if (button->reg_r == dev->button_polling_addresses[j]) { - addr_new = 0; + addr_new = false; break; } } diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f6cf99fa30b2..3642438bc7d4 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -721,7 +721,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, struct em28xx_buffer *buf = dev->usb_ctl.vid_buf; struct em28xx_dmaqueue *dmaq = &dev->vidq; struct em28xx_v4l2 *v4l2 = dev->v4l2; - bool frame_end = 0; + bool frame_end = false; /* Check for header */ /* NOTE: at least with bulk transfers, only the first packet @@ -2308,7 +2308,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->v4l2_dev.ctrl_handler = hdl; if (dev->board.is_webcam) - v4l2->progressive = 1; + v4l2->progressive = true; /* * Default format, used for tvp5150 or saa711x output formats -- cgit v1.2.3 From 22bf3deb7ee483167edd8ec1aecfb9928a759580 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:08:11 -0300 Subject: [media] tuner-core: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 177023200737..559f8372e2eb 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -601,7 +601,7 @@ static int tuner_probe(struct i2c_client *client, t->name = "(tuner unset)"; t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; - t->standby = 1; + t->standby = true; t->radio_freq = 87.5 * 16000; /* Initial freq range */ t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */ -- cgit v1.2.3 From 6a5e7fde3a04ef5134702753f77e9b8aa6aab789 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:20:50 -0300 Subject: [media] af9013: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9013.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index ecf6388d2200..8001690d7576 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -683,7 +683,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) switch (c->transmission_mode) { case TRANSMISSION_MODE_AUTO: - auto_mode = 1; + auto_mode = true; break; case TRANSMISSION_MODE_2K: break; @@ -693,12 +693,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid transmission_mode\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->guard_interval) { case GUARD_INTERVAL_AUTO: - auto_mode = 1; + auto_mode = true; break; case GUARD_INTERVAL_1_32: break; @@ -714,12 +714,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid guard_interval\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->hierarchy) { case HIERARCHY_AUTO: - auto_mode = 1; + auto_mode = true; break; case HIERARCHY_NONE: break; @@ -734,12 +734,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) break; default: dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->modulation) { case QAM_AUTO: - auto_mode = 1; + auto_mode = true; break; case QPSK: break; @@ -751,7 +751,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) break; default: dev_dbg(&state->i2c->dev, "%s: invalid modulation\n", __func__); - auto_mode = 1; + auto_mode = true; } /* Use HP. How and which case we can switch to LP? */ @@ -759,7 +759,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) switch (c->code_rate_HP) { case FEC_AUTO: - auto_mode = 1; + auto_mode = true; break; case FEC_1_2: break; @@ -778,12 +778,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid code_rate_HP\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->code_rate_LP) { case FEC_AUTO: - auto_mode = 1; + auto_mode = true; break; case FEC_1_2: break; @@ -804,7 +804,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid code_rate_LP\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->bandwidth_hz) { -- cgit v1.2.3 From 285c0b005f387a9b1251d018aca3359497bd62a6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:22:02 -0300 Subject: [media] cxd2820r: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2820r_c.c | 4 ++-- drivers/media/dvb-frontends/cxd2820r_core.c | 4 ++-- drivers/media/dvb-frontends/cxd2820r_t.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 0f4657e01cde..149fdca3fb44 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -65,7 +65,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) } priv->delivery_system = SYS_DVBC_ANNEX_A; - priv->ber_running = 0; /* tune stops BER counter */ + priv->ber_running = false; /* tune stops BER counter */ /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { @@ -168,7 +168,7 @@ int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber) start_ber = 1; } } else { - priv->ber_running = 1; + priv->ber_running = true; start_ber = 1; } diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 03930d5e9fea..cd2af3edbd04 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -564,10 +564,10 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) /* check if we have a valid signal */ if (status & FE_HAS_LOCK) { - priv->last_tune_failed = 0; + priv->last_tune_failed = false; return DVBFE_ALGO_SEARCH_SUCCESS; } else { - priv->last_tune_failed = 1; + priv->last_tune_failed = true; return DVBFE_ALGO_SEARCH_AGAIN; } diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 9b5a45b907bc..51401d036530 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -89,7 +89,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) } priv->delivery_system = SYS_DVBT; - priv->ber_running = 0; /* tune stops BER counter */ + priv->ber_running = false; /* tune stops BER counter */ /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { @@ -272,7 +272,7 @@ int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber) start_ber = 1; } } else { - priv->ber_running = 1; + priv->ber_running = true; start_ber = 1; } -- cgit v1.2.3 From afbd6eb4ba25388955a87caa9ffac5c5c0d1c22e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:24:29 -0300 Subject: [media] m88ds3103: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 6eae2c619843..81657e94c5a4 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1063,16 +1063,16 @@ static int m88ds3103_set_voltage(struct dvb_frontend *fe, switch (fe_sec_voltage) { case SEC_VOLTAGE_18: - voltage_sel = 1; - voltage_dis = 0; + voltage_sel = true; + voltage_dis = false; break; case SEC_VOLTAGE_13: - voltage_sel = 0; - voltage_dis = 0; + voltage_sel = false; + voltage_dis = false; break; case SEC_VOLTAGE_OFF: - voltage_sel = 0; - voltage_dis = 1; + voltage_sel = false; + voltage_dis = true; break; default: dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n", -- cgit v1.2.3 From 2fe15e201375ced4f2d1e9504f6ea19f6ffcae18 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:25:39 -0300 Subject: [media] af9013: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Also, instead of testing foo == false, just use the simplified notation if(!foo). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 2 +- drivers/media/dvb-frontends/rtl2832_sdr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index fdbed35c87fa..eb737cf29a36 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -936,7 +936,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work) if (ret != 1) goto err; - priv->i2c_gate_state = 0; + priv->i2c_gate_state = false; return; err: diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 023e0f49c786..5bcf48bb4a71 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -1432,7 +1432,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, s->pixelformat = formats[0].pixelformat; s->buffersize = formats[0].buffersize; s->num_formats = NUM_FORMATS; - if (rtl2832_sdr_emulated_fmt == false) + if (!rtl2832_sdr_emulated_fmt) s->num_formats -= 1; mutex_init(&s->v4l2_lock); -- cgit v1.2.3 From 79a5ee7882d0bc757f6861149934af7e89ef72fe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:26:07 -0300 Subject: [media] tda10071: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/tda10071.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 9619be5d4827..4a19b85995f1 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -1037,7 +1037,7 @@ static int tda10071_init(struct dvb_frontend *fe) ret = -EFAULT; goto error; } else { - priv->warm = 1; + priv->warm = true; } cmd.args[0] = CMD_GET_FW_VERSION; -- cgit v1.2.3 From 06e916b75a067e4dceefcd19ddc34833b2f4a191 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:29:04 -0300 Subject: [media] smiapp-core: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index c4cc5de3ae59..d312932bc56e 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1312,7 +1312,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor) clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); regulator_disable(sensor->vana); - sensor->streaming = 0; + sensor->streaming = false; } static int smiapp_set_power(struct v4l2_subdev *subdev, int on) @@ -1509,13 +1509,13 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) return 0; if (enable) { - sensor->streaming = 1; + sensor->streaming = true; rval = smiapp_start_streaming(sensor); if (rval < 0) - sensor->streaming = 0; + sensor->streaming = false; } else { rval = smiapp_stop_streaming(sensor); - sensor->streaming = 0; + sensor->streaming = false; } return rval; -- cgit v1.2.3 From cdde1a9bae292bcfca03ed9d77506ff1d376051f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:29:45 -0300 Subject: [media] ov9740: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/ov9740.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index ea76863dfdb4..ee9eb635d540 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -564,13 +564,13 @@ static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height) u32 y_start; u32 x_end; u32 y_end; - bool scaling = 0; + bool scaling = false; u32 scale_input_x; u32 scale_input_y; int ret; if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT)) - scaling = 1; + scaling = true; /* * Try to use as much of the sensor area as possible when supporting -- cgit v1.2.3 From 11b4c175d99481b239993242b14961299477491d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:48:14 -0300 Subject: [media] omap3isp: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index cabf46b4b645..81a9dc053d58 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1806,7 +1806,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) spin_lock_irqsave(&ccdc->lock, flags); if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running && ccdc->bt656) - restart = 1; + restart = true; else ccdc->underrun = 1; spin_unlock_irqrestore(&ccdc->lock, flags); -- cgit v1.2.3 From 68bbbd7912abb7ec8633fb32342ed9049ed98ab5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:52:21 -0300 Subject: [media] ti-vpe: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 773b1fbf3269..febeca70211b 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -835,10 +835,10 @@ static int set_srcdst_params(struct vpe_ctx *ctx) VPDMA_STRIDE_ALIGN); mv_buf_size = bytes_per_line * s_q_data->height; - ctx->deinterlacing = 1; + ctx->deinterlacing = true; src_h <<= 1; } else { - ctx->deinterlacing = 0; + ctx->deinterlacing = false; mv_buf_size = 0; } -- cgit v1.2.3 From 6c515a44a84aef17dc63b30e84ef87c53c580585 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:53:45 -0300 Subject: [media] vivid-tpg: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 8576b2c1d4a1..57ff428c897e 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -183,7 +183,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: - tpg->is_yuv = 0; + tpg->is_yuv = false; break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: @@ -193,7 +193,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: - tpg->is_yuv = 1; + tpg->is_yuv = true; break; default: return false; -- cgit v1.2.3 From 8b4b68186f7095fc2a4badaacd31a39ac6cadea2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:54:17 -0300 Subject: [media] radio: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 2 +- drivers/media/radio/radio-sf16fmi.c | 4 ++-- drivers/media/radio/si470x/radio-si470x-common.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 235c0e349820..cff1eb144a5c 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -332,7 +332,7 @@ static int __init gemtek_init(void) static void __exit gemtek_exit(void) { - hardmute = 1; /* Turn off PLL */ + hardmute = true; /* Turn off PLL */ #ifdef CONFIG_PNP pnp_unregister_driver(&gemtek_driver.pnp_driver); #endif diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index d7ce8fe6b5ae..bcd0946c84a5 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -285,7 +285,7 @@ static int __init fmi_init(void) io = isapnp_fmi_probe(); if (io < 0) continue; - pnp_attached = 1; + pnp_attached = true; } if (!request_region(io, 2, "radio-sf16fmi")) { if (pnp_attached) @@ -349,7 +349,7 @@ static int __init fmi_init(void) mutex_init(&fmi->lock); /* mute card and set default frequency */ - fmi->mute = 1; + fmi->mute = true; fmi->curfreq = RSF16_MINFREQ; fmi_set_freq(fmi); diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 0e750aef656a..909c3f92d839 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -208,7 +208,7 @@ static int si470x_set_band(struct si470x_device *radio, int band) static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) { int retval; - bool timed_out = 0; + bool timed_out = false; /* start tuning */ radio->registers[CHANNEL] &= ~CHANNEL_CHAN; @@ -300,7 +300,7 @@ static int si470x_set_seek(struct si470x_device *radio, { int band, retval; unsigned int freq; - bool timed_out = 0; + bool timed_out = false; /* set band */ if (seek->rangelow || seek->rangehigh) { -- cgit v1.2.3 From 2816cc31e06b9d04ac0a92ae6a8311b5ab873fed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:01:36 -0300 Subject: [media] ene_ir: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index d16d9b496b92..e80f2c6c5f1a 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -979,7 +979,7 @@ static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n) dev->tx_reg = 0; dev->tx_done = 0; dev->tx_sample = 0; - dev->tx_sample_pulse = 0; + dev->tx_sample_pulse = false; dbg("TX: %d samples", dev->tx_len); -- cgit v1.2.3 From f6b83c3e06e2e6dddd126294bf465afec5dd495e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:17:56 -0300 Subject: [media] au0828-dvb: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 4bd9d687d2d6..00ab1563d142 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -630,7 +630,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev) stop_urb_transfer(dev); au0828_stop_transport(dev, 1); mutex_unlock(&dvb->lock); - dev->need_urb_start = 1; + dev->need_urb_start = true; } /* suspend frontend - does tuner and fe to sleep */ rc = dvb_frontend_suspend(dvb->frontend); -- cgit v1.2.3 From 235d89ec4a1b7b34005ba5f277a3cd7ece7f3a8b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:18:17 -0300 Subject: [media] lmedm04: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/lmedm04.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index e332af731187..9f2c5459b73a 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -1252,7 +1252,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, /* Turn PID filter on the fly by module option */ if (pid_filter == 2) { - adap->pid_filtering = 1; + adap->pid_filtering = true; adap->max_feed_count = 15; } -- cgit v1.2.3 From 61f6a0569c6ce563accb8f415373756febe62752 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:18:48 -0300 Subject: [media] af9005: use true/false for boolean vars Instead of using 0 or 1 for boolean, use the true/false defines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/af9005.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index af176b6ce738..3f4361e48a32 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." DVB_USB_DEBUG_STATUS); /* enable obnoxious led */ -bool dvb_usb_af9005_led = 1; +bool dvb_usb_af9005_led = true; module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); -- cgit v1.2.3 From ad7b8c0227ef18b29256e063d788e206c1466ac2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:19:29 -0300 Subject: [media] msi2500: simplify boolean tests Instead of using if (foo == false), just use if (!foo). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 71e0960b46c0..e980aaa47b7c 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1212,7 +1212,7 @@ static int msi2500_probe(struct usb_interface *intf, s->pixelformat = formats[0].pixelformat; s->buffersize = formats[0].buffersize; s->num_formats = NUM_FORMATS; - if (msi2500_emulated_fmt == false) + if (!msi2500_emulated_fmt) s->num_formats -= 2; /* Init videobuf2 queue structure */ -- cgit v1.2.3 From 5a7f7b79d80ee8ee9f54055f1ba56fae1644b4ec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:23:57 -0300 Subject: [media] drxk_hard: simplify test logic instead of testing if it is false or true, just use if (!foo) or if (foo). That makes the code easier to read and shorter. Also, properly initialize booleans with true or false. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index cce94a75b2e1..88182c18e186 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -1028,7 +1028,7 @@ static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result) ((state->m_hi_cfg_ctrl) & SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) == SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ); - if (powerdown_cmd == false) { + if (!powerdown_cmd) { /* Wait until command rdy */ u32 retry_count = 0; u16 wait_cmd; @@ -1129,7 +1129,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable) if (status < 0) goto error; - if (mpeg_enable == false) { + if (!mpeg_enable) { /* Set MPEG TS pads to inputmode */ status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000); if (status < 0) @@ -1190,7 +1190,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable) if (status < 0) goto error; - if (state->m_enable_parallel == true) { + if (state->m_enable_parallel) { /* parallel -> enable MD1 to MD7 */ status = write16(state, SIO_PDR_MD1_CFG__A, sio_pdr_mdx_cfg); @@ -1392,7 +1392,7 @@ static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable) dprintk(1, "\n"); - if (enable == false) { + if (!enable) { desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF; desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN; } @@ -2012,7 +2012,7 @@ static int mpegts_dto_setup(struct drxk_state *state, goto error; fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M); fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M); - if (state->m_insert_rs_byte == true) { + if (state->m_insert_rs_byte) { /* enable parity symbol forward */ fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M; /* MVAL disable during parity bytes */ @@ -2023,7 +2023,7 @@ static int mpegts_dto_setup(struct drxk_state *state, /* Check serial or parallel output */ fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M)); - if (state->m_enable_parallel == false) { + if (!state->m_enable_parallel) { /* MPEG data output is serial -> set ipr_mode[0] */ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M; } @@ -2136,19 +2136,19 @@ static int mpegts_configure_polarity(struct drxk_state *state) /* Control selective inversion of output bits */ fec_oc_reg_ipr_invert &= (~(invert_data_mask)); - if (state->m_invert_data == true) + if (state->m_invert_data) fec_oc_reg_ipr_invert |= invert_data_mask; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M)); - if (state->m_invert_err == true) + if (state->m_invert_err) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M)); - if (state->m_invert_str == true) + if (state->m_invert_str) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M)); - if (state->m_invert_val == true) + if (state->m_invert_val) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M)); - if (state->m_invert_clk == true) + if (state->m_invert_clk) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M; return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert); @@ -3352,7 +3352,7 @@ static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled) int status; dprintk(1, "\n"); - if (*enabled == true) + if (*enabled) status = write16(state, IQM_CF_BYPASSDET__A, 0); else status = write16(state, IQM_CF_BYPASSDET__A, 1); @@ -3368,7 +3368,7 @@ static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled) int status; dprintk(1, "\n"); - if (*enabled == true) { + if (*enabled) { /* write mask to 1 */ status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, DEFAULT_FR_THRES_8K); @@ -6794,11 +6794,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->enable_merr_cfg = config->enable_merr_cfg; if (config->dynamic_clk) { - state->m_dvbt_static_clk = 0; - state->m_dvbc_static_clk = 0; + state->m_dvbt_static_clk = false; + state->m_dvbc_static_clk = false; } else { - state->m_dvbt_static_clk = 1; - state->m_dvbc_static_clk = 1; + state->m_dvbt_static_clk = true; + state->m_dvbc_static_clk = true; } -- cgit v1.2.3 From afb666d1e7b0af5ec8f8b35b6f9d813d538c95e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:28:27 -0300 Subject: [media] lm3560: simplify boolean tests Instead of using if (on == true), just use if (on). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/lm3560.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index c23de593c17d..d9ece4b2d047 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -100,14 +100,14 @@ static int lm3560_enable_ctrl(struct lm3560_flash *flash, int rval; if (led_no == LM3560_LED0) { - if (on == true) + if (on) rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x08, 0x08); else rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x08, 0x00); } else { - if (on == true) + if (on) rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x10, 0x10); else -- cgit v1.2.3 From 1b21e2187adea385d9de53c8c861d9f56ea5bebe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:39:01 -0300 Subject: [media] lm3560: simplify a boolean test lml33dpatch is boolean. So, the possible values are true or false. Instead of using if (lml33dpath), just use if (!lml33dpath). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index bf34b93f23ee..b6801e035ea4 100644 --- a/drivers/media/pci/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -682,7 +682,7 @@ set_videobus_dir (struct zoran *zr, switch (zr->card.type) { case LML33: case LML33R10: - if (lml33dpath == 0) + if (!lml33dpath) GPIO(zr, 5, val); else GPIO(zr, 5, 1); -- cgit v1.2.3 From 160ac0babc0d8c382bdf32db238bf16a3d3fa0a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:46:32 -0300 Subject: [media] omap: simplify test logic instead of testing bools if they are false or true, just use if (!foo) or if (foo). That makes the code easier to read and shorter. Also, properly initialize booleans with true or false. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 8 ++++---- drivers/media/platform/omap/omap_vout_vrfb.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index d9258f3d0f8e..64ab6fb06b9c 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -989,7 +989,7 @@ static int omap_vout_release(struct file *file) mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; omap_dispc_unregister_isr(omap_vout_isr, vout, mask); - vout->streaming = 0; + vout->streaming = false; videobuf_streamoff(q); videobuf_queue_cancel(q); @@ -1644,7 +1644,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) vout->field_id = 0; /* set flag here. Next QBUF will start DMA */ - vout->streaming = 1; + vout->streaming = true; vout->first_int = 1; @@ -1704,7 +1704,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) if (!vout->streaming) return -EINVAL; - vout->streaming = 0; + vout->streaming = false; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; @@ -1912,7 +1912,7 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) control[0].id = V4L2_CID_ROTATE; control[0].value = 0; vout->rotation = 0; - vout->mirror = 0; + vout->mirror = false; vout->control[2].id = V4L2_CID_HFLIP; vout->control[2].value = 0; if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 62e7e5783ce8..aa39306afc73 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -148,7 +148,7 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, ret = -ENOMEM; goto release_vrfb_ctx; } - vout->vrfb_static_allocation = 1; + vout->vrfb_static_allocation = true; } return 0; @@ -336,7 +336,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) offset = vout->vrfb_context[0].yoffset * vout->vrfb_context[0].bytespp; temp_ps = ps / vr_ps; - if (mirroring == 0) { + if (!mirroring) { *cropped_offset = offset + line_length * temp_ps * cleft + crop->top * temp_ps; } else { @@ -350,7 +350,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) vout->vrfb_context[0].bytespp) + (vout->vrfb_context[0].xoffset * vout->vrfb_context[0].bytespp)); - if (mirroring == 0) { + if (!mirroring) { *cropped_offset = offset + (line_length * ps * ctop) + (cleft / vr_ps) * ps; @@ -364,7 +364,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * vout->vrfb_context[0].bytespp; temp_ps = ps / vr_ps; - if (mirroring == 0) { + if (!mirroring) { *cropped_offset = offset + line_length * temp_ps * crop->left + ctop * ps; } else { @@ -375,7 +375,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) } break; case dss_rotation_0_degree: - if (mirroring == 0) { + if (!mirroring) { *cropped_offset = (line_length * ps) * crop->top + (crop->left / vr_ps) * ps; } else { -- cgit v1.2.3 From b2617dc3eb3ed3e768919cda55b36571bc6c7bf8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:53:05 -0300 Subject: [media] via-camera: simplify boolean tests Instead of using if (foo == false), just use if (!foo). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/via-camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 00d431293190..ae6870cb8339 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1276,7 +1276,7 @@ static bool viacam_serial_is_enabled(void) VIACAM_SERIAL_CREG, &cbyte); if ((cbyte & VIACAM_SERIAL_BIT) == 0) return false; /* Not enabled */ - if (override_serial == 0) { + if (!override_serial) { printk(KERN_NOTICE "Via camera: serial port is enabled, " \ "refusing to load.\n"); printk(KERN_NOTICE "Specify override_serial=1 to force " \ -- cgit v1.2.3 From a04557a20be0ff3733eca454abdd1bd4c5ebc3f2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:04:59 -0300 Subject: [media] e4000: simplify boolean tests Instead of using if (foo == false), just use if (!foo). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 90d93348f20c..cd9cf643f602 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -400,7 +400,7 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl); int ret; - if (s->active == false) + if (!s->active) return 0; switch (ctrl->id) { @@ -423,7 +423,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - if (s->active == false) + if (!s->active) return 0; switch (ctrl->id) { -- cgit v1.2.3 From d8e8b40c067c3242b32ebe835f6bc6247fd67454 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:50:39 -0300 Subject: [media] s5p-tv: Simplify the return logic Make sure pm_runtime_* calls does not use unnecessary IS_ERR_VALUE(). Reported by scripts/coccinelle/api/pm_runtime.cocci script. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmi_drv.c | 2 +- drivers/media/platform/s5p-tv/sdo_drv.c | 2 +- drivers/media/platform/s5p-tv/sii9234_drv.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 754740f4b671..37c8bd694c5f 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -615,7 +615,7 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on) else ret = pm_runtime_put_sync(hdev->dev); /* only values < 0 indicate errors */ - return IS_ERR_VALUE(ret) ? ret : 0; + return ret < 0 ? ret : 0; } static int hdmi_s_dv_timings(struct v4l2_subdev *sd, diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 5a7c3796f22e..72cf892dd008 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c @@ -190,7 +190,7 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on) ret = pm_runtime_put_sync(dev); /* only values < 0 indicate errors */ - return IS_ERR_VALUE(ret) ? ret : 0; + return ret < 0 ? ret : 0; } static int sdo_streamon(struct sdo_device *sdev) diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c index 3dd762e5b67e..db8c17bb4aaa 100644 --- a/drivers/media/platform/s5p-tv/sii9234_drv.c +++ b/drivers/media/platform/s5p-tv/sii9234_drv.c @@ -289,7 +289,7 @@ static int sii9234_s_power(struct v4l2_subdev *sd, int on) else ret = pm_runtime_put(&ctx->client->dev); /* only values < 0 indicate errors */ - return IS_ERR_VALUE(ret) ? ret : 0; + return ret < 0 ? ret : 0; } static int sii9234_s_stream(struct v4l2_subdev *sd, int enable) -- cgit v1.2.3 From 2f1e48d670dc755d40f7bd926d02713d90b378ea Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:02:55 -0300 Subject: [media] siano: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 050984c5b1e3..a3677438205e 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -2129,8 +2129,6 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, static int __init smscore_module_init(void) { - int rc = 0; - INIT_LIST_HEAD(&g_smscore_notifyees); INIT_LIST_HEAD(&g_smscore_devices); kmutex_init(&g_smscore_deviceslock); @@ -2138,7 +2136,7 @@ static int __init smscore_module_init(void) INIT_LIST_HEAD(&g_smscore_registry); kmutex_init(&g_smscore_registrylock); - return rc; + return 0; } static void __exit smscore_module_exit(void) -- cgit v1.2.3 From 7c9950768fb4a0a3fbd3a866ae94734c5078fd0c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:10:25 -0300 Subject: [media] stv0367: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0367.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 764577218974..59f622ae80e8 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -1935,8 +1935,6 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; - - int error = 0; enum stv0367_ter_mode mode; int constell = 0,/* snr = 0,*/ Data = 0; @@ -2020,7 +2018,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe) p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); - return error; + return 0; } static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) -- cgit v1.2.3 From 8b37c6455fc8f43e0e95db2847284e618db6a4f8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:18:27 -0300 Subject: [media] media-devnode: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-devnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 7acd19c881de..ebf9626e5ae5 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -192,7 +192,6 @@ static int media_open(struct inode *inode, struct file *filp) static int media_release(struct inode *inode, struct file *filp) { struct media_devnode *mdev = media_devnode_data(filp); - int ret = 0; if (mdev->fops->release) mdev->fops->release(filp); @@ -201,7 +200,7 @@ static int media_release(struct inode *inode, struct file *filp) return value is ignored. */ put_device(&mdev->dev); filp->private_data = NULL; - return ret; + return 0; } static const struct file_operations media_devnode_fops = { -- cgit v1.2.3 From a896dc7a1f416e2b76efabff27c624c69645cc50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:30:41 -0300 Subject: [media] bt8xx: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 3 +-- drivers/media/pci/bt8xx/dst_ca.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 750bdab8aacb..4a8176c09fc9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, { struct bttv_buffer *old; unsigned long flags; - int retval = 0; dprintk("switch_overlay: enter [new=%p]\n", new); if (new) @@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, if (NULL == new) free_btres_lock(btv,fh,RESOURCE_OVERLAY); dprintk("switch_overlay: done\n"); - return retval; + return 0; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index 0e788fca992c..c22c4ae06844 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file) static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { - ssize_t bytes_read = 0; - dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); - return bytes_read; + return 0; } static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) -- cgit v1.2.3 From 5b0eb8271d9126db2daa2cf41422cc84ba319a6e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:36:12 -0300 Subject: [media] saa7164: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index e042963d377d..4f3b1dd18ba4 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -680,7 +680,6 @@ static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) { struct saa7164_dev *dev = port->dev; - int ret = 0; u8 agc_disable; dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std); @@ -733,7 +732,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */ msleep(100); - return ret; + return 0; } /* Ensure the dif is in the correct state for the operating mode -- cgit v1.2.3 From b80cefb4153b374d536c11ac4664cfc6dd90073b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:39:46 -0300 Subject: [media] davinci: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Acked-by: "Lad, Prabhakar" Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ed9dd27e3c63..c557eb5ebf6b 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -943,12 +943,11 @@ static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); /* Fill in the information about format */ *fmt = vpfe_dev->fmt; - return ret; + return 0; } static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, -- cgit v1.2.3 From 6cf77d18f6ffa3eda879aff919a8cca10d5aa85a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:40:22 -0300 Subject: [media] marvel-ccic: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-isp-video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 93f9cf2ebcd6..9d8d885558e5 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -313,7 +313,6 @@ static int isp_video_release(struct file *file) struct fimc_is_video *ivc = &isp->video_capture; struct media_entity *entity = &ivc->ve.vdev.entity; struct media_device *mdev = entity->parent; - int ret = 0; mutex_lock(&isp->video_lock); @@ -335,7 +334,7 @@ static int isp_video_release(struct file *file) pm_runtime_put(&isp->pdev->dev); mutex_unlock(&isp->video_lock); - return ret; + return 0; } static const struct v4l2_file_operations isp_video_fops = { -- cgit v1.2.3 From 9b08f41724b60a49979a2458e90918f812228a37 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:02:30 -0300 Subject: [media] fintek-cir: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/fintek-cir.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index f0a1f7d31ee6..b5167573240e 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -148,7 +148,6 @@ static int fintek_hw_detect(struct fintek_dev *fintek) u8 vendor_major, vendor_minor; u8 portsel, ir_class; u16 vendor, chip; - int ret = 0; fintek_config_mode_enable(fintek); @@ -208,7 +207,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek) spin_unlock_irqrestore(&fintek->fintek_lock, flags); - return ret; + return 0; } static void fintek_cir_ldev_init(struct fintek_dev *fintek) @@ -644,7 +643,6 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) static int fintek_resume(struct pnp_dev *pdev) { - int ret = 0; struct fintek_dev *fintek = pnp_get_drvdata(pdev); fit_dbg("%s called", __func__); @@ -661,7 +659,7 @@ static int fintek_resume(struct pnp_dev *pdev) fintek_cir_regs_init(fintek); - return ret; + return 0; } static void fintek_shutdown(struct pnp_dev *pdev) -- cgit v1.2.3 From fc823729e0b432a628d3f32e11dfa83a30de35aa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:03:08 -0300 Subject: [media] ite-cir: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 447fe35862dc..56abf9120cc2 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1666,7 +1666,6 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state) static int ite_resume(struct pnp_dev *pdev) { - int ret = 0; struct ite_dev *dev = pnp_get_drvdata(pdev); unsigned long flags; @@ -1681,7 +1680,7 @@ static int ite_resume(struct pnp_dev *pdev) spin_unlock_irqrestore(&dev->lock, flags); - return ret; + return 0; } static void ite_shutdown(struct pnp_dev *pdev) -- cgit v1.2.3 From f2747cf6f0a1110d132280d49ce3dd6886dacd85 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:03:41 -0300 Subject: [media] nuvoton-cir: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 7f4fd859bba5..9c2c8635ff33 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -229,7 +229,6 @@ static int nvt_hw_detect(struct nvt_dev *nvt) { unsigned long flags; u8 chip_major, chip_minor; - int ret = 0; char chip_id[12]; bool chip_unknown = false; @@ -285,7 +284,7 @@ static int nvt_hw_detect(struct nvt_dev *nvt) nvt->chip_minor = chip_minor; spin_unlock_irqrestore(&nvt->nvt_lock, flags); - return ret; + return 0; } static void nvt_cir_ldev_init(struct nvt_dev *nvt) @@ -1177,7 +1176,6 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) static int nvt_resume(struct pnp_dev *pdev) { - int ret = 0; struct nvt_dev *nvt = pnp_get_drvdata(pdev); nvt_dbg("%s called", __func__); @@ -1195,7 +1193,7 @@ static int nvt_resume(struct pnp_dev *pdev) nvt_cir_regs_init(nvt); nvt_cir_wake_regs_init(nvt); - return ret; + return 0; } static void nvt_shutdown(struct pnp_dev *pdev) -- cgit v1.2.3 From 4539fc5c68d78f2df815f426f957528011b50a08 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:06:55 -0300 Subject: [media] mt2060: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mt2060.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c index 13381de58a84..b87b2549d58d 100644 --- a/drivers/media/tuners/mt2060.c +++ b/drivers/media/tuners/mt2060.c @@ -157,7 +157,6 @@ static int mt2060_set_params(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2060_priv *priv; - int ret=0; int i=0; u32 freq; u8 lnaband; @@ -240,7 +239,7 @@ static int mt2060_set_params(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ - return ret; + return 0; } static void mt2060_calibrate(struct mt2060_priv *priv) -- cgit v1.2.3 From 2f00fce46793bc5b523c64dcefd7bac13ab70b9c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:16:04 -0300 Subject: [media] mxl5005s: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mxl5005s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index b473b76cb278..92a3be4fde87 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -1692,7 +1692,6 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, ) { struct mxl5005s_state *state = fe->tuner_priv; - u16 status = 0; state->Mode = Mode; state->IF_Mode = IF_mode; @@ -1715,7 +1714,7 @@ static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, /* Synthesizer LO frequency calculation */ MXL_SynthIFLO_Calc(fe); - return status; + return 0; } static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) -- cgit v1.2.3 From ea21f702fc65e1f343dcbc422613cbb8af23d901 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 16:16:53 -0300 Subject: [media] cx231xx: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 2adfecf70236..6c7b5e250eed 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -403,8 +403,6 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) { - int status = 0; - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; @@ -423,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) } - return status; + return 0; } int cx231xx_reset_analog_tuner(struct cx231xx *dev) -- cgit v1.2.3 From 97e0e1e867952d369f245fce0d6791eacb40b2bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 18:42:09 -0300 Subject: [media] xc4000: Fix bad alignments As reported by cocinelle: drivers/media/tuners/xc4000.c:573:2-28: code aligned with following code on line 574 drivers/media/tuners/xc4000.c:575:2-29: code aligned with following code on line 576 drivers/media/tuners/xc4000.c:577:2-29: code aligned with following code on line 578 drivers/media/tuners/xc4000.c:579:2-27: code aligned with following code on line 580 drivers/media/tuners/xc4000.c:581:2-29: code aligned with following code on line 582 drivers/media/tuners/xc4000.c:583:2-29: code aligned with following code on line 584 drivers/media/tuners/xc4000.c:585:2-28: code aligned with following code on line 586 drivers/media/tuners/xc4000.c:587:2-27: code aligned with following code on line 588 drivers/media/tuners/xc4000.c:589:2-28: code aligned with following code on line 590 drivers/media/tuners/xc4000.c:591:2-29: code aligned with following code on line 592 drivers/media/tuners/xc4000.c:593:2-28: code aligned with following code on line 594 drivers/media/tuners/xc4000.c:595:2-26: code aligned with following code on line 596 drivers/media/tuners/xc4000.c:597:2-30: code aligned with following code on line 598 drivers/media/tuners/xc4000.c:599:2-27: code aligned with following code on line 600 drivers/media/tuners/xc4000.c:601:2-28: code aligned with following code on line 602 drivers/media/tuners/xc4000.c:603:2-28: code aligned with following code on line 604 drivers/media/tuners/xc4000.c:605:2-28: code aligned with following code on line 606 drivers/media/tuners/xc4000.c:607:2-26: code aligned with following code on line 608 drivers/media/tuners/xc4000.c:609:2-28: code aligned with following code on line 610 drivers/media/tuners/xc4000.c:611:2-30: code aligned with following code on line 612 drivers/media/tuners/xc4000.c:613:2-31: code aligned with following code on line 614 drivers/media/tuners/xc4000.c:615:2-30: code aligned with following code on line 616 drivers/media/tuners/xc4000.c:617:2-33: code aligned with following code on line 618 drivers/media/tuners/xc4000.c:619:2-33: code aligned with following code on line 620 drivers/media/tuners/xc4000.c:621:2-32: code aligned with following code on line 622 drivers/media/tuners/xc4000.c:623:2-34: code aligned with following code on line 624 drivers/media/tuners/xc4000.c:625:2-29: code aligned with following code on line 626 drivers/media/tuners/xc4000.c:627:2-29: code aligned with following code on line 628 drivers/media/tuners/xc4000.c:629:2-30: code aligned with following code on line 630 drivers/media/tuners/xc4000.c:631:2-29: code aligned with following code on line 632 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc4000.c | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index f9ab79e3432d..219ebafae70f 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -569,67 +569,67 @@ static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { - if (type & BASE) + if (type & BASE) printk(KERN_CONT "BASE "); - if (type & INIT1) + if (type & INIT1) printk(KERN_CONT "INIT1 "); - if (type & F8MHZ) + if (type & F8MHZ) printk(KERN_CONT "F8MHZ "); - if (type & MTS) + if (type & MTS) printk(KERN_CONT "MTS "); - if (type & D2620) + if (type & D2620) printk(KERN_CONT "D2620 "); - if (type & D2633) + if (type & D2633) printk(KERN_CONT "D2633 "); - if (type & DTV6) + if (type & DTV6) printk(KERN_CONT "DTV6 "); - if (type & QAM) + if (type & QAM) printk(KERN_CONT "QAM "); - if (type & DTV7) + if (type & DTV7) printk(KERN_CONT "DTV7 "); - if (type & DTV78) + if (type & DTV78) printk(KERN_CONT "DTV78 "); - if (type & DTV8) + if (type & DTV8) printk(KERN_CONT "DTV8 "); - if (type & FM) + if (type & FM) printk(KERN_CONT "FM "); - if (type & INPUT1) + if (type & INPUT1) printk(KERN_CONT "INPUT1 "); - if (type & LCD) + if (type & LCD) printk(KERN_CONT "LCD "); - if (type & NOGD) + if (type & NOGD) printk(KERN_CONT "NOGD "); - if (type & MONO) + if (type & MONO) printk(KERN_CONT "MONO "); - if (type & ATSC) + if (type & ATSC) printk(KERN_CONT "ATSC "); - if (type & IF) + if (type & IF) printk(KERN_CONT "IF "); - if (type & LG60) + if (type & LG60) printk(KERN_CONT "LG60 "); - if (type & ATI638) + if (type & ATI638) printk(KERN_CONT "ATI638 "); - if (type & OREN538) + if (type & OREN538) printk(KERN_CONT "OREN538 "); - if (type & OREN36) + if (type & OREN36) printk(KERN_CONT "OREN36 "); - if (type & TOYOTA388) + if (type & TOYOTA388) printk(KERN_CONT "TOYOTA388 "); - if (type & TOYOTA794) + if (type & TOYOTA794) printk(KERN_CONT "TOYOTA794 "); - if (type & DIBCOM52) + if (type & DIBCOM52) printk(KERN_CONT "DIBCOM52 "); - if (type & ZARLINK456) + if (type & ZARLINK456) printk(KERN_CONT "ZARLINK456 "); - if (type & CHINA) + if (type & CHINA) printk(KERN_CONT "CHINA "); - if (type & F6MHZ) + if (type & F6MHZ) printk(KERN_CONT "F6MHZ "); - if (type & INPUT2) + if (type & INPUT2) printk(KERN_CONT "INPUT2 "); - if (type & SCODE) + if (type & SCODE) printk(KERN_CONT "SCODE "); - if (type & HAS_IF) + if (type & HAS_IF) printk(KERN_CONT "HAS_IF_%d ", int_freq); } -- cgit v1.2.3 From c56019fc40c5b7a7b3aa7be7f17c6b993cd853b5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 18:43:31 -0300 Subject: [media] tuner-xc2028: fix bad alignments As reported by cocinelle: drivers/media/tuners/tuner-xc2028.c:182:2-18: code aligned with following code on line 183 drivers/media/tuners/tuner-xc2028.c:184:2-19: code aligned with following code on line 185 drivers/media/tuners/tuner-xc2028.c:186:2-19: code aligned with following code on line 187 drivers/media/tuners/tuner-xc2028.c:188:2-17: code aligned with following code on line 189 drivers/media/tuners/tuner-xc2028.c:190:2-19: code aligned with following code on line 191 drivers/media/tuners/tuner-xc2028.c:192:2-19: code aligned with following code on line 193 drivers/media/tuners/tuner-xc2028.c:194:2-18: code aligned with following code on line 195 drivers/media/tuners/tuner-xc2028.c:196:2-17: code aligned with following code on line 197 drivers/media/tuners/tuner-xc2028.c:198:2-18: code aligned with following code on line 199 drivers/media/tuners/tuner-xc2028.c:200:2-19: code aligned with following code on line 201 drivers/media/tuners/tuner-xc2028.c:202:2-18: code aligned with following code on line 203 drivers/media/tuners/tuner-xc2028.c:204:2-16: code aligned with following code on line 205 drivers/media/tuners/tuner-xc2028.c:206:2-20: code aligned with following code on line 207 drivers/media/tuners/tuner-xc2028.c:208:2-17: code aligned with following code on line 209 drivers/media/tuners/tuner-xc2028.c:210:2-18: code aligned with following code on line 211 drivers/media/tuners/tuner-xc2028.c:212:2-18: code aligned with following code on line 213 drivers/media/tuners/tuner-xc2028.c:214:2-18: code aligned with following code on line 215 drivers/media/tuners/tuner-xc2028.c:216:2-16: code aligned with following code on line 217 drivers/media/tuners/tuner-xc2028.c:218:2-18: code aligned with following code on line 219 drivers/media/tuners/tuner-xc2028.c:220:2-20: code aligned with following code on line 221 drivers/media/tuners/tuner-xc2028.c:222:2-21: code aligned with following code on line 223 drivers/media/tuners/tuner-xc2028.c:224:2-20: code aligned with following code on line 225 drivers/media/tuners/tuner-xc2028.c:226:2-23: code aligned with following code on line 227 drivers/media/tuners/tuner-xc2028.c:228:2-23: code aligned with following code on line 229 drivers/media/tuners/tuner-xc2028.c:230:2-22: code aligned with following code on line 231 drivers/media/tuners/tuner-xc2028.c:232:2-24: code aligned with following code on line 233 drivers/media/tuners/tuner-xc2028.c:234:2-19: code aligned with following code on line 235 drivers/media/tuners/tuner-xc2028.c:236:2-19: code aligned with following code on line 237 drivers/media/tuners/tuner-xc2028.c:238:2-20: code aligned with following code on line 239 drivers/media/tuners/tuner-xc2028.c:240:2-19: code aligned with following code on line 241 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner-xc2028.c | 62 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 565eeebb3aeb..d12f5e4ad8bf 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -178,67 +178,67 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { - if (type & BASE) + if (type & BASE) printk("BASE "); - if (type & INIT1) + if (type & INIT1) printk("INIT1 "); - if (type & F8MHZ) + if (type & F8MHZ) printk("F8MHZ "); - if (type & MTS) + if (type & MTS) printk("MTS "); - if (type & D2620) + if (type & D2620) printk("D2620 "); - if (type & D2633) + if (type & D2633) printk("D2633 "); - if (type & DTV6) + if (type & DTV6) printk("DTV6 "); - if (type & QAM) + if (type & QAM) printk("QAM "); - if (type & DTV7) + if (type & DTV7) printk("DTV7 "); - if (type & DTV78) + if (type & DTV78) printk("DTV78 "); - if (type & DTV8) + if (type & DTV8) printk("DTV8 "); - if (type & FM) + if (type & FM) printk("FM "); - if (type & INPUT1) + if (type & INPUT1) printk("INPUT1 "); - if (type & LCD) + if (type & LCD) printk("LCD "); - if (type & NOGD) + if (type & NOGD) printk("NOGD "); - if (type & MONO) + if (type & MONO) printk("MONO "); - if (type & ATSC) + if (type & ATSC) printk("ATSC "); - if (type & IF) + if (type & IF) printk("IF "); - if (type & LG60) + if (type & LG60) printk("LG60 "); - if (type & ATI638) + if (type & ATI638) printk("ATI638 "); - if (type & OREN538) + if (type & OREN538) printk("OREN538 "); - if (type & OREN36) + if (type & OREN36) printk("OREN36 "); - if (type & TOYOTA388) + if (type & TOYOTA388) printk("TOYOTA388 "); - if (type & TOYOTA794) + if (type & TOYOTA794) printk("TOYOTA794 "); - if (type & DIBCOM52) + if (type & DIBCOM52) printk("DIBCOM52 "); - if (type & ZARLINK456) + if (type & ZARLINK456) printk("ZARLINK456 "); - if (type & CHINA) + if (type & CHINA) printk("CHINA "); - if (type & F6MHZ) + if (type & F6MHZ) printk("F6MHZ "); - if (type & INPUT2) + if (type & INPUT2) printk("INPUT2 "); - if (type & SCODE) + if (type & SCODE) printk("SCODE "); - if (type & HAS_IF) + if (type & HAS_IF) printk("HAS_IF_%d ", int_freq); } -- cgit v1.2.3 From a16ae7d5bcc79fb4b882a611815fad05f818bfb4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 19:13:59 -0300 Subject: [media] sp8870: fix bad alignments As reported by cocinelle: drivers/media/dvb-frontends/sp8870.c:395:2-14: code aligned with following code on line 397 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/sp8870.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 2aa8ef76eba2..57dc2abaa87b 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -394,8 +394,7 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) if (ret < 0) return -EIO; - tmp = ret << 6; - + tmp = ret << 6; if (tmp >= 0x3FFF0) tmp = ~0; -- cgit v1.2.3 From cea130021448763b15f4b16af184bbab4be118fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 19:16:00 -0300 Subject: [media] drxd_hard: fix bad alignments As reported by cocinelle: drivers/media/dvb-frontends/drxd_hard.c:2632:3-51: code aligned with following code on line 2633 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxd_hard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index ae2276db77bc..961641b67728 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2628,10 +2628,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) break; /* Apply I2c address patch to B1 */ - if (!state->type_A && state->m_HiI2cPatch != NULL) + if (!state->type_A && state->m_HiI2cPatch != NULL) { status = WriteTable(state, state->m_HiI2cPatch); if (status < 0) break; + } if (state->type_A) { /* HI firmware patch for UIO readout, -- cgit v1.2.3 From 89fffac802c18caebdf4e91c0785b522c9f6399a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 19:11:45 -0300 Subject: [media] drxk_hard: fix bad alignments drivers/media/dvb-frontends/drxk_hard.c:2224:3-22: code aligned with following code on line 2227 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 88182c18e186..672195147d01 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -2220,12 +2220,13 @@ static int set_agc_rf(struct drxk_state *state, } /* Set TOP, only if IF-AGC is in AUTO mode */ - if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) + if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) { status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, p_agc_cfg->top); if (status < 0) goto error; + } /* Cut-Off current */ status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, -- cgit v1.2.3 From 5740f4e75f713015067e2667a52bd3b35ef91e07 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 03:31:07 -0300 Subject: [media] tw68: add original tw68 code This tw68 driver has been out-of-tree for many years on gitorious: https://gitorious.org/tw68/tw68-v2. This copies that code to the kernel as a record of that original code. Note that William Brack's email address in these sources is no longer valid and I have not been able to contact him. However, all the code is standard GPL. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-cards.c | 172 +++ drivers/media/pci/tw68/tw68-core.c | 1091 ++++++++++++++++ drivers/media/pci/tw68/tw68-i2c.c | 245 ++++ drivers/media/pci/tw68/tw68-reg.h | 195 +++ drivers/media/pci/tw68/tw68-risc.c | 268 ++++ drivers/media/pci/tw68/tw68-ts.c | 66 + drivers/media/pci/tw68/tw68-tvaudio.c | 80 ++ drivers/media/pci/tw68/tw68-vbi.c | 76 ++ drivers/media/pci/tw68/tw68-video.c | 2230 +++++++++++++++++++++++++++++++++ drivers/media/pci/tw68/tw68.h | 588 +++++++++ 10 files changed, 5011 insertions(+) create mode 100644 drivers/media/pci/tw68/tw68-cards.c create mode 100644 drivers/media/pci/tw68/tw68-core.c create mode 100644 drivers/media/pci/tw68/tw68-i2c.c create mode 100644 drivers/media/pci/tw68/tw68-reg.h create mode 100644 drivers/media/pci/tw68/tw68-risc.c create mode 100644 drivers/media/pci/tw68/tw68-ts.c create mode 100644 drivers/media/pci/tw68/tw68-tvaudio.c create mode 100644 drivers/media/pci/tw68/tw68-vbi.c create mode 100644 drivers/media/pci/tw68/tw68-video.c create mode 100644 drivers/media/pci/tw68/tw68.h diff --git a/drivers/media/pci/tw68/tw68-cards.c b/drivers/media/pci/tw68/tw68-cards.c new file mode 100644 index 000000000000..62aec4faa0d1 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-cards.c @@ -0,0 +1,172 @@ +/* + * device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 +#include /* must appear before i2c-algo-bit.h */ +#include + +#include +#include + +#include "tw68.h" +#include "tw68-reg.h" + +/* commly used strings */ +#if 0 +static char name_mute[] = "mute"; +static char name_radio[] = "Radio"; +static char name_tv[] = "Television"; +static char name_tv_mono[] = "TV (mono only)"; +static char name_svideo[] = "S-Video"; +static char name_comp[] = "Composite"; +#endif +static char name_comp1[] = "Composite1"; +static char name_comp2[] = "Composite2"; +static char name_comp3[] = "Composite3"; +static char name_comp4[] = "Composite4"; + +/* ------------------------------------------------------------------ */ +/* board config info */ + +/* If radio_type !=UNSET, radio_addr should be specified + */ + +struct tw68_board tw68_boards[] = { + [TW68_BOARD_UNKNOWN] = { + .name = "GENERIC", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + + .inputs = { + { + .name = name_comp1, + .vmux = 0, + }, { + .name = name_comp2, + .vmux = 1, + }, { + .name = name_comp3, + .vmux = 2, + }, { + .name = name_comp4, + .vmux = 3, + }, { /* Must have a NULL entry at end of list */ + .name = NULL, + .vmux = 0, + } + }, + }, +}; + +const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards); + +/* + * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps + * the PCI ID database up to date. Note that the entries must be + * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. + */ +struct pci_device_id tw68_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6800, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6801, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6804, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + /* end of list */ + } +}; +MODULE_DEVICE_TABLE(pci, tw68_pci_tbl); + +/* ------------------------------------------------------------ */ +/* stuff done before i2c enabled */ +int tw68_board_init1(struct tw68_dev *dev) +{ + /* Clear GPIO outputs */ + tw_writel(TW68_GPOE, 0); + /* Remainder of setup according to board ID */ + switch (dev->board) { + case TW68_BOARD_UNKNOWN: + printk(KERN_INFO "%s: Unable to determine board type, " + "using generic values\n", dev->name); + break; + } + dev->input = dev->hw_input = &card_in(dev,0); + return 0; +} + +int tw68_tuner_setup(struct tw68_dev *dev) +{ + return 0; +} + +/* stuff which needs working i2c */ +int tw68_board_init2(struct tw68_dev *dev) +{ + return 0; +} + + diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c new file mode 100644 index 000000000000..2c5d7a5f3f8e --- /dev/null +++ b/drivers/media/pci/tw68/tw68-core.c @@ -0,0 +1,1091 @@ +/* + * tw68-core.c + * Core functions for the Techwell 68xx driver + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "tw68.h" +#include "tw68-reg.h" + +MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); +MODULE_AUTHOR("William M. Brack "); +MODULE_LICENSE("GPL"); + +static unsigned int core_debug; +module_param(core_debug, int, 0644); +MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); + +static unsigned int gpio_tracking; +module_param(gpio_tracking, int, 0644); +MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); + +static unsigned int alsa = 1; +module_param(alsa, int, 0644); +MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); + +static unsigned int latency = UNSET; +module_param(latency, int, 0444); +MODULE_PARM_DESC(latency, "pci latency timer"); + +static unsigned int nocomb; +module_param(nocomb, int, 0644); +MODULE_PARM_DESC(nocomb, "disable comb filter"); + +static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); +module_param_array(tuner, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device number"); +MODULE_PARM_DESC(vbi_nr, "vbi device number"); +MODULE_PARM_DESC(radio_nr, "radio device number"); +MODULE_PARM_DESC(tuner, "tuner type"); +MODULE_PARM_DESC(card, "card type"); + +LIST_HEAD(tw68_devlist); +EXPORT_SYMBOL(tw68_devlist); +DEFINE_MUTEX(tw68_devlist_lock); +EXPORT_SYMBOL(tw68_devlist_lock); +static LIST_HEAD(mops_list); +static unsigned int tw68_devcount; /* curr tot num of devices present */ + +int (*tw68_dmasound_init)(struct tw68_dev *dev); +EXPORT_SYMBOL(tw68_dmasound_init); +int (*tw68_dmasound_exit)(struct tw68_dev *dev); +EXPORT_SYMBOL(tw68_dmasound_exit); + +#define dprintk(level, fmt, arg...) if (core_debug & (level)) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +/* ------------------------------------------------------------------ */ + +void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) +{ + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + BUG_ON(in_interrupt()); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + videobuf_waiton(&buf->vb, 0, 0); +#else + videobuf_waiton(q, &buf->vb, 0, 0); +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + videobuf_dma_unmap(q, dma); +#else + videobuf_dma_unmap(q->dev, dma); +#endif + videobuf_dma_free(dma); + /* if no risc area allocated, btcx_riscmem_free just returns */ + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +/* ------------------------------------------------------------------ */ +/* ------------- placeholders for later development ----------------- */ + +static int tw68_input_init1(struct tw68_dev *dev) +{ + return 0; +} + +static void tw68_input_fini(struct tw68_dev *dev) +{ + return; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) +{ + return; +} + +static void tw68_ir_stop(struct tw68_dev *dev) +{ + return; +} +#endif + +/* ------------------------------------------------------------------ */ +/* + * Buffer handling routines + * + * These routines are "generic", i.e. are intended to be used by more + * than one module, e.g. the video and the transport stream modules. + * To accomplish this generality, callbacks are used whenever some + * module-specific test or action is required. + */ + +/* resends a current buffer in queue after resume */ +int tw68_buffer_requeue(struct tw68_dev *dev, + struct tw68_dmaqueue *q) +{ + struct tw68_buf *buf, *prev; + + dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, + buf, buf->vb.i); + q->start_dma(dev, q, buf); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); + /* if nothing precedes this one */ + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + q->start_dma(dev, q, buf); + buf->activate(dev, buf, NULL); + dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", + __func__, buf, buf->vb.i); + + } else if (q->buf_compat(prev, buf) && + (prev->fmt == buf->fmt)) { + list_move_tail(&buf->vb.queue, &q->active); + buf->activate(dev, buf, NULL); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", + __func__, buf, buf->vb.i); + } else { + dprintk(DBG_BUFF, "%s: no action taken\n", __func__); + return 0; + } + prev = buf; + } +} + +/* nr of (tw68-)pages for the given buffer size */ +static int tw68_buffer_pages(int size) +{ + size = PAGE_ALIGN(size); + size += PAGE_SIZE; /* for non-page-aligned buffers */ + size /= 4096; + return size; +} + +/* calc max # of buffers from size (must not exceed the 4MB virtual + * address space per DMA channel) */ +int tw68_buffer_count(unsigned int size, unsigned int count) +{ + unsigned int maxcount; + + maxcount = 1024 / tw68_buffer_pages(size); + if (count > maxcount) + count = maxcount; + return count; +} + +/* + * tw68_wakeup + * + * Called when the driver completes filling a buffer, and tasks waiting + * for the data need to be awakened. + */ +void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) +{ + struct tw68_dev *dev = q->dev; + struct tw68_buf *buf; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (list_empty(&q->active)) { + dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", + __func__); + del_timer(&q->timeout); + return; + } + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + do_gettimeofday(&buf->vb.ts); + buf->vb.field_count = (*fc)++; + dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", + __func__, buf, buf->vb.i, *fc); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); +} + +/* + * tw68_buffer_queue + * + * Add specified buffer to specified queue + */ +void tw68_buffer_queue(struct tw68_dev *dev, + struct tw68_dmaqueue *q, + struct tw68_buf *buf) +{ + struct tw68_buf *prev; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + assert_spin_locked(&dev->slock); + dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); + + /* append a 'JUMP to stopper' to the buffer risc program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + + /* if this buffer is not "compatible" (in dimensions and format) + * with the currently active chain of buffers, we must change + * settings before filling it; if a previous buffer has already + * been determined to require changes, this buffer must follow + * it. To do this, we maintain a "queued" chain. If that + * chain exists, append this buffer to it */ + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", + __func__, buf, buf->vb.i); + + /* else if the 'active' chain doesn't yet exist we create it now */ + } else if (list_empty(&q->active)) { + dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", + __func__, buf, buf->vb.i); + list_add_tail(&buf->vb.queue, &q->active); + q->start_dma(dev, q, buf); /* 1st one - start dma */ + /* TODO - why have we removed buf->count and q->count? */ + buf->activate(dev, buf, NULL); + + /* else we would like to put this buffer on the tail of the + * active chain, provided it is "compatible". */ + } else { + /* "compatibility" depends upon the type of buffer */ + prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); + if (q->buf_compat(prev, buf)) { + /* If "compatible", append to active chain */ + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* the param 'prev' is only for debug printing */ + buf->activate(dev, buf, prev); + list_add_tail(&buf->vb.queue, &q->active); + dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", + __func__, buf, buf->vb.i); + } else { + /* If "incompatible", append to queued chain */ + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " + "to queued\n", __func__, buf, buf->vb.i); + } + } +} + +/* + * tw68_buffer_timeout + * + * This routine is set as the video_q.timeout.function + * + * Log the event, try to reset the h/w. + * Flag the current buffer as failed, try to start again with next buff + */ +void tw68_buffer_timeout(unsigned long data) +{ + struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; + struct tw68_dev *dev = q->dev; + struct tw68_buf *buf; + unsigned long flags; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + spin_lock_irqsave(&dev->slock, flags); + + /* flag all current active buffers as failed */ + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + dev->name, buf, buf->vb.i, + (unsigned long)buf->risc.dma); + } + tw68_buffer_requeue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +/* ------------------------------------------------------------------ */ +/* early init (no i2c, no irq) */ + +/* Called from tw68_hw_init1 and tw68_resume */ +static int tw68_hw_enable1(struct tw68_dev *dev) +{ + return 0; +} + +/* + * The device is given a "soft reset". According to the specifications, + * after this "all register content remain unchanged", so we also write + * to all specified registers manually as well (mostly to manufacturer's + * specified reset values) + */ +static int tw68_hw_init1(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + /* Assure all interrupts are disabled */ + tw_writel(TW68_INTMASK, 0); /* 020 */ + /* Clear any pending interrupts */ + tw_writel(TW68_INTSTAT, 0xffffffff); /* 01C */ + /* Stop risc processor, set default buffer level */ + tw_writel(TW68_DMAC, 0x1600); + + tw_writeb(TW68_ACNTL, 0x80); /* 218 soft reset */ + msleep(100); + + tw_writeb(TW68_INFORM, 0x40); /* 208 mux0, 27mhz xtal */ + tw_writeb(TW68_OPFORM, 0x04); /* 20C analog line-lock */ + tw_writeb(TW68_HSYNC, 0); /* 210 color-killer high sens */ + tw_writeb(TW68_ACNTL, 0x42); /* 218 int vref #2, chroma adc off */ + + tw_writeb(TW68_CROP_HI, 0x02); /* 21C Hactive m.s. bits */ + tw_writeb(TW68_VDELAY_LO, 0x12);/* 220 Mfg specified reset value */ + tw_writeb(TW68_VACTIVE_LO, 0xf0); + tw_writeb(TW68_HDELAY_LO, 0x0f); + tw_writeb(TW68_HACTIVE_LO, 0xd0); + + tw_writeb(TW68_CNTRL1, 0xcd); /* 230 Wide Chroma BPF B/W + * Secam reduction, Adap comb for + * NTSC, Op Mode 1 */ + + tw_writeb(TW68_VSCALE_LO, 0); /* 234 */ + tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */ + tw_writeb(TW68_HSCALE_LO, 0); /* 23c */ + tw_writeb(TW68_BRIGHT, 0); /* 240 */ + tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */ + tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */ + tw_writeb(TW68_SAT_U, 0x80); /* 24C */ + tw_writeb(TW68_SAT_V, 0x80); /* 250 */ + tw_writeb(TW68_HUE, 0x00); /* 254 */ + + /* TODO - Check that none of these are set by control defaults */ + tw_writeb(TW68_SHARP2, 0x53); /* 258 Mfg specified reset val */ + tw_writeb(TW68_VSHARP, 0x80); /* 25C Sharpness Coring val 8 */ + tw_writeb(TW68_CORING, 0x44); /* 260 CTI and Vert Peak coring */ + tw_writeb(TW68_CNTRL2, 0x00); /* 268 No power saving enabled */ + tw_writeb(TW68_SDT, 0x07); /* 270 Enable shadow reg, auto-det */ + tw_writeb(TW68_SDTR, 0x7f); /* 274 All stds recog, don't start */ + tw_writeb(TW68_CLMPG, 0x50); /* 280 Clamp end at 40 sys clocks */ + tw_writeb(TW68_IAGC, 0x22); /* 284 Mfg specified reset val */ + tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ + tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ + tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ +// tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ + tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ + tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ + tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ + /* Bit DETV of VCNTL1 helps sync multi cams/chip board */ + tw_writeb(TW68_VCNTL1, 0x04); /* 2A0 */ + tw_writeb(TW68_VCNTL2, 0); /* 2A4 */ + tw_writeb(TW68_CKILL, 0x68); /* 2A8 Mfg specified reset val */ + tw_writeb(TW68_COMB, 0x44); /* 2AC Mfg specified reset val */ + tw_writeb(TW68_LDLY, 0x30); /* 2B0 Max positive luma delay */ + tw_writeb(TW68_MISC1, 0x14); /* 2B4 Mfg specified reset val */ + tw_writeb(TW68_LOOP, 0xa5); /* 2B8 Mfg specified reset val */ + tw_writeb(TW68_MISC2, 0xe0); /* 2BC Enable colour killer */ + tw_writeb(TW68_MVSN, 0); /* 2C0 */ + tw_writeb(TW68_CLMD, 0x05); /* 2CC slice level auto, clamp med. */ + tw_writeb(TW68_IDCNTL, 0); /* 2D0 Writing zero to this register + * selects NTSC ID detection, + * but doesn't change the + * sensitivity (which has a reset + * value of 1E). Since we are + * not doing auto-detection, it + * has no real effect */ + tw_writeb(TW68_CLCNTL1, 0); /* 2D4 */ + tw_writel(TW68_VBIC, 0x03); /* 010 */ + tw_writel(TW68_CAP_CTL, 0x03); /* 040 Enable both even & odd flds */ + tw_writel(TW68_DMAC, 0x2000); /* patch set had 0x2080 */ + tw_writel(TW68_TESTREG, 0); /* 02C */ + + /* + * Some common boards, especially inexpensive single-chip models, + * use the GPIO bits 0-3 to control an on-board video-output mux. + * For these boards, we need to set up the GPIO register into + * "normal" mode, set bits 0-3 as output, and then set those bits + * zero. + * + * Eventually, it would be nice if we could identify these boards + * uniquely, and only do this initialisation if the board has been + * identify. For the moment, however, it shouldn't hurt anything + * to do these steps. + */ + tw_writel(TW68_GPIOC, 0); /* Set the GPIO to "normal", no ints */ + tw_writel(TW68_GPOE, 0x0f); /* Set bits 0-3 to "output" */ + tw_writel(TW68_GPDATA, 0); /* Set all bits to low state */ + + /* Initialize the device control structures */ + mutex_init(&dev->lock); + spin_lock_init(&dev->slock); + + /* Initialize any subsystems */ + tw68_video_init1(dev); + tw68_vbi_init1(dev); + if (card_has_mpeg(dev)) + tw68_ts_init1(dev); + tw68_input_init1(dev); + + /* Do any other h/w early initialisation at this point */ + tw68_hw_enable1(dev); + + return 0; +} + +/* late init (with i2c + irq) */ +static int tw68_hw_enable2(struct tw68_dev *dev) +{ + + dprintk(DBG_FLOW, "%s: called\n", __func__); +#ifdef TW68_TESTING + dev->pci_irqmask |= TW68_I2C_INTS; +#endif + tw_setl(TW68_INTMASK, dev->pci_irqmask); + return 0; +} + +static int tw68_hw_init2(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + tw68_video_init2(dev); /* initialise video function first */ + tw68_tvaudio_init2(dev);/* audio next */ + + /* all other board-related things, incl. enabling interrupts */ + tw68_hw_enable2(dev); + return 0; +} + +/* shutdown */ +static int tw68_hwfini(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (card_has_mpeg(dev)) + tw68_ts_fini(dev); + tw68_input_fini(dev); + tw68_vbi_fini(dev); + tw68_tvaudio_fini(dev); + return 0; +} + +static void __devinit must_configure_manually(void) +{ + unsigned int i, p; + + printk(KERN_WARNING + "tw68: \n" + "tw68: Congratulations! Your TV card vendor saved a few\n" + "tw68: cents for a eeprom, thus your pci board has no\n" + "tw68: subsystem ID and I can't identify it automatically\n" + "tw68: \n" + "tw68: I feel better now. Ok, here is the good news:\n" + "tw68: You can use the card= insmod option to specify\n" + "tw68: which board you have. The list:\n"); + for (i = 0; i < tw68_bcount; i++) { + printk(KERN_WARNING "tw68: card=%d -> %-40.40s", + i, tw68_boards[i].name); + for (p = 0; tw68_pci_tbl[p].driver_data; p++) { + if (tw68_pci_tbl[p].driver_data != i) + continue; + printk(" %04x:%04x", + tw68_pci_tbl[p].subvendor, + tw68_pci_tbl[p].subdevice); + } + printk("\n"); + } +} + + +static irqreturn_t tw68_irq(int irq, void *dev_id) +{ + struct tw68_dev *dev = dev_id; + u32 status, orig; + int loop; + + status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; + /* Check if anything to do */ + if (0 == status) + return IRQ_RETVAL(0); /* Nope - return */ + for (loop = 0; loop < 10; loop++) { + if (status & dev->board_virqmask) /* video interrupt */ + tw68_irq_video_done(dev, status); +#ifdef TW68_TESTING + if (status & TW68_I2C_INTS) + tw68_irq_i2c(dev, status); +#endif + status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; + if (0 == status) + goto out; + } + dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" + " (orig 0x%08x, cur 0x%08x)", + dev->name, orig, tw_readl(TW68_INTSTAT)); + dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " + "0x%08x ****\n", dev->name, + dev->pci_irqmask, dev->board_virqmask); + tw_clearl(TW68_INTMASK, dev->pci_irqmask); +out: + return IRQ_RETVAL(1); +} + +int tw68_set_dmabits(struct tw68_dev *dev) +{ + return 0; +} + +static struct video_device *vdev_init(struct tw68_dev *dev, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->parent = &dev->pci->dev; + vfd->release = video_device_release; + /* vfd->debug = tw_video_debug; */ + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + dev->name, type, tw68_boards[dev->board].name); + return vfd; +} + +static void tw68_unregister_video(struct tw68_dev *dev) +{ + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (dev->video_dev) { + if (-1 != dev->video_dev->minor) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + } + if (dev->vbi_dev) { + if (-1 != dev->vbi_dev->minor) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->radio_dev) { + if (-1 != dev->radio_dev->minor) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } +} + +static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, + struct tw68_dev *dev) +{ + int err; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (NULL != dev->mops) + return; + if (tw68_boards[dev->board].mpeg != ops->type) + return; + err = ops->init(dev); + if (0 != err) + return; + dev->mops = ops; +} + +static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, + struct tw68_dev *dev) +{ + + if (NULL == dev->mops) + return; + if (dev->mops != ops) + return; + dev->mops->fini(dev); + dev->mops = NULL; +} + +static int __devinit tw68_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct tw68_dev *dev; + struct tw68_mpeg_ops *mops; + int err; + + if (tw68_devcount == TW68_MAXBOARDS) + return -ENOMEM; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err) + goto fail0; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail1; + } + + dev->nr = tw68_devcount; + sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); + + /* pci quirks */ + if (pci_pci_problems) { + if (pci_pci_problems & PCIPCI_TRITON) + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", + dev->name); + if (pci_pci_problems & PCIPCI_NATOMA) + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", + dev->name); + if (pci_pci_problems & PCIPCI_VIAETBF) + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", + dev->name); + if (pci_pci_problems & PCIPCI_VSFX) + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", + dev->name); +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " + "-- latency fixup\n", dev->name); + latency = 0x0A; + } +#endif + } + if (UNSET != latency) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + dev->name, latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, + (unsigned long long)pci_resource_start(pci_dev, 0)); + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { + printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail1; + } + + switch (pci_id->device) { + case PCI_DEVICE_ID_6800: /* TW6800 */ + dev->vdecoder = TW6800; + dev->board_virqmask = TW68_VID_INTS; + break; + case PCI_DEVICE_ID_6801: /* Video decoder for TW6802 */ + dev->vdecoder = TW6801; + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ + dev->vdecoder = TW6804; + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + default: + dev->vdecoder = TWXXXX; /* To be announced */ + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + } + /* board config */ + dev->board = pci_id->driver_data; + if (card[dev->nr] >= 0 && + card[dev->nr] < tw68_bcount) + dev->board = card[dev->nr]; + if (TW68_BOARD_NOAUTO == dev->board) { + must_configure_manually(); + dev->board = TW68_BOARD_UNKNOWN; + } + dev->autodetected = card[dev->nr] != dev->board; + dev->tuner_type = tw68_boards[dev->board].tuner_type; + dev->tuner_addr = tw68_boards[dev->board].tuner_addr; + dev->radio_type = tw68_boards[dev->board].radio_type; + dev->radio_addr = tw68_boards[dev->board].radio_addr; + dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; + if (UNSET != tuner[dev->nr]) + dev->tuner_type = tuner[dev->nr]; + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, pci_dev->subsystem_vendor, + pci_dev->subsystem_device, tw68_boards[dev->board].name, + dev->board, dev->autodetected ? + "autodetected" : "insmod option"); + + /* get mmio */ + if (!request_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0), + dev->name)) { + err = -EBUSY; + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, + (unsigned long long)pci_resource_start(pci_dev, 0)); + goto fail1; + } + dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + dev->bmmio = (__u8 __iomem *)dev->lmmio; + if (NULL == dev->lmmio) { + err = -EIO; + printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + dev->name); + goto fail2; + } + /* initialize hardware #1 */ + /* First, take care of anything unique to a particular card */ + tw68_board_init1(dev); + /* Then do any initialisation wanted before interrupts are on */ + tw68_hw_init1(dev); + + /* get irq */ + err = request_irq(pci_dev->irq, tw68_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail3; + } + +#ifdef TW68_TESTING + dev->pci_irqmask |= TW68_SBDONE; + tw_setl(TW68_INTMASK, dev->pci_irqmask); + printk(KERN_INFO "Calling tw68_i2c_register\n"); + /* Register the i2c bus */ + tw68_i2c_register(dev); +#endif + + /* + * Now do remainder of initialisation, first for + * things unique for this card, then for general board + */ + tw68_board_init2(dev); + + tw68_hw_init2(dev); + +#if 0 + /* load i2c helpers */ + if (card_is_empress(dev)) { + struct v4l2_subdev *sd = + v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", + "saa6752hs", 0x20); + + if (sd) + sd->grp_id = GRP_EMPRESS; + } + + request_submodules(dev); +#endif + + v4l2_prio_init(&dev->prio); + + mutex_lock(&tw68_devlist_lock); + list_for_each_entry(mops, &mops_list, next) + mpeg_ops_attach(mops, dev); + list_add_tail(&dev->devlist, &tw68_devlist); + mutex_unlock(&tw68_devlist_lock); + + /* check for signal */ + tw68_irq_video_signalchange(dev); + +#if 0 + if (TUNER_ABSENT != dev->tuner_type) + tw_call_all(dev, core, s_standby, 0); +#endif + + dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); + err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device video%d [v4l2]\n", + dev->name, dev->video_dev->num); + + dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); + + err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register vbi device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device vbi%d\n", + dev->name, dev->vbi_dev->num); + + if (card_has_radio(dev)) { + dev->radio_dev = vdev_init(dev, &tw68_radio_template, + "radio"); + err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->nr]); + if (err < 0) { + /* TODO - need to unregister vbi? */ + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device radio%d\n", + dev->name, dev->radio_dev->num); + } + + /* everything worked */ + tw68_devcount++; + + if (tw68_dmasound_init && !dev->dmasound.priv_data) + tw68_dmasound_init(dev); + + return 0; + + fail4: + tw68_unregister_video(dev); +#ifdef TW68_TESTING + tw68_i2c_unregister(dev); +#endif + free_irq(pci_dev->irq, dev); + fail3: + tw68_hwfini(dev); + iounmap(dev->lmmio); + fail2: + release_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + fail1: + v4l2_device_unregister(&dev->v4l2_dev); + fail0: + kfree(dev); + return err; +} + +static void __devexit tw68_finidev(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = + container_of(v4l2_dev, struct tw68_dev, v4l2_dev); + struct tw68_mpeg_ops *mops; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + /* Release DMA sound modules if present */ + if (tw68_dmasound_exit && dev->dmasound.priv_data) + tw68_dmasound_exit(dev); + + /* shutdown subsystems */ + tw68_hwfini(dev); + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + tw_writel(TW68_INTMASK, 0); + + /* unregister */ + mutex_lock(&tw68_devlist_lock); + list_del(&dev->devlist); + list_for_each_entry(mops, &mops_list, next) + mpeg_ops_detach(mops, dev); + mutex_unlock(&tw68_devlist_lock); + tw68_devcount--; + +#ifdef TW68_TESTING + tw68_i2c_unregister(dev); +#endif + tw68_unregister_video(dev); + + + /* the DMA sound modules should be unloaded before reaching + this, but just in case they are still present... */ + if (dev->dmasound.priv_data != NULL) { + free_irq(pci_dev->irq, &dev->dmasound); + dev->dmasound.priv_data = NULL; + } + + + /* release resources */ + free_irq(pci_dev->irq, dev); + iounmap(dev->lmmio); + release_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + + v4l2_device_unregister(&dev->v4l2_dev); + + /* free memory */ + kfree(dev); +} + +#ifdef CONFIG_PM + +static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = container_of(v4l2_dev, + struct tw68_dev, v4l2_dev); + + dprintk(DBG_FLOW, "%s: called\n", __func__); + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + dev->pci_irqmask &= ~TW68_VID_INTS; + tw_writel(TW68_INTMASK, 0); + + dev->insuspend = 1; + synchronize_irq(pci_dev->irq); + + /* Disable timeout timers - if we have active buffers, we will + fill them on resume*/ + + del_timer(&dev->video_q.timeout); + del_timer(&dev->vbi_q.timeout); + del_timer(&dev->ts_q.timeout); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (dev->remote) + tw68_ir_stop(dev); +#endif + + pci_save_state(pci_dev); + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + + return 0; +} + +static int tw68_resume(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = container_of(v4l2_dev, + struct tw68_dev, v4l2_dev); + unsigned long flags; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + pci_set_power_state(pci_dev, PCI_D0); + pci_restore_state(pci_dev); + + /* Do things that are done in tw68_initdev , + except of initializing memory structures.*/ + + tw68_board_init1(dev); + + /* tw68_hw_init1 */ + if (tw68_boards[dev->board].video_out) + tw68_videoport_init(dev); + if (card_has_mpeg(dev)) + tw68_ts_init_hw(dev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (dev->remote) + tw68_ir_start(dev, dev->remote); +#endif + tw68_hw_enable1(dev); + + msleep(100); + + tw68_board_init2(dev); + + /*tw68_hw_init2*/ + tw68_set_tvnorm_hw(dev); + tw68_tvaudio_setmute(dev); +/* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ + tw68_tvaudio_init(dev); + tw68_irq_video_signalchange(dev); + + /*resume unfinished buffer(s)*/ + spin_lock_irqsave(&dev->slock, flags); + tw68_buffer_requeue(dev, &dev->video_q); + tw68_buffer_requeue(dev, &dev->vbi_q); + tw68_buffer_requeue(dev, &dev->ts_q); + + /* FIXME: Disable DMA audio sound - temporary till proper support + is implemented*/ + + dev->dmasound.dma_running = 0; + + /* start DMA now*/ + dev->insuspend = 0; + smp_wmb(); + tw68_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} +#endif + +/* ----------------------------------------------------------- */ + +static struct pci_driver tw68_pci_driver = { + .name = "tw68", + .id_table = tw68_pci_tbl, + .probe = tw68_initdev, + .remove = __devexit_p(tw68_finidev), +#ifdef CONFIG_PM + .suspend = tw68_suspend, + .resume = tw68_resume +#endif +}; + +static int tw68_init(void) +{ + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + INIT_LIST_HEAD(&tw68_devlist); + printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", + (TW68_VERSION_CODE >> 16) & 0xff, + (TW68_VERSION_CODE >> 8) & 0xff, + TW68_VERSION_CODE & 0xff); +#if 0 + printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&tw68_pci_driver); +} + +static void module_cleanup(void) +{ + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + pci_unregister_driver(&tw68_pci_driver); +} + +module_init(tw68_init); +module_exit(module_cleanup); diff --git a/drivers/media/pci/tw68/tw68-i2c.c b/drivers/media/pci/tw68/tw68-i2c.c new file mode 100644 index 000000000000..38659d0b1e18 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-i2c.c @@ -0,0 +1,245 @@ +/* + * tw68 code to handle the i2c interface. + * + * Much of this code is derived from the bt87x driver. The original + * work was by Gerd Knorr; more recently the code was enhanced by Mauro + * Carvalho Chehab. Their work is gratefully acknowledged. Full credit + * goes to them - any problems within this code are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 +#include +#include +#include +#include + +#include "tw68.h" +#include +#include + +/*----------------------------------------------------------------*/ + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +#if 0 +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); +#endif + +#define d1printk if (1 == i2c_debug) printk + +#define I2C_CLOCK 0xa6 /* 99.4 kHz */ + +/*----------------------------------------------------------------------*/ +/* Although the TW68xx i2c controller has a "hardware" mode, where all of + * the low-level i2c/smbbus is handled by the chip, it appears that mode + * is not suitable for linux i2c handling routines because extended "bursts" + * of data (sequences of bytes without intervening START/STOP bits) are + * not possible. Instead, we put the chip into "software" mode, and handle + * the i2c bus at a low level. To accomplish this, we use the routines + * from the i2c modules. + * + * Because the particular boards which I had for testing did not have any + * devices attached to the i2c bus, I have been unable to test these + * routines. + */ + +/*----------------------------------------------------------------------*/ +/* I2C functions - "bit-banging" adapter (software i2c) */ + +/* tw68_bit_setcl + * Handles "toggling" the i2c clock bit + */ +static void tw68_bit_setscl(void *data, int state) +{ + struct tw68_dev *dev = data; + + tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B); +} + +/* tw68_bit_setsda + * Handles "toggling" the i2c data bit + */ +static void tw68_bit_setsda(void *data, int state) +{ + struct tw68_dev *dev = data; + + tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B); +} + +/* tw68_bit_getscl + * + * Returns the current state of the clock bit + */ +static int tw68_bit_getscl(void *data) +{ + struct tw68_dev *dev = data; + + return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0; +} + +/* tw68_bit_getsda + * + * Returns the current state of the data bit + */ +static int tw68_bit_getsda(void *data) +{ + struct tw68_dev *dev = data; + + return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0; +} + +static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = { + .setsda = tw68_bit_setsda, + .setscl = tw68_bit_setscl, + .getsda = tw68_bit_getsda, + .getscl = tw68_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +static struct i2c_client tw68_client_template = { + .name = "tw68 internal", +}; + +/*----------------------------------------------------------------*/ + +static int attach_inform(struct i2c_client *client) +{ +/* struct tw68_dev *dev = client->adapter->algo_data; */ + + d1printk("%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, client->name); + + switch (client->addr) { + /* No info yet on what addresses to expect */ + } + + return 0; +} + +static struct i2c_adapter tw68_adap_sw_template = { + .owner = THIS_MODULE, + .name = "tw68_sw", + .client_register = attach_inform, +}; + +static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata, + int len) +{ + unsigned char buf; + int i, err; + + dev->i2c_client.addr = 0xa0 >> 1; + buf = 256 - len; + + err = i2c_master_send(&dev->i2c_client, &buf, 1); + if (1 != err) { + printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n", + dev->name, err); + return -1; + } + err = i2c_master_recv(&dev->i2c_client, eedata, len); + if (len != err) { + printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", + dev->name, err); + return -1; + } + + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + printk(KERN_INFO "%s: i2c eeprom %02x:", + dev->name, i); + printk(KERN_INFO " %02x", eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + return 0; +} + +#if 0 +static char *i2c_devs[128] = { + [0xa0 >> 1] = "eeprom", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + c->addr = i; + rc = i2c_master_recv(c, &buf, 1); + if (rc < 0) + continue; + printk(KERN_INFO "%s: i2c scan: found device " + "@ 0x%x [%s]\n", name, i << 1, + i2c_devs[i] ? i2c_devs[i] : "???"); + } +} +#endif + +int __devinit tw68_i2c_register(struct tw68_dev *dev) +{ + int rc; + +printk(KERN_DEBUG "%s: Registering i2c module\n", __func__); + tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */ + + memcpy(&dev->i2c_client, &tw68_client_template, + sizeof(tw68_client_template)); + + memcpy(&dev->i2c_adap, &tw68_adap_sw_template, + sizeof(tw68_adap_sw_template)); + dev->i2c_adap.algo_data = &dev->i2c_algo; + dev->i2c_adap.dev.parent = &dev->pci->dev; + + memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template, + sizeof(tw68_i2c_algo_bit_template)); + dev->i2c_algo.data = dev; + /* TODO - may want to set better name (see bttv code) */ + + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + dev->i2c_client.adapter = &dev->i2c_adap; + + /* Assure chip is in "software" mode */ + tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK); + tw68_bit_setscl(dev, 1); + tw68_bit_setsda(dev, 1); + + rc = i2c_bit_add_bus(&dev->i2c_adap); + + tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); +#if 0 + if (i2c_scan) + do_i2c_scan(dev->name, &dev->i2c_client); +#endif + + return rc; +} + +int tw68_i2c_unregister(struct tw68_dev *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h new file mode 100644 index 000000000000..314bc43cd9d3 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-reg.h @@ -0,0 +1,195 @@ +/* + * tw68-reg.h - TW68xx register offsets + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) William M. Brack + * + * 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 _TW68_REG_H_ +#define _TW68_REG_H_ + +/* ---------------------------------------------------------------------- */ +#define TW68_DMAC 0x000 +#define TW68_DMAP_SA 0x004 +#define TW68_DMAP_EXE 0x008 +#define TW68_DMAP_PP 0x00c +#define TW68_VBIC 0x010 +#define TW68_SBUSC 0x014 +#define TW68_SBUSSD 0x018 +#define TW68_INTSTAT 0x01C +#define TW68_INTMASK 0x020 +#define TW68_GPIOC 0x024 +#define TW68_GPOE 0x028 +#define TW68_TESTREG 0x02C +#define TW68_SBUSRD 0x030 +#define TW68_SBUS_TRIG 0x034 +#define TW68_CAP_CTL 0x040 +#define TW68_SUBSYS 0x054 +#define TW68_I2C_RST 0x064 +#define TW68_VBIINST 0x06C +/* define bits in FIFO and DMAP Control reg */ +#define TW68_DMAP_EN (1 << 0) +#define TW68_FIFO_EN (1 << 1) +/* define the Interrupt Status Register bits */ +#define TW68_SBDONE (1 << 0) +#define TW68_DMAPI (1 << 1) +#define TW68_GPINT (1 << 2) +#define TW68_FFOF (1 << 3) +#define TW68_FDMIS (1 << 4) +#define TW68_DMAPERR (1 << 5) +#define TW68_PABORT (1 << 6) +#define TW68_SBDONE2 (1 << 12) +#define TW68_SBERR2 (1 << 13) +#define TW68_PPERR (1 << 14) +#define TW68_FFERR (1 << 15) +#define TW68_DET50 (1 << 16) +#define TW68_FLOCK (1 << 17) +#define TW68_CCVALID (1 << 18) +#define TW68_VLOCK (1 << 19) +#define TW68_FIELD (1 << 20) +#define TW68_SLOCK (1 << 21) +#define TW68_HLOCK (1 << 22) +#define TW68_VDLOSS (1 << 23) +#define TW68_SBERR (1 << 24) +/* define the i2c control register bits */ +#define TW68_SBMODE (0) +#define TW68_WREN (1) +#define TW68_SSCLK (6) +#define TW68_SSDAT (7) +#define TW68_SBCLK (8) +#define TW68_WDLEN (16) +#define TW68_RDLEN (20) +#define TW68_SBRW (24) +#define TW68_SBDEV (25) + +#define TW68_SBMODE_B (1 << TW68_SBMODE) +#define TW68_WREN_B (1 << TW68_WREN) +#define TW68_SSCLK_B (1 << TW68_SSCLK) +#define TW68_SSDAT_B (1 << TW68_SSDAT) +#define TW68_SBRW_B (1 << TW68_SBRW) + +#define TW68_GPDATA 0x100 +#define TW68_STATUS1 0x204 +#define TW68_INFORM 0x208 +#define TW68_OPFORM 0x20C +#define TW68_HSYNC 0x210 +#define TW68_ACNTL 0x218 +#define TW68_CROP_HI 0x21C +#define TW68_VDELAY_LO 0x220 +#define TW68_VACTIVE_LO 0x224 +#define TW68_HDELAY_LO 0x228 +#define TW68_HACTIVE_LO 0x22C +#define TW68_CNTRL1 0x230 +#define TW68_VSCALE_LO 0x234 +#define TW68_SCALE_HI 0x238 +#define TW68_HSCALE_LO 0x23C +#define TW68_BRIGHT 0x240 +#define TW68_CONTRAST 0x244 +#define TW68_SHARPNESS 0x248 +#define TW68_SAT_U 0x24C +#define TW68_SAT_V 0x250 +#define TW68_HUE 0x254 +#define TW68_SHARP2 0x258 +#define TW68_VSHARP 0x25C +#define TW68_CORING 0x260 +#define TW68_VBICNTL 0x264 +#define TW68_CNTRL2 0x268 +#define TW68_CC_DATA 0x26C +#define TW68_SDT 0x270 +#define TW68_SDTR 0x274 +#define TW68_RESERV2 0x278 +#define TW68_RESERV3 0x27C +#define TW68_CLMPG 0x280 +#define TW68_IAGC 0x284 +#define TW68_AGCGAIN 0x288 +#define TW68_PEAKWT 0x28C +#define TW68_CLMPL 0x290 +#define TW68_SYNCT 0x294 +#define TW68_MISSCNT 0x298 +#define TW68_PCLAMP 0x29C +#define TW68_VCNTL1 0x2A0 +#define TW68_VCNTL2 0x2A4 +#define TW68_CKILL 0x2A8 +#define TW68_COMB 0x2AC +#define TW68_LDLY 0x2B0 +#define TW68_MISC1 0x2B4 +#define TW68_LOOP 0x2B8 +#define TW68_MISC2 0x2BC +#define TW68_MVSN 0x2C0 +#define TW68_STATUS2 0x2C4 +#define TW68_HFREF 0x2C8 +#define TW68_CLMD 0x2CC +#define TW68_IDCNTL 0x2D0 +#define TW68_CLCNTL1 0x2D4 + +/* Audio */ +#define TW68_ACKI1 0x300 +#define TW68_ACKI2 0x304 +#define TW68_ACKI3 0x308 +#define TW68_ACKN1 0x30C +#define TW68_ACKN2 0x310 +#define TW68_ACKN3 0x314 +#define TW68_SDIV 0x318 +#define TW68_LRDIV 0x31C +#define TW68_ACCNTL 0x320 + +#define TW68_VSCTL 0x3B8 +#define TW68_CHROMAGVAL 0x3BC + +#define TW68_F2CROP_HI 0x3DC +#define TW68_F2VDELAY_LO 0x3E0 +#define TW68_F2VACTIVE_LO 0x3E4 +#define TW68_F2HDELAY_LO 0x3E8 +#define TW68_F2HACTIVE_LO 0x3EC +#define TW68_F2CNT 0x3F0 +#define TW68_F2VSCALE_LO 0x3F4 +#define TW68_F2SCALE_HI 0x3F8 +#define TW68_F2HSCALE_LO 0x3FC + +#define RISC_INT_BIT 0x08000000 +#define RISC_SYNCO 0xC0000000 +#define RISC_SYNCE 0xD0000000 +#define RISC_JUMP 0xB0000000 +#define RISC_LINESTART 0x90000000 +#define RISC_INLINE 0xA0000000 + +#define VideoFormatNTSC 0 +#define VideoFormatNTSCJapan 0 +#define VideoFormatPALBDGHI 1 +#define VideoFormatSECAM 2 +#define VideoFormatNTSC443 3 +#define VideoFormatPALM 4 +#define VideoFormatPALN 5 +#define VideoFormatPALNC 5 +#define VideoFormatPAL60 6 +#define VideoFormatAuto 7 + +#define ColorFormatRGB32 0x00 +#define ColorFormatRGB24 0x10 +#define ColorFormatRGB16 0x20 +#define ColorFormatRGB15 0x30 +#define ColorFormatYUY2 0x40 +#define ColorFormatBSWAP 0x04 +#define ColorFormatWSWAP 0x08 +#define ColorFormatGamma 0x80 +#endif diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c new file mode 100644 index 000000000000..66273bbd51c5 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -0,0 +1,268 @@ +/* + * tw68_risc.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 "tw68.h" + +#define NO_SYNC_LINE (-1U) + +/** + * @rp pointer to current risc program position + * @sglist pointer to "scatter-gather list" of buffer pointers + * @offset offset to target memory buffer + * @sync_line 0 -> no sync, 1 -> odd sync, 2 -> even sync + * @bpl number of bytes per scan line + * @padding number of bytes of padding to add + * @lines number of lines in field + * @lpi lines per IRQ, or 0 to not generate irqs + * Note: IRQ to be generated _after_ lpi lines are transferred + */ +static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines, unsigned int lpi) +{ + struct scatterlist *sg; + unsigned int line, todo, done; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) { + if (sync_line == 1) + *(rp++) = cpu_to_le32(RISC_SYNCO); + else + *(rp++) = cpu_to_le32(RISC_SYNCE); + *(rp++) = 0; + } + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + /* calculate next starting position */ + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg) - offset) { + /* fits into current chunk */ + *(rp++) = cpu_to_le32(RISC_LINESTART | + /* (offset<<12) |*/ bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + offset += bpl; + } else { + /* + * scanline needs to be split. Put the start in + * whatever memory remains using RISC_LINESTART, + * then the remainder into following addresses + * given by the scatter-gather list. + */ + todo = bpl; /* one full line to be done */ + /* first fragment */ + done = (sg_dma_len(sg) - offset); + *(rp++) = cpu_to_le32(RISC_LINESTART | + (7 << 24) | + done); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + todo -= done; + sg++; + /* succeeding fragments have no offset */ + while (todo > sg_dma_len(sg)) { + *(rp++) = cpu_to_le32(RISC_INLINE | + (done << 12) | + sg_dma_len(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + todo -= sg_dma_len(sg); + sg++; + done += sg_dma_len(sg); + } + if (todo) { + /* final chunk - offset 0, count 'todo' */ + *(rp++) = cpu_to_le32(RISC_INLINE | + (done << 12) | + todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + } + offset = todo; + } + offset += padding; + /* If this line needs an interrupt, put it in */ + if (lpi && line > 0 && !(line % lpi)) + *(rp-2) |= RISC_INT_BIT; + } + + return rp; +} + +/** + * tw68_risc_buffer + * + * This routine is called by tw68-video. It allocates + * memory for the dma controller "program" and then fills in that + * memory with the appropriate "instructions". + * + * @pci_dev structure with info about the pci + * slot which our device is in. + * @risc structure with info about the memory + * used for our controller program. + * @sglist scatter-gather list entry + * @top_offset offset within the risc program area for the + * first odd frame line + * @bottom_offset offset within the risc program area for the + * first even frame line + * @bpl number of data bytes per scan line + * @padding number of extra bytes to add at end of line + * @lines number of scan lines + */ +int tw68_risc_buffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, + unsigned int bottom_offset, + unsigned int bpl, + unsigned int padding, + unsigned int lines) +{ + u32 instructions, fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + /* + * estimate risc mem: worst case is one write per page border + + * one write per scan line + syncs + jump (all 2 dwords). + * Padding can cause next bpl to start close to a page border. + * First DMA region may be smaller than PAGE_SIZE + */ + instructions = fields * (1 + (((bpl + padding) * lines) / + PAGE_SIZE) + lines) + 2; + rc = btcx_riscmem_alloc(pci, risc, instructions * 8); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) /* generates SYNCO */ + rp = tw68_risc_field(rp, sglist, top_offset, 1, + bpl, padding, lines, 0); + if (UNSET != bottom_offset) /* generates SYNCE */ + rp = tw68_risc_field(rp, sglist, bottom_offset, 2, + bpl, padding, lines, 0); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + /* assure risc buffer hasn't overflowed */ + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +#if 0 +/* ------------------------------------------------------------------ */ +/* debug helper code */ + +static void tw68_risc_decode(u32 risc, u32 addr) +{ +#define RISC_OP(reg) (((reg) >> 28) & 7) + static struct instr_details { + char *name; + u8 has_data_type; + u8 has_byte_info; + u8 has_addr; + } instr[8] = { + [RISC_OP(RISC_SYNCO)] = {"syncOdd", 0, 0, 0}, + [RISC_OP(RISC_SYNCE)] = {"syncEven", 0, 0, 0}, + [RISC_OP(RISC_JUMP)] = {"jump", 0, 0, 1}, + [RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1}, + [RISC_OP(RISC_INLINE)] = {"inline", 1, 1, 1}, + }; + u32 p; + + p = RISC_OP(risc); + if (!(risc & 0x80000000) || !instr[p].name) { + printk(KERN_DEBUG "0x%08x [ INVALID ]\n", risc); + return; + } + printk(KERN_DEBUG "0x%08x %-9s IRQ=%d", + risc, instr[p].name, (risc >> 27) & 1); + if (instr[p].has_data_type) + printk(KERN_DEBUG " Type=%d", (risc >> 24) & 7); + if (instr[p].has_byte_info) + printk(KERN_DEBUG " Start=0x%03x Count=%03u", + (risc >> 12) & 0xfff, risc & 0xfff); + if (instr[p].has_addr) + printk(KERN_DEBUG " StartAddr=0x%08x", addr); + printk(KERN_DEBUG "\n"); +} + +void tw68_risc_program_dump(struct tw68_core *core, + struct btcx_riscmem *risc) +{ + __le32 *addr; + + printk(KERN_DEBUG "%s: risc_program_dump: risc=%p, " + "risc->cpu=0x%p, risc->jmp=0x%p\n", + core->name, risc, risc->cpu, risc->jmp); + for (addr = risc->cpu; addr <= risc->jmp; addr += 2) + tw68_risc_decode(*addr, *(addr+1)); +} +EXPORT_SYMBOL_GPL(tw68_risc_program_dump); +#endif + +/* + * tw68_risc_stopper + * Normally, the risc code generated for a buffer ends with a + * JUMP instruction to direct the DMAP processor to the code for + * the next buffer. However, when there is no additional buffer + * currently available, the code instead jumps to this routine. + * + * My first try for a "stopper" program was just a simple + * "jump to self" instruction. Unfortunately, this caused the + * video FIFO to overflow. My next attempt was to just disable + * the DMAP processor. Unfortunately, this caused the video + * decoder to lose its synchronization. The solution to this was to + * add a "Sync-Odd" instruction, which "eats" all the video data + * until the start of the next odd field. + */ +int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc) +{ + __le32 *rp; + int rc; + + rc = btcx_riscmem_alloc(pci, risc, 8*4); + if (rc < 0) + return rc; + + /* write risc inststructions */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(RISC_SYNCO); + *(rp++) = 0; + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + risc->jmp = risc->cpu; + return 0; +} diff --git a/drivers/media/pci/tw68/tw68-ts.c b/drivers/media/pci/tw68/tw68-ts.c new file mode 100644 index 000000000000..dacd6e621bae --- /dev/null +++ b/drivers/media/pci/tw68/tw68-ts.c @@ -0,0 +1,66 @@ +/* + * tw68_ts.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 "tw68.h" + +int tw68_ts_init1(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_ts_ini(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_ts_fini(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status) +{ + return; +} + +int tw68_ts_register(struct tw68_mpeg_ops *ops) +{ + return 0; +} + +void tw68_ts_unregister(struct tw68_mpeg_ops *ops) +{ + return; +} + +int tw68_ts_init_hw(struct tw68_dev *dev) +{ + return 0; +} + + diff --git a/drivers/media/pci/tw68/tw68-tvaudio.c b/drivers/media/pci/tw68/tw68-tvaudio.c new file mode 100644 index 000000000000..656d462196f4 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-tvaudio.c @@ -0,0 +1,80 @@ +/* + * tw68_controls.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 "tw68.h" + +int tw68_tvaudio_rx2mode(u32 rx) +{ + return 0; +} + +void tw68_tvaudio_setmute(struct tw68_dev *dev) +{ + return; +} + +void tw68_tvaudio_setinput(struct tw68_dev *dev, struct tw68_input *in) +{ + return; +} + +void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level) +{ + return; +} + +int tw68_tvaudio_getstereo(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_tvaudio_init(struct tw68_dev *dev) +{ + return; +} + +int tw68_tvaudio_init2(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_tvaudio_fini(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_tvaudio_do_scan(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_enable_i2s(struct tw68_dev *dev) +{ + return; +} + diff --git a/drivers/media/pci/tw68/tw68-vbi.c b/drivers/media/pci/tw68/tw68-vbi.c new file mode 100644 index 000000000000..fbad3b998848 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-vbi.c @@ -0,0 +1,76 @@ +/* + * tw68_controls.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 "tw68.h" + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) { + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); + return 0; +} +static int buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); + return 0; +} +static void buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); +} +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); +} +struct videobuf_queue_ops tw68_vbi_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +int tw68_vbi_init1(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_vbi_fini(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status) +{ + return; +} + diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c new file mode 100644 index 000000000000..ca08ca38d3bd --- /dev/null +++ b/drivers/media/pci/tw68/tw68-video.c @@ -0,0 +1,2230 @@ +/* + * tw68 functions to handle video data + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 +#include + +#include "tw68.h" +#include "tw68-reg.h" + +unsigned int video_debug; + +static unsigned int gbuffers = 8; +static unsigned int noninterlaced; /* 0 */ +static unsigned int gbufsz = 768*576*4; +static unsigned int gbufsz_max = 768*576*4; +static char secam[] = "--"; + +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); +module_param(gbuffers, int, 0444); +MODULE_PARM_DESC(gbuffers, "number of capture buffers, range 2-32"); +module_param(noninterlaced, int, 0644); +MODULE_PARM_DESC(noninterlaced, "capture non interlaced video"); +module_param_string(secam, secam, sizeof(secam), 0644); +MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); + +#define dprintk(level, fmt, arg...) if (video_debug & (level)) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) + +/* ------------------------------------------------------------------ */ +/* data structs for video */ +/* + * FIXME - + * Note that the saa7134 has formats, e.g. YUV420, which are classified + * as "planar". These affect overlay mode, and are flagged with a field + * ".planar" in the format. Do we need to implement this in this driver? + */ +static struct tw68_format formats[] = { + { + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = 16, + .twformat = ColorFormatRGB15, + }, { + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .twformat = ColorFormatRGB15 | ColorFormatBSWAP, + }, { + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .twformat = ColorFormatRGB16, + }, { + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .twformat = ColorFormatRGB16 | ColorFormatBSWAP, + }, { + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .twformat = ColorFormatRGB24, + }, { + .name = "24 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .twformat = ColorFormatRGB24 | ColorFormatBSWAP, + }, { + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, + .twformat = ColorFormatRGB32, + }, { + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .twformat = ColorFormatRGB32 | ColorFormatBSWAP | + ColorFormatWSWAP, + }, { + .name = "4:2:2 packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .twformat = ColorFormatYUY2, + }, { + .name = "4:2:2 packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .twformat = ColorFormatYUY2 | ColorFormatBSWAP, + } +}; +#define FORMATS ARRAY_SIZE(formats) + +#define NORM_625_50 \ + .h_delay = 3, \ + .h_delay0 = 133, \ + .h_start = 0, \ + .h_stop = 719, \ + .v_delay = 24, \ + .vbi_v_start_0 = 7, \ + .vbi_v_stop_0 = 22, \ + .video_v_start = 24, \ + .video_v_stop = 311, \ + .vbi_v_start_1 = 319 + +#define NORM_525_60 \ + .h_delay = 8, \ + .h_delay0 = 138, \ + .h_start = 0, \ + .h_stop = 719, \ + .v_delay = 22, \ + .vbi_v_start_0 = 10, \ + .vbi_v_stop_0 = 21, \ + .video_v_start = 22, \ + .video_v_stop = 262, \ + .vbi_v_start_1 = 273 + +/* + * The following table is searched by tw68_s_std, first for a specific + * match, then for an entry which contains the desired id. The table + * entries should therefore be ordered in ascending order of specificity. + */ +static struct tw68_tvnorm tvnorms[] = { + { + .name = "PAL-BG", + .id = V4L2_STD_PAL_BG, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL-I", + .id = V4L2_STD_PAL_I, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL-DK", + .id = V4L2_STD_PAL_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL", /* autodetect */ + .id = V4L2_STD_PAL, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0x89, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatNTSC, + + }, { + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM-LC", + .id = V4L2_STD_SECAM_LC, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0xb9, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatPALM, + + }, { + .name = "PAL-Nc", + .id = V4L2_STD_PAL_Nc, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0xa1, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALNC, + + }, { + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + .h_delay = 186, + .h_start = 0, + .h_stop = 719, + .v_delay = 26, + .video_v_start = 23, + .video_v_stop = 262, + .vbi_v_start_0 = 10, + .vbi_v_stop_0 = 21, + .vbi_v_start_1 = 273, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPAL60, + + }, { +/* + * FIXME: The following are meant to be "catch-all", and need + * to be further thought out! + */ + .name = "STD-525-60", + .id = V4L2_STD_525_60, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0x89, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatNTSC, + + }, { + .name = "STD-625-50", + .id = V4L2_STD_625_50, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + } +}; +#define TVNORMS ARRAY_SIZE(tvnorms) + +static const struct v4l2_queryctrl no_ctrl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; +static const struct v4l2_queryctrl video_ctrls[] = { + /* --- video --- */ + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 20, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 100, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_COLOR_KILLER, + .name = "Color Killer", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_CHROMA_AGC, + .name = "Chroma AGC", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + /* --- 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 = -15, + .maximum = 15, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; +static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); + +/* + * Routine to lookup a control by its ID, and return a pointer + * to the entry in the video_ctrls array for that control. + */ +static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +{ + unsigned int i; + + for (i = 0; i < CTRLS; i++) + if (video_ctrls[i].id == id) + return video_ctrls+i; + return NULL; +} + +static struct tw68_format *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < FORMATS; i++) + if (formats[i].fourcc == fourcc) + return formats+i; + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct tw68_fh *fh, unsigned int bit) +{ + struct tw68_dev *dev = fh->dev; + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&fh->dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(DBG_FLOW, "%s: %d\n", __func__, bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct tw68_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +static int res_locked(struct tw68_dev *dev, unsigned int bit) +{ + return dev->resources & bit; +} + +static void res_free(struct tw68_fh *fh, + unsigned int bits) +{ + struct tw68_dev *dev = fh->dev; + + BUG_ON((fh->resources & bits) != bits); + + mutex_lock(&fh->dev->lock); + fh->resources &= ~bits; + fh->dev->resources &= ~bits; + dprintk(DBG_FLOW, "%s: %d\n", __func__, bits); + mutex_unlock(&fh->dev->lock); +} + +/* ------------------------------------------------------------------ */ +/* + * Note that the cropping rectangles are described in terms of a single + * frame, i.e. line positions are only 1/2 the interlaced equivalent + */ +static void set_tvnorm(struct tw68_dev *dev, struct tw68_tvnorm *norm) +{ + dprintk(DBG_FLOW, "%s: %s\n", __func__, norm->name); + dev->tvnorm = norm; + + /* setup cropping */ + dev->crop_bounds.left = norm->h_start; + dev->crop_defrect.left = norm->h_start; + dev->crop_bounds.width = norm->h_stop - norm->h_start + 1; + dev->crop_defrect.width = norm->h_stop - norm->h_start + 1; + + dev->crop_bounds.top = norm->video_v_start; + dev->crop_defrect.top = norm->video_v_start; + dev->crop_bounds.height = (((norm->id & V4L2_STD_525_60) ? + 524 : 624)) / 2 - dev->crop_bounds.top; + dev->crop_defrect.height = (norm->video_v_stop - + norm->video_v_start + 1); + + dev->crop_current = dev->crop_defrect; + + if (norm != dev->tvnorm) { + dev->tvnorm = norm; + tw68_set_tvnorm_hw(dev); + } +} + +static void video_mux(struct tw68_dev *dev, int input) +{ + dprintk(DBG_FLOW, "%s: input = %d [%s]\n", __func__, input, + card_in(dev, input).name); + /* + * dev->input shows current application request, + * dev->hw_input shows current hardware setting + */ + dev->input = &card_in(dev, input); + tw68_tvaudio_setinput(dev, &card_in(dev, input)); +} + +/* + * tw68_set_scale + * + * Scaling and Cropping for video decoding + * + * We are working with 3 values for horizontal and vertical - scale, + * delay and active. + * + * HACTIVE represent the actual number of pixels in the "usable" image, + * before scaling. HDELAY represents the number of pixels skipped + * between the start of the horizontal sync and the start of the image. + * HSCALE is calculated using the formula + * HSCALE = (HACTIVE / (#pixels desired)) * 256 + * + * The vertical registers are similar, except based upon the total number + * of lines in the image, and the first line of the image (i.e. ignoring + * vertical sync and VBI). + * + * Note that the number of bytes reaching the FIFO (and hence needing + * to be processed by the DMAP program) is completely dependent upon + * these values, especially HSCALE. + * + * Parameters: + * @dev pointer to the device structure, needed for + * getting current norm (as well as debug print) + * @width actual image width (from user buffer) + * @height actual image height + * @field indicates Top, Bottom or Interlaced + */ +static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field) +{ + + /* set individually for debugging clarity */ + int hactive, hdelay, hscale; + int vactive, vdelay, vscale; + int comb; + + if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ + height /= 2; /* we must set for 1-frame */ + + dprintk(DBG_FLOW, "%s: width=%d, height=%d, both=%d\n Crop rect: " + "top=%d, left=%d, width=%d height=%d\n" + " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " + "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, + width, height, V4L2_FIELD_HAS_BOTH(field), + dev->crop_bounds.top, dev->crop_bounds.left, + dev->crop_bounds.width, dev->crop_bounds.height, + dev->tvnorm->h_delay, dev->tvnorm->h_start, dev->tvnorm->h_stop, + dev->tvnorm->v_delay, dev->tvnorm->video_v_start, + dev->tvnorm->video_v_stop); + + switch (dev->vdecoder) { + case TW6800: + hdelay = dev->tvnorm->h_delay0; + break; + default: + hdelay = dev->tvnorm->h_delay; + break; + } + hdelay += dev->crop_bounds.left; + hactive = dev->crop_bounds.width; + + hscale = (hactive * 256) / (width); + + vdelay = dev->tvnorm->v_delay + dev->crop_bounds.top - + dev->crop_defrect.top; + vactive = dev->crop_bounds.height; + vscale = (vactive * 256) / height; + + dprintk(DBG_FLOW, "%s: %dx%d [%s%s,%s]\n", __func__, + width, height, + V4L2_FIELD_HAS_TOP(field) ? "T" : "", + V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", + v4l2_norm_to_name(dev->tvnorm->id)); + dprintk(DBG_FLOW, "%s: hactive=%d, hdelay=%d, hscale=%d; " + "vactive=%d, vdelay=%d, vscale=%d\n", __func__, + hactive, hdelay, hscale, vactive, vdelay, vscale); + + comb = ((vdelay & 0x300) >> 2) | + ((vactive & 0x300) >> 4) | + ((hdelay & 0x300) >> 6) | + ((hactive & 0x300) >> 8); + dprintk(DBG_FLOW, "%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " + "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", + __func__, comb, vdelay, vactive, hdelay, hactive); + tw_writeb(TW68_CROP_HI, comb); + tw_writeb(TW68_VDELAY_LO, vdelay & 0xff); + tw_writeb(TW68_VACTIVE_LO, vactive & 0xff); + tw_writeb(TW68_HDELAY_LO, hdelay & 0xff); + tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); + + comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); + dprintk(DBG_FLOW, "%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " + "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); + tw_writeb(TW68_SCALE_HI, comb); + tw_writeb(TW68_VSCALE_LO, vscale); + tw_writeb(TW68_HSCALE_LO, hscale); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, + struct tw68_buf *buf) { + + dprintk(DBG_FLOW, "%s: Starting risc program\n", __func__); + /* Assure correct input */ + if (dev->hw_input != dev->input) { + dev->hw_input = dev->input; + tw_andorb(TW68_INFORM, 0x03 << 2, dev->input->vmux << 2); + } + /* Set cropping and scaling */ + tw68_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + /* + * Set start address for RISC program. Note that if the DMAP + * processor is currently running, it must be stopped before + * a new address can be set. + */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN); + tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->risc.dma)); + /* Clear any pending interrupts */ + tw_writel(TW68_INTSTAT, dev->board_virqmask); + /* Enable the risc engine and the fifo */ + tw_andorl(TW68_DMAC, 0xff, buf->fmt->twformat | + ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); + dev->pci_irqmask |= dev->board_virqmask; + tw_setl(TW68_INTMASK, dev->pci_irqmask); + return 0; +} + +/* ------------------------------------------------------------------ */ +/* videobuf queue operations */ + +/* + * check_buf_fmt + * + * callback from tw68-core buffer_queue to determine whether the + * current buffer and the previous one are "compatible" (i.e. the + * risc programs can be chained without requiring a format change) + */ +static int tw68_check_video_fmt(struct tw68_buf *prev, struct tw68_buf *buf) +{ + return (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt); +} + +/* + * buffer_setup + * + * Calculate required size of buffer and maximum number allowed + */ +static int +buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct tw68_fh *fh = q->priv_data; + + *size = fh->fmt->depth * fh->width * fh->height >> 3; + if (0 == *count) + *count = gbuffers; + *count = tw68_buffer_count(*size, *count); + return 0; +} + +static int buffer_activate(struct tw68_dev *dev, struct tw68_buf *buf, + struct tw68_buf *next) +{ + dprintk(DBG_BUFF, "%s: dev=%p, buf=%p, next=%p\n", + __func__, dev, buf, next); + if (dev->hw_input != dev->input) { + dev->hw_input = dev->input; + tw_andorb(TW68_INFORM, 0x03 << 2, + dev->hw_input->vmux << 2); + } + buf->vb.state = VIDEOBUF_ACTIVE; + /* TODO - need to assure scaling/cropping are set correctly */ + mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* +* buffer_prepare +* +* Set the ancilliary information into the buffer structure. This +* includes generating the necessary risc program if it hasn't already +* been done for the current buffer format. +* The structure fh contains the details of the format requested by the +* user - type, width, height and #fields. This is compared with the +* last format set for the current buffer. If they differ, the risc +* code (which controls the filling of the buffer) is (re-)generated. +*/ +static int +buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct tw68_fh *fh = q->priv_data; + struct tw68_dev *dev = fh->dev; + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int rc, init_buffer = 0; + unsigned int maxw, maxh; + + BUG_ON(NULL == fh->fmt); + maxw = dev->tvnorm->h_stop - dev->tvnorm->h_start + 1; + maxh = 2*(dev->tvnorm->video_v_stop - dev->tvnorm->video_v_start + 1); + if (fh->width < 48 || fh->width > maxw || fh->height > maxh + || fh->height < 16) { + dprintk(DBG_UNEXPECTED, "%s: invalid dimensions - " + "fh->width=%d, fh->height=%d, maxw=%d, maxh=%d\n", + __func__, fh->width, fh->height, maxw, maxh); + return -EINVAL; + } + buf->vb.size = (fh->width * fh->height * (fh->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) { + dprintk(DBG_BUFF, "%s: buf - fmt=%p, width=%3d, height=%3d, " + "field=%d\n%s: fh - fmt=%p, width=%3d, height=%3d, " + "field=%d\n", __func__, buf->fmt, buf->vb.width, + buf->vb.height, buf->vb.field, __func__, fh->fmt, + fh->width, fh->height, field); + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; /* force risc code re-generation */ + } + buf->input = dev->input; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + init_buffer = 1; /* force risc code re-generation */ + } + dprintk(DBG_BUFF, "%s: q=%p, vb=%p, init_buffer=%d\n", + __func__, q, vb, init_buffer); + + if (init_buffer) { + buf->bpl = buf->vb.width * (buf->fmt->depth) >> 3; + dprintk(DBG_TESTING, "%s: Generating new risc code " + "[%dx%dx%d](%d)\n", __func__, buf->vb.width, + buf->vb.height, buf->fmt->depth, buf->bpl); + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, UNSET, + buf->bpl, 0, + buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + UNSET, 0, + buf->bpl, 0, + buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(DBG_BUFF, "%s: [%p/%d] - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + __func__, buf, buf->vb.i, fh->width, fh->height, + fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + buf->activate = buffer_activate; + return 0; + + fail: + tw68_dma_free(q, buf); + return rc; +} + +/* + * buffer_queue + * + * Callback whenever a buffer has been requested (by read() or QBUF) + */ +static void +buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct tw68_fh *fh = q->priv_data; + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + tw68_buffer_queue(fh->dev, &fh->dev->video_q, buf); +} + +/* + * buffer_release + * + * Free a buffer previously allocated. + */ +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + tw68_dma_free(q, buf); +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +static int tw68_g_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, + struct v4l2_control *c) +{ + const struct v4l2_queryctrl *ctrl; + + dprintk(DBG_FLOW, "%s\n", __func__); + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = (char)tw_readb(TW68_BRIGHT); + break; + case V4L2_CID_HUE: + c->value = (char)tw_readb(TW68_HUE); + break; + case V4L2_CID_CONTRAST: + c->value = tw_readb(TW68_CONTRAST); + break; + case V4L2_CID_SATURATION: + c->value = tw_readb(TW68_SAT_U); + break; + case V4L2_CID_COLOR_KILLER: + c->value = 0 != (tw_readb(TW68_MISC2) & 0xe0); + break; + case V4L2_CID_CHROMA_AGC: + c->value = 0 != (tw_readb(TW68_LOOP) & 0x30); + break; + case V4L2_CID_AUDIO_MUTE: + /*hack to suppresss tvtime complaint */ + c->value = 0; + break; +#if 0 + case V4L2_CID_AUDIO_VOLUME: + c->value = dev->ctl_volume; + break; +#endif + default: + return -EINVAL; + } + return 0; +} + +static int tw68_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +{ + struct tw68_fh *fh = priv; + + return tw68_g_ctrl_internal(fh->dev, fh, c); +} + +static int tw68_s_ctrl_value(struct tw68_dev *dev, __u32 id, int val) +{ + int err = 0; + + dprintk(DBG_FLOW, "%s\n", __func__); + switch (id) { + case V4L2_CID_BRIGHTNESS: + tw_writeb(TW68_BRIGHT, val); + break; + case V4L2_CID_HUE: + tw_writeb(TW68_HUE, val); + break; + case V4L2_CID_CONTRAST: + tw_writeb(TW68_CONTRAST, val); + break; + case V4L2_CID_SATURATION: + tw_writeb(TW68_SAT_U, val); + tw_writeb(TW68_SAT_V, val); + break; + case V4L2_CID_COLOR_KILLER: + if (val) + tw_andorb(TW68_MISC2, 0xe0, 0xe0); + else + tw_andorb(TW68_MISC2, 0xe0, 0x00); + break; + case V4L2_CID_CHROMA_AGC: + if (val) + tw_andorb(TW68_LOOP, 0x30, 0x20); + else + tw_andorb(TW68_LOOP, 0x30, 0x00); + break; + case V4L2_CID_AUDIO_MUTE: + /* hack to suppress tvtime complaint */ + break; +#if 0 + case V4L2_CID_AUDIO_VOLUME: + dev->ctl_volume = val; + tw68_tvaudio_setvolume(dev, dev->ctl_volume); + break; + case V4L2_CID_HFLIP: + dev->ctl_mirror = val; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + dev->ctl_automute = val; + if (dev->tda9887_conf) { + if (dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + else + dev->tda9887_conf &= ~TDA9887_AUTOMUTE; + + tw_call_all(dev, tuner, s_config, &tda9887_cfg); + } + break; + } +#endif + default: + err = -EINVAL; + } + return err; +} + +static int tw68_s_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, + struct v4l2_control *c) +{ + const struct v4l2_queryctrl *ctrl; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (fh) { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + return err; + } + + mutex_lock(&dev->lock); + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) { + err = -EINVAL; + goto error; + } + + dprintk(DBG_BUFF, "%s: name=%s val=%d\n", __func__, + ctrl->name, c->value); + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (c->value < ctrl->minimum) + c->value = ctrl->minimum; + if (c->value > ctrl->maximum) + c->value = ctrl->maximum; + break; + default: + /* nothing */; + }; + err = tw68_s_ctrl_value(dev, c->id, c->value); + +error: + mutex_unlock(&dev->lock); + return err; +} + +static int tw68_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +{ + struct tw68_fh *fh = f; + + return tw68_s_ctrl_internal(fh->dev, fh, c); +} + +/* ------------------------------------------------------------------ */ + +/* + * Returns a pointer to the currently used queue (e.g. video, vbi, etc.) + */ +static struct videobuf_queue *tw68_queue(struct tw68_fh *fh) +{ + struct videobuf_queue *q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int tw68_resource(struct tw68_fh *fh) +{ + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return RESOURCE_VIDEO; + + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return RESOURCE_VBI; + + BUG(); + return 0; +} + +static int video_open(struct file *file) +{ + int minor = video_devdata(file)->minor; + struct tw68_dev *dev; + struct tw68_fh *fh; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int radio = 0; + + mutex_lock(&tw68_devlist_lock); + list_for_each_entry(dev, &tw68_devlist, devlist) { + if (dev->video_dev && (dev->video_dev->minor == minor)) + goto found; + if (dev->radio_dev && (dev->radio_dev->minor == minor)) { + radio = 1; + goto found; + } + if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { + type = V4L2_BUF_TYPE_VBI_CAPTURE; + goto found; + } + } + mutex_unlock(&tw68_devlist_lock); + return -ENODEV; + +found: + mutex_unlock(&tw68_devlist_lock); + + dprintk(DBG_FLOW, "%s: minor=%d radio=%d type=%s\n", __func__, minor, + radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + 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, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct tw68_buf), +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + fh +#else + fh, &dev->lock +#endif + ); + videobuf_queue_sg_init(&fh->vbi, &tw68_vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct tw68_buf), +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + fh +#else + fh, &dev->lock +#endif + ); + if (fh->radio) { + /* switch to radio mode */ + tw68_tvaudio_setinput(dev, &card(dev).radio); + tw_call_all(dev, tuner, s_radio); + } else { + /* switch to video/vbi mode */ + tw68_tvaudio_setinput(dev, dev->input); + } + return 0; +} + +static ssize_t +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct tw68_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(tw68_queue(fh), + data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh, RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(tw68_queue(fh), + data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + break; + default: + BUG(); + return 0; + } +} + +static unsigned int +video_poll(struct file *file, struct poll_table_struct *wait) +{ + struct tw68_fh *fh = file->private_data; + struct videobuf_buffer *buf = NULL; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) + return videobuf_poll_stream(file, &fh->vbi, wait); + + if (res_check(fh, RESOURCE_VIDEO)) { + if (!list_empty(&fh->cap.stream)) + buf = list_entry(fh->cap.stream.next, + struct videobuf_buffer, stream); + } else { + mutex_lock(&fh->cap.vb_lock); + if (UNSET == fh->cap.read_off) { + /* need to capture a new frame */ + if (res_locked(fh->dev, RESOURCE_VIDEO)) + goto err; + if (0 != fh->cap.ops->buf_prepare(&fh->cap, + fh->cap.read_buf, fh->cap.field)) + goto err; + fh->cap.ops->buf_queue(&fh->cap, fh->cap.read_buf); + fh->cap.read_off = 0; + } + mutex_unlock(&fh->cap.vb_lock); + buf = fh->cap.read_buf; + } + + if (!buf) + return POLLERR; + + poll_wait(file, &buf->done, wait); + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) + return POLLIN | POLLRDNORM; + return 0; + +err: + mutex_unlock(&fh->cap.vb_lock); + return POLLERR; +} + +static int video_release(struct file *file) +{ + struct tw68_fh *fh = file->private_data; + struct tw68_dev *dev = fh->dev; + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_streamoff(&fh->cap); + res_free(fh , RESOURCE_VIDEO); + } + if (fh->cap.read_buf) { + buffer_release(&fh->cap, fh->cap.read_buf); + kfree(fh->cap.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + videobuf_stop(&fh->vbi); + res_free(fh, RESOURCE_VBI); + } + +#if 0 + tw_call_all(dev, core, s_standby, 0); +#endif + + /* free stuff */ + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + v4l2_prio_close(&dev->prio, &fh->prio); +#else + v4l2_prio_close(&dev->prio, fh->prio); +#endif + file->private_data = NULL; + kfree(fh); + return 0; +} + +static int video_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct tw68_fh *fh = file->private_data; + + return videobuf_mmap_mapper(tw68_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ + +#if 0 +static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + struct tw68_tvnorm *norm = dev->tvnorm; + + 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; + f->fmt.vbi.offset = 64 * 4; + f->fmt.vbi.start[0] = norm->vbi_v_start_0; + f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; + f->fmt.vbi.start[1] = norm->vbi_v_start_1; + f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ + +#if 0 + if (V4L2_STD_PAL == norm->id) { + /* FIXME */ + f->fmt.vbi.start[0] += 3; + f->fmt.vbi.start[1] += 3*2; + } +#endif + return 0; +} +#endif + +/* + * Note that this routine returns what is stored in the fh structure, and + * does not interrogate any of the device registers. + */ +static int tw68_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->cap.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; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int tw68_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + struct tw68_format *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + dprintk(DBG_FLOW, "%s\n", __func__); + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); + maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + break; + case V4L2_FIELD_INTERLACED: + maxh = maxh * 2; + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + 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; +} + +/* + * Note that tw68_s_fmt_vid_cap sets the information into the fh structure, + * and it will be used for all future new buffers. However, there could be + * some number of buffers on the "active" chain which will be filled before + * the change takes place. + */ +static int tw68_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + err = tw68_try_fmt_vid_cap(file, priv, f); + if (0 != err) + return err; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->cap.field = f->fmt.pix.field; + /* + * The following lines are to make v4l2-test program happy. + * The docs should be checked to assure they make sense. + */ + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + return 0; +} + +static int tw68_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) +#if 0 + && (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1) +#endif + ) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + *c = *ctrl; + return 0; +} + +static int tw68_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + unsigned int n; + + n = i->index; + dprintk(DBG_FLOW, "%s: index is %d\n", __func__, n); + if (n >= TW68_INPUT_MAX) { + dprintk(DBG_FLOW, "%s: INPUT_MAX reached\n", __func__); + return -EINVAL; + } + if (NULL == card_in(dev, n).name) { + dprintk(DBG_FLOW, "%s: End of list\n", __func__); + return -EINVAL; + } + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, card_in(dev, n).name); + if (card_in(dev, n).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + i->audioset = 1; + /* If the query is for the current input, get live data */ + if (n == dev->hw_input->vmux) { + int v1 = tw_readb(TW68_STATUS1); + int v2 = tw_readb(TW68_MVSN); + + if (0 != (v1 & (1 << 7))) + i->status |= V4L2_IN_ST_NO_SYNC; + if (0 != (v1 & (1 << 6))) + i->status |= V4L2_IN_ST_NO_H_LOCK; + if (0 != (v1 & (1 << 2))) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 != (v1 & 1 << 1)) + i->status |= V4L2_IN_ST_NO_COLOR; + if (0 != (v2 & (1 << 2))) + i->status |= V4L2_IN_ST_MACROVISION; + } + i->std = TW68_NORMS; + return 0; +} + +static int tw68_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *i = dev->input->vmux; + return 0; +} + +static int tw68_s_input(struct file *file, void *priv, unsigned int i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + + if (i < 0 || i >= TW68_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + unsigned int tuner_type = dev->tuner_type; + + dprintk(DBG_FLOW, "%s\n", __func__); + strcpy(cap->driver, "tw68"); + strlcpy(cap->card, tw68_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = TW68_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; + return 0; +} + +static int tw68_s_std_internal(struct tw68_dev *dev, struct tw68_fh *fh, + v4l2_std_id *id) +{ +/* unsigned long flags; */ + unsigned int i; + v4l2_std_id fixup; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (fh) { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + } + + /* Look for match on complete norm id (may have mult bits) */ + for (i = 0; i < TVNORMS; i++) { + if (*id == tvnorms[i].id) + break; + } + + /* If no exact match, look for norm which contains this one */ + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) { + if (*id & tvnorms[i].id) + break; + } + /* If still not matched, give up */ + if (i == TVNORMS) + return -EINVAL; + + /* TODO - verify this additional work with SECAM applies to TW */ + 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; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; + } + + *id = tvnorms[i].id; + mutex_lock(&dev->lock); + set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ + tw68_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + return tw68_s_std_internal(fh->dev, fh, id); +} + +static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *id = dev->tvnorm->id; + return 0; +} + +static int tw68_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int n; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + for (n = 0; n < TW68_INPUT_MAX; n++) + if (card_in(dev, n).tv) + break; + if (n == TW68_INPUT_MAX) + return -EINVAL; +#if 0 + if (NULL != card_in(dev, n).name) { + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = tw68_tvaudio_getstereo(dev); + t->audmode = tw68_tvaudio_rx2mode(t->rxsubchans); + } + if (0 != (saa_readb(TW68_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; +#endif + return 0; +} + +static int tw68_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; +#if 0 + int rx, mode +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + +#if 0 + mode = dev->thread.mode; + if (UNSET == mode) { + rx = tw68_tvaudio_getstereo(dev); + mode = tw68_tvaudio_rx2mode(t->rxsubchans); + } + if (mode != t->audmode) + dev->thread.mode = t->audmode; +#endif + return 0; +} + +static int tw68_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + if (unlikely(dev->tuner_type)) + return -EINVAL; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; +/* f->frequency = dev->ctl_freq; */ + + return 0; +} + +static int tw68_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + + if (0 != f->tuner) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + mutex_lock(&dev->lock); +/* dev->ctl_freq = f->frequency; */ + + tw_call_all(dev, tuner, s_frequency, f); + + tw68_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + strcpy(a->name, "audio"); + return 0; +} + +static int tw68_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return 0; +} + +static int tw68_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *p = v4l2_prio_max(&dev->prio); + return 0; +} + +static int tw68_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + return v4l2_prio_change(&dev->prio, &fh->prio, prio); +} + +static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (f->index >= FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int tw68_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + } + return 0; +} + +static int tw68_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + crop->c = dev->crop_current; + return 0; +} + +static int tw68_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + struct v4l2_rect *b = &dev->crop_bounds; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + + if ((crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (crop->c.height < 0) || (crop->c.width < 0)) { + dprintk(DBG_UNEXPECTED, "%s: invalid request\n", __func__); + return -EINVAL; + } + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dprintk(DBG_FLOW, "%s: setting cropping rectangle: top=%d, left=%d, " + "width=%d, height=%d\n", __func__, crop->c.top, + crop->c.left, crop->c.width, crop->c.height); + dev->crop_current = crop->c; + return 0; +} + +/* + * Wrappers for the v4l2_ioctl_ops functions + */ +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct tw68_fh *fh = file->private_data; + return videobuf_cgmbuf(tw68_queue(fh), mbuf, 8); +} +#endif + +static int tw68_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct tw68_fh *fh = priv; + return videobuf_reqbufs(tw68_queue(fh), p); +} + +static int tw68_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_querybuf(tw68_queue(fh), b); +} + +static int tw68_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_qbuf(tw68_queue(fh), b); +} + +static int tw68_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_dqbuf(tw68_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int tw68_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int res = tw68_resource(fh); + + dprintk(DBG_FLOW, "%s\n", __func__); + if (!res_get(fh, res)) + return -EBUSY; + + tw68_buffer_requeue(dev, &dev->video_q); + return videobuf_streamon(tw68_queue(fh)); +} + +static int tw68_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int err; + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int res = tw68_resource(fh); + + dprintk(DBG_FLOW, "%s\n", __func__); + err = videobuf_streamoff(tw68_queue(fh)); + if (err < 0) + return err; + res_free(fh, res); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * Used strictly for internal development and debugging, this routine + * prints out the current register contents for the tw68xx device. + */ +static void tw68_dump_regs(struct tw68_dev *dev) +{ + unsigned char line[80]; + int i, j, k; + unsigned char *cptr; + + printk(KERN_DEBUG "Full dump of TW68 registers:\n"); + /* First we do the PCI regs, 8 4-byte regs per line */ + for (i = 0; i < 0x100; i += 32) { + cptr = line; + cptr += sprintf(cptr, "%03x ", i); + /* j steps through the next 4 words */ + for (j = i; j < i + 16; j += 4) + cptr += sprintf(cptr, "%08x ", tw_readl(j)); + *cptr++ = ' '; + for (; j < i + 32; j += 4) + cptr += sprintf(cptr, "%08x ", tw_readl(j)); + *cptr++ = '\n'; + *cptr = 0; + printk(KERN_DEBUG "%s", line); + } + /* Next the control regs, which are single-byte, address mod 4 */ + while (i < 0x400) { + cptr = line; + cptr += sprintf(cptr, "%03x ", i); + /* Print out 4 groups of 4 bytes */ + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + cptr += sprintf(cptr, "%02x ", + tw_readb(i)); + i += 4; + } + *cptr++ = ' '; + } + *cptr++ = '\n'; + *cptr = 0; + printk(KERN_DEBUG "%s", line); + } +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + tw68_dump_regs(dev); + return 0; +} + +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; /* needed for tw_readb */ + + dprintk(DBG_FLOW, "%s\n", __func__); + if (!v4l2_chip_match_host(®->match)) + dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); + return -EINVAL; + if (reg->size == 1) + reg->val = tw_readb(reg->reg); + else + reg->val = tw_readl(reg->reg); + return 0; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; /* needed for tw_writeb */ + + dprintk(DBG_FLOW, "%s: request to set reg 0x%04x to 0x%02x\n", + __func__, (unsigned int)reg->reg, (unsigned int)reg->val); + if (!v4l2_chip_match_host(®->match)) { + dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); + return -EINVAL; + } + if (reg->size == 1) + tw_writeb(reg->reg, reg->val); + else + tw_writel(reg->reg & 0xffff, reg->val); + return 0; +} +#endif + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = tw68_querycap, + .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, + .vidioc_reqbufs = tw68_reqbufs, + .vidioc_querybuf = tw68_querybuf, + .vidioc_qbuf = tw68_qbuf, + .vidioc_dqbuf = tw68_dqbuf, + .vidioc_s_std = tw68_s_std, + .vidioc_g_std = tw68_g_std, + .vidioc_enum_input = tw68_enum_input, + .vidioc_g_input = tw68_g_input, + .vidioc_s_input = tw68_s_input, + .vidioc_queryctrl = tw68_queryctrl, + .vidioc_g_ctrl = tw68_g_ctrl, + .vidioc_s_ctrl = tw68_s_ctrl, + .vidioc_streamon = tw68_streamon, + .vidioc_streamoff = tw68_streamoff, + .vidioc_g_priority = tw68_g_priority, + .vidioc_s_priority = tw68_s_priority, + .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, + .vidioc_cropcap = tw68_cropcap, + .vidioc_g_crop = tw68_g_crop, + .vidioc_s_crop = tw68_s_crop, +/* + * Functions not yet implemented / not yet passing tests. + */ + +#if 0 + .vidioc_g_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, +#endif + .vidioc_g_audio = tw68_g_audio, + .vidioc_s_audio = tw68_s_audio, + .vidioc_g_tuner = tw68_g_tuner, + .vidioc_s_tuner = tw68_s_tuner, + .vidioc_g_frequency = tw68_g_frequency, + .vidioc_s_frequency = tw68_s_frequency, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_log_status = vidioc_log_status, + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +/* ------------------------------------------------------------------ */ +/* exported stuff */ +struct video_device tw68_video_template = { + .name = "tw68_video", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .minor = -1, + .tvnorms = TW68_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +struct video_device tw68_radio_template = { + .name = "tw68_radio", +}; + +int tw68_videoport_init(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_set_tvnorm_hw(struct tw68_dev *dev) +{ + tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); + return; +} + +int tw68_video_init1(struct tw68_dev *dev) +{ + int i; + + dprintk(DBG_FLOW, "%s\n", __func__); + /* sanitycheck insmod options */ + if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) + gbuffers = 2; + if (gbufsz < 0 || gbufsz > gbufsz_max) + gbufsz = gbufsz_max; + gbufsz = (gbufsz + PAGE_SIZE - 1) & PAGE_MASK; + + /* put some sensible defaults into the data structures ... */ + for (i = 0; i < CTRLS; i++) + tw68_s_ctrl_value(dev, video_ctrls[i].id, + video_ctrls[i].default_value); +#if 0 + if (dev->tda9887_conf && dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + dev->automute = 0; +#endif + INIT_LIST_HEAD(&dev->video_q.queued); + INIT_LIST_HEAD(&dev->video_q.active); + init_timer(&dev->video_q.timeout); + dev->video_q.timeout.function = tw68_buffer_timeout; + dev->video_q.timeout.data = (unsigned long)(&dev->video_q); + dev->video_q.dev = dev; + dev->video_q.buf_compat = tw68_check_video_fmt; + dev->video_q.start_dma = tw68_video_start_dma; + tw68_risc_stopper(dev->pci, &dev->video_q.stopper); + + if (tw68_boards[dev->board].video_out) + tw68_videoport_init(dev); + + return 0; +} + +int tw68_video_init2(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s\n", __func__); + set_tvnorm(dev, &tvnorms[0]); + video_mux(dev, 0); +/* + tw68_tvaudio_setmut(dev); + tw68_tvaudio_setvolume(dev, dev->ctl_volume); +*/ + return 0; +} + +/* + * tw68_irq_video_signalchange + * + * TODO: + * Check for presence of video signal. If not present, mute audio. + * If present, log type of signal present. + */ +void tw68_irq_video_signalchange(struct tw68_dev *dev) +{ + return; +} + +/* + * tw68_irq_video_done + */ +void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) +{ + __u32 reg; + + /* reset interrupts handled by this routine */ + tw_writel(TW68_INTSTAT, status); + /* + * Check most likely first + * + * DMAPI shows we have reached the end of the risc code + * for the current buffer. + */ + if (status & TW68_DMAPI) { + struct tw68_dmaqueue *q = &dev->video_q; + dprintk(DBG_FLOW | DBG_TESTING, "DMAPI interrupt\n"); + spin_lock(&dev->slock); + /* + * tw68_wakeup will take care of the buffer handling, + * plus any non-video requirements. + */ + tw68_wakeup(q, &dev->video_fieldcount); + spin_unlock(&dev->slock); + /* Check whether we have gotten into 'stopper' code */ + reg = tw_readl(TW68_DMAP_PP); + if ((reg >= q->stopper.dma) && + (reg < q->stopper.dma + q->stopper.size)) { + /* Yes - log the information */ + dprintk(DBG_FLOW | DBG_TESTING, + "%s: stopper risc code entered\n", __func__); + } + status &= ~(TW68_DMAPI); + if (0 == status) + return; + } + if (status & (TW68_VLOCK | TW68_HLOCK)) { /* lost sync */ + dprintk(DBG_UNUSUAL, "Lost sync\n"); + } + if (status & TW68_PABORT) { /* TODO - what should we do? */ + dprintk(DBG_UNEXPECTED, "PABORT interrupt\n"); + } + if (status & TW68_DMAPERR) { + dprintk(DBG_UNEXPECTED, "DMAPERR interrupt\n"); +#if 0 + /* Stop risc & fifo */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + tw_clearl(TW68_INTMASK, dev->board_virqmask); + dev->pci_irqmask &= ~dev->board_virqmask; +#endif + } + /* + * On TW6800, FDMIS is apparently generated if video input is switched + * during operation. Therefore, it is not enabled for that chip. + */ + if (status & TW68_FDMIS) { /* logic error somewhere */ + dprintk(DBG_UNEXPECTED, "FDMIS interrupt\n"); + /* Stop risc & fifo */ +// tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); +// tw_clearl(TW68_INTMASK, dev->board_virqmask); +// dev->pci_irqmask &= ~dev->board_virqmask; + } + if (status & TW68_FFOF) { /* probably a logic error */ + reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; + tw_clearl(TW68_DMAC, TW68_FIFO_EN); + dprintk(DBG_UNUSUAL, "FFOF interrupt\n"); + tw_setl(TW68_DMAC, reg); + } + if (status & TW68_FFERR) + dprintk(DBG_UNEXPECTED, "FFERR interrupt\n"); + return; +} diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h new file mode 100644 index 000000000000..e723efb5e623 --- /dev/null +++ b/drivers/media/pci/tw68/tw68.h @@ -0,0 +1,588 @@ +/* + * tw68 driver common header file + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 +#define TW68_VERSION_CODE KERNEL_VERSION(0, 0, 8) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +# include +#endif +#include +#include + +#include "btcx-risc.h" +#include "tw68-reg.h" + +#define UNSET (-1U) + +/* + * dprintk statement within the code use a 'level' argument. For + * our purposes, we use the following levels: + */ +#define DBG_UNEXPECTED (1 << 0) +#define DBG_UNUSUAL (1 << 1) +#define DBG_TESTING (1 << 2) +#define DBG_BUFF (1 << 3) +#define DBG_FLOW (1 << 15) + +/* system vendor and device ID's */ +#define PCI_VENDOR_ID_TECHWELL 0x1797 +#define PCI_DEVICE_ID_6800 0x6800 +#define PCI_DEVICE_ID_6801 0x6801 +#define PCI_DEVICE_ID_AUDIO2 0x6802 +#define PCI_DEVICE_ID_TS3 0x6803 +#define PCI_DEVICE_ID_6804 0x6804 +#define PCI_DEVICE_ID_AUDIO5 0x6805 +#define PCI_DEVICE_ID_TS6 0x6806 + +/* tw6816 based cards */ +#define PCI_DEVICE_ID_6816_1 0x6810 +#define PCI_DEVICE_ID_6816_2 0x6811 +#define PCI_DEVICE_ID_6816_3 0x6812 +#define PCI_DEVICE_ID_6816_4 0x6813 + +/* subsystem vendor ID's */ +#define TW68_PCI_ID_TECHWELL 0x1797 + +#define TW68_NORMS (\ + V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60 | \ + V4L2_STD_525_60 | V4L2_STD_625_50 | \ + V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC | V4L2_STD_SECAM_DK) + +#define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ + TW68_FFOF | TW68_DMAPI) +/* TW6800 chips have trouble with these, so we don't set them for that chip */ +#define TW68_VID_INTSX (TW68_FDMIS | TW68_HLOCK | TW68_VLOCK) + +#define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ + TW68_SBDONE2) + +typedef enum { + TW6800, + TW6801, + TW6804, + TWXXXX, +} TW68_DECODER_TYPE; +/* ----------------------------------------------------------- */ +/* static data */ + +struct tw68_tvnorm { + char *name; + v4l2_std_id id; + + /* video decoder */ + u32 sync_control; + u32 luma_control; + u32 chroma_ctrl1; + u32 chroma_gain; + u32 chroma_ctrl2; + u32 vgate_misc; + + /* video scaler */ + u32 h_delay; + u32 h_delay0; /* for TW6800 */ + u32 h_start; + u32 h_stop; + u32 v_delay; + u32 video_v_start; + u32 video_v_stop; + u32 vbi_v_start_0; + u32 vbi_v_stop_0; + u32 vbi_v_start_1; + + /* Techwell specific */ + u32 format; +}; + +struct tw68_format { + char *name; + u32 fourcc; + u32 depth; + u32 twformat; +}; + +/* ----------------------------------------------------------- */ +/* card configuration */ + +#define TW68_BOARD_NOAUTO UNSET +#define TW68_BOARD_UNKNOWN 0 +#define TW68_BOARD_GENERIC_6802 1 + +#define TW68_MAXBOARDS 16 +#define TW68_INPUT_MAX 8 + +/* ----------------------------------------------------------- */ +/* enums */ + +enum tw68_mpeg_type { + TW68_MPEG_UNUSED, + TW68_MPEG_EMPRESS, + TW68_MPEG_DVB, +}; + +enum tw68_audio_in { + TV = 1, + LINE1 = 2, + LINE2 = 3, + LINE2_LEFT, +}; + +enum tw68_video_out { + CCIR656 = 1, +}; + +/* Structs for card definition */ +struct tw68_input { + char *name; /* text description */ + unsigned int vmux; /* mux value */ + enum tw68_audio_in mux; + unsigned int gpio; + unsigned int tv:1; +}; + +struct tw68_board { + char *name; + unsigned int audio_clock; + + /* input switching */ + unsigned int gpiomask; + struct tw68_input inputs[TW68_INPUT_MAX]; + struct tw68_input radio; + struct tw68_input mute; + + /* i2c chip info */ + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + unsigned int tda9887_conf; + unsigned int tuner_config; + + enum tw68_video_out video_out; + enum tw68_mpeg_type mpeg; + unsigned int vid_port_opts; +}; + +#define card_has_radio(dev) (NULL != tw68_boards[dev->board].radio.name) +#define card_has_mpeg(dev) (TW68_MPEG_UNUSED != \ + tw68_boards[dev->board].mpeg) +#define card_in(dev, n) (tw68_boards[dev->board].inputs[n]) +#define card(dev) (tw68_boards[dev->board]) + +/* ----------------------------------------------------------- */ +/* device / file handle status */ + +#define RESOURCE_VIDEO 1 +#define RESOURCE_VBI 2 + +#define INTERLACE_AUTO 0 +#define INTERLACE_ON 1 +#define INTERLACE_OFF 2 + +#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ + +struct tw68_dev; /* forward delclaration */ + +/* tvaudio thread status */ +struct tw68_thread { + struct task_struct *thread; + unsigned int scan1; + unsigned int scan2; + unsigned int mode; + unsigned int stopped; +}; + +/* buffer for one video/vbi/ts frame */ +struct tw68_buf { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* tw68 specific */ + struct tw68_format *fmt; + struct tw68_input *input; + unsigned int top_seen; + int (*activate)(struct tw68_dev *dev, + struct tw68_buf *buf, + struct tw68_buf *next); + struct btcx_riscmem risc; + unsigned int bpl; +}; + +struct tw68_dmaqueue { + struct tw68_dev *dev; + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + int (*buf_compat)(struct tw68_buf *prev, + struct tw68_buf *buf); + int (*start_dma)(struct tw68_dev *dev, + struct tw68_dmaqueue *q, + struct tw68_buf *buf); +}; + +/* video filehandle status */ +struct tw68_fh { + struct tw68_dev *dev; + unsigned int radio; + enum v4l2_buf_type type; + unsigned int resources; + enum v4l2_priority prio; + + /* video capture */ + struct tw68_format *fmt; + unsigned int width, height; + struct videobuf_queue cap; /* also used for overlay */ + + /* vbi capture */ + struct videobuf_queue vbi; +}; + +/* dmasound dsp status */ +struct tw68_dmasound { + struct mutex lock; + int minor_mixer; + int minor_dsp; + unsigned int users_dsp; + + /* mixer */ + enum tw68_audio_in input; + unsigned int count; + unsigned int line1; + unsigned int line2; + + /* dsp */ + unsigned int afmt; + unsigned int rate; + unsigned int channels; + unsigned int recording_on; + unsigned int dma_running; + unsigned int blocks; + unsigned int blksize; + unsigned int bufsize; + struct videobuf_dmabuf dma; + unsigned int dma_blk; + unsigned int read_offset; + unsigned int read_count; + void *priv_data; + struct snd_pcm_substream *substream; +}; + +struct tw68_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 twformat; +}; + +/* ts/mpeg status */ +struct tw68_ts { + /* TS capture */ + int nr_packets; + int nr_bufs; +}; + +/* ts/mpeg ops */ +struct tw68_mpeg_ops { + enum tw68_mpeg_type type; + struct list_head next; + int (*init)(struct tw68_dev *dev); + int (*fini)(struct tw68_dev *dev); + void (*signal_change)(struct tw68_dev *dev); +}; + +enum tw68_ts_status { + TW68_TS_STOPPED, + TW68_TS_BUFF_DONE, + TW68_TS_STARTED, +}; + +/* global device status */ +struct tw68_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; + + /* insmod option/autodetected */ + int autodetected; + + /* various device info */ + TW68_DECODER_TYPE vdecoder; + unsigned int resources; + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + struct tw68_dmasound dmasound; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) + /* infrared remote */ + int has_remote; + struct card_ir *remote; +#endif + + /* pci i/o */ + char name[32]; + int nr; + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + u32 pci_irqmask; + /* The irq mask to be used will depend upon the chip type */ + u32 board_virqmask; + + /* config info */ + unsigned int board; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + unsigned int tda9887_conf; + unsigned int gpio_value; + + /* i2c i/o */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + u32 i2c_state; + u32 i2c_done; + wait_queue_head_t i2c_queue; + int i2c_rc; + unsigned char eedata[256]; + + /* video+ts+vbi capture */ + struct tw68_dmaqueue video_q; + struct tw68_dmaqueue vbi_q; + unsigned int video_fieldcount; + unsigned int vbi_fieldcount; + + /* various v4l controls */ + struct tw68_tvnorm *tvnorm; /* video */ + struct tw68_tvaudio *tvaudio; +#if 0 + unsigned int ctl_input; + int ctl_bright; + int ctl_contrast; + int ctl_hue; + int ctl_saturation; + int ctl_freq; + int ctl_mute; /* audio */ + int ctl_volume; + int ctl_invert; /* private */ + int ctl_mirror; + int ctl_y_odd; + int ctl_y_even; + int ctl_automute; +#endif + + /* crop */ + struct v4l2_rect crop_bounds; + struct v4l2_rect crop_defrect; + struct v4l2_rect crop_current; + + /* other global state info */ + unsigned int automute; + struct tw68_thread thread; + /* input is latest requested by app, hw_input is current hw setting */ + struct tw68_input *input; + struct tw68_input *hw_input; + unsigned int hw_mute; + int last_carrier; + int nosignal; + unsigned int insuspend; + + /* TW68_MPEG_* */ + struct tw68_ts ts; + struct tw68_dmaqueue ts_q; + enum tw68_ts_status ts_state; + unsigned int buff_cnt; + struct tw68_mpeg_ops *mops; + + void (*gate_ctrl)(struct tw68_dev *dev, int open); +}; + +/* ----------------------------------------------------------- */ + +#define tw_readl(reg) readl(dev->lmmio + ((reg) >> 2)) +#define tw_readb(reg) readb(dev->bmmio + (reg)) +#define tw_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) +#define tw_writeb(reg, value) writeb((value), dev->bmmio + (reg)) + +#define tw_andorl(reg, mask, value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) +#define tw_andorb(reg, mask, value) \ + writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\ + ((value) & (mask)), dev->bmmio+(reg)) +#define tw_setl(reg, bit) tw_andorl((reg), (bit), (bit)) +#define tw_setb(reg, bit) tw_andorb((reg), (bit), (bit)) +#define tw_clearl(reg, bit) \ + writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \ + dev->lmmio + ((reg) >> 2)) +#define tw_clearb(reg, bit) \ + writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ + dev->bmmio + (reg)) +#define tw_call_all(dev, o, f, args...) do { \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 1); \ + v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 0); \ +} while (0) + +#define tw_wait(us) { udelay(us); } + +static inline struct tw68_dev *to_tw68_dev(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct tw68_dev, v4l2_dev); +} + +/* ----------------------------------------------------------- */ +/* tw68-core.c */ + +extern struct list_head tw68_devlist; +extern struct mutex tw68_devlist_lock; +extern unsigned int irq_debug; + +int tw68_buffer_count(unsigned int size, unsigned int count); +void tw68_buffer_queue(struct tw68_dev *dev, struct tw68_dmaqueue *q, + struct tw68_buf *buf); +void tw68_buffer_timeout(unsigned long data); +int tw68_set_dmabits(struct tw68_dev *dev); +void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf); +void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *field_count); +int tw68_buffer_requeue(struct tw68_dev *dev, struct tw68_dmaqueue *q); + +/* ----------------------------------------------------------- */ +/* tw68-cards.c */ + +extern struct tw68_board tw68_boards[]; +extern const unsigned int tw68_bcount; +extern struct pci_device_id __devinitdata tw68_pci_tbl[]; + +int tw68_board_init1(struct tw68_dev *dev); +int tw68_board_init2(struct tw68_dev *dev); +int tw68_tuner_callback(void *priv, int component, int command, int arg); + +/* ----------------------------------------------------------- */ +/* tw68-i2c.c */ + +int tw68_i2c_register(struct tw68_dev *dev); +int tw68_i2c_unregister(struct tw68_dev *dev); +void tw68_irq_i2c(struct tw68_dev *dev, int status); + +/* ----------------------------------------------------------- */ +/* tw68-video.c */ + +extern unsigned int video_debug; +extern struct video_device tw68_video_template; +extern struct video_device tw68_radio_template; + +int tw68_videoport_init(struct tw68_dev *dev); +void tw68_set_tvnorm_hw(struct tw68_dev *dev); + +int tw68_video_init1(struct tw68_dev *dev); +int tw68_video_init2(struct tw68_dev *dev); +void tw68_irq_video_signalchange(struct tw68_dev *dev); +void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); + +/* ----------------------------------------------------------- */ +/* tw68-ts.c */ + +int tw68_ts_init1(struct tw68_dev *dev); +int tw68_ts_fini(struct tw68_dev *dev); +void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status); + +int tw68_ts_register(struct tw68_mpeg_ops *ops); +void tw68_ts_unregister(struct tw68_mpeg_ops *ops); + +int tw68_ts_init_hw(struct tw68_dev *dev); + +/* ----------------------------------------------------------- */ +/* tw68-vbi.c */ + +extern struct videobuf_queue_ops tw68_vbi_qops; +extern struct video_device tw68_vbi_template; + +int tw68_vbi_init1(struct tw68_dev *dev); +int tw68_vbi_fini(struct tw68_dev *dev); +void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status); + +/* ----------------------------------------------------------- */ +/* tw68-tvaudio.c */ + +int tw68_tvaudio_rx2mode(u32 rx); + +void tw68_tvaudio_setmute(struct tw68_dev *dev); +void tw68_tvaudio_setinput(struct tw68_dev *dev, + struct tw68_input *in); +void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level); +int tw68_tvaudio_getstereo(struct tw68_dev *dev); +void tw68_tvaudio_init(struct tw68_dev *dev); +int tw68_tvaudio_init2(struct tw68_dev *dev); +int tw68_tvaudio_fini(struct tw68_dev *dev); +int tw68_tvaudio_do_scan(struct tw68_dev *dev); +int tw_dsp_writel(struct tw68_dev *dev, int reg, u32 value); +void tw68_enable_i2s(struct tw68_dev *dev); + +/* ----------------------------------------------------------- */ +/* tw68-risc.c */ + +int tw68_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines); +int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc); +int tw68_risc_overlay(struct tw68_fh *fh, struct btcx_riscmem *risc, + int field_type); -- cgit v1.2.3 From e15d1c12c5878b3a80d6573af1721e17264e0286 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 03:36:14 -0300 Subject: [media] tw68: refactor and cleanup the tw68 driver Refactor and clean up the tw68 driver. It's now using the proper V4L2 core frameworks. Tested with my Techwell tw6805a and tw6816 grabber boards. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/tw68/Kconfig | 10 + drivers/media/pci/tw68/Makefile | 3 + drivers/media/pci/tw68/tw68-cards.c | 172 --- drivers/media/pci/tw68/tw68-core.c | 801 ++------------ drivers/media/pci/tw68/tw68-i2c.c | 245 ----- drivers/media/pci/tw68/tw68-reg.h | 10 +- drivers/media/pci/tw68/tw68-risc.c | 156 +-- drivers/media/pci/tw68/tw68-ts.c | 66 -- drivers/media/pci/tw68/tw68-tvaudio.c | 80 -- drivers/media/pci/tw68/tw68-vbi.c | 76 -- drivers/media/pci/tw68/tw68-video.c | 1922 +++++++-------------------------- drivers/media/pci/tw68/tw68.h | 435 +------- 14 files changed, 566 insertions(+), 3412 deletions(-) create mode 100644 drivers/media/pci/tw68/Kconfig create mode 100644 drivers/media/pci/tw68/Makefile delete mode 100644 drivers/media/pci/tw68/tw68-cards.c delete mode 100644 drivers/media/pci/tw68/tw68-i2c.c delete mode 100644 drivers/media/pci/tw68/tw68-ts.c delete mode 100644 drivers/media/pci/tw68/tw68-tvaudio.c delete mode 100644 drivers/media/pci/tw68/tw68-vbi.c diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 5c16c9c2203e..933280740176 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig" source "drivers/media/pci/zoran/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" +source "drivers/media/pci/tw68/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index dc2ebbe27306..73d9c0f11127 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ +obj-$(CONFIG_VIDEO_TW68) += tw68/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig new file mode 100644 index 000000000000..5425ba1e320d --- /dev/null +++ b/drivers/media/pci/tw68/Kconfig @@ -0,0 +1,10 @@ +config VIDEO_TW68 + tristate "Techwell tw68x Video For Linux" + depends on VIDEO_DEV && PCI && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEOBUF2_DMA_SG + ---help--- + Support for Techwell tw68xx based frame grabber boards. + + To compile this driver as a module, choose M here: the + module will be called tw68. diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile new file mode 100644 index 000000000000..3d02f28b14fb --- /dev/null +++ b/drivers/media/pci/tw68/Makefile @@ -0,0 +1,3 @@ +tw68-objs := tw68-core.o tw68-video.o tw68-risc.o + +obj-$(CONFIG_VIDEO_TW68) += tw68.o diff --git a/drivers/media/pci/tw68/tw68-cards.c b/drivers/media/pci/tw68/tw68-cards.c deleted file mode 100644 index 62aec4faa0d1..000000000000 --- a/drivers/media/pci/tw68/tw68-cards.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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 -#include /* must appear before i2c-algo-bit.h */ -#include - -#include -#include - -#include "tw68.h" -#include "tw68-reg.h" - -/* commly used strings */ -#if 0 -static char name_mute[] = "mute"; -static char name_radio[] = "Radio"; -static char name_tv[] = "Television"; -static char name_tv_mono[] = "TV (mono only)"; -static char name_svideo[] = "S-Video"; -static char name_comp[] = "Composite"; -#endif -static char name_comp1[] = "Composite1"; -static char name_comp2[] = "Composite2"; -static char name_comp3[] = "Composite3"; -static char name_comp4[] = "Composite4"; - -/* ------------------------------------------------------------------ */ -/* board config info */ - -/* If radio_type !=UNSET, radio_addr should be specified - */ - -struct tw68_board tw68_boards[] = { - [TW68_BOARD_UNKNOWN] = { - .name = "GENERIC", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = { - { - .name = name_comp1, - .vmux = 0, - }, { - .name = name_comp2, - .vmux = 1, - }, { - .name = name_comp3, - .vmux = 2, - }, { - .name = name_comp4, - .vmux = 3, - }, { /* Must have a NULL entry at end of list */ - .name = NULL, - .vmux = 0, - } - }, - }, -}; - -const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards); - -/* - * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps - * the PCI ID database up to date. Note that the entries must be - * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. - */ -struct pci_device_id tw68_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6801, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6804, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - /* end of list */ - } -}; -MODULE_DEVICE_TABLE(pci, tw68_pci_tbl); - -/* ------------------------------------------------------------ */ -/* stuff done before i2c enabled */ -int tw68_board_init1(struct tw68_dev *dev) -{ - /* Clear GPIO outputs */ - tw_writel(TW68_GPOE, 0); - /* Remainder of setup according to board ID */ - switch (dev->board) { - case TW68_BOARD_UNKNOWN: - printk(KERN_INFO "%s: Unable to determine board type, " - "using generic values\n", dev->name); - break; - } - dev->input = dev->hw_input = &card_in(dev,0); - return 0; -} - -int tw68_tuner_setup(struct tw68_dev *dev) -{ - return 0; -} - -/* stuff which needs working i2c */ -int tw68_board_init2(struct tw68_dev *dev) -{ - return 0; -} - - diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 2c5d7a5f3f8e..baf93af1d764 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -9,7 +9,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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,10 +24,6 @@ * 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 @@ -44,320 +44,44 @@ #include "tw68-reg.h" MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); -MODULE_AUTHOR("William M. Brack "); +MODULE_AUTHOR("William M. Brack"); +MODULE_AUTHOR("Hans Verkuil "); MODULE_LICENSE("GPL"); -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -static unsigned int gpio_tracking; -module_param(gpio_tracking, int, 0644); -MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); - -static unsigned int alsa = 1; -module_param(alsa, int, 0644); -MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); - static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency, "pci latency timer"); -static unsigned int nocomb; -module_param(nocomb, int, 0644); -MODULE_PARM_DESC(nocomb, "disable comb filter"); - static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; - module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - MODULE_PARM_DESC(video_nr, "video device number"); -MODULE_PARM_DESC(vbi_nr, "vbi device number"); -MODULE_PARM_DESC(radio_nr, "radio device number"); -MODULE_PARM_DESC(tuner, "tuner type"); -MODULE_PARM_DESC(card, "card type"); - -LIST_HEAD(tw68_devlist); -EXPORT_SYMBOL(tw68_devlist); -DEFINE_MUTEX(tw68_devlist_lock); -EXPORT_SYMBOL(tw68_devlist_lock); -static LIST_HEAD(mops_list); -static unsigned int tw68_devcount; /* curr tot num of devices present */ -int (*tw68_dmasound_init)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_init); -int (*tw68_dmasound_exit)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_exit); +static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); -#define dprintk(level, fmt, arg...) if (core_debug & (level)) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +static atomic_t tw68_instance = ATOMIC_INIT(0); /* ------------------------------------------------------------------ */ -void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - BUG_ON(in_interrupt()); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) - videobuf_waiton(&buf->vb, 0, 0); -#else - videobuf_waiton(q, &buf->vb, 0, 0); -#endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) - videobuf_dma_unmap(q, dma); -#else - videobuf_dma_unmap(q->dev, dma); -#endif - videobuf_dma_free(dma); - /* if no risc area allocated, btcx_riscmem_free just returns */ - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -/* ------------------------------------------------------------------ */ -/* ------------- placeholders for later development ----------------- */ - -static int tw68_input_init1(struct tw68_dev *dev) -{ - return 0; -} - -static void tw68_input_fini(struct tw68_dev *dev) -{ - return; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) -{ - return; -} - -static void tw68_ir_stop(struct tw68_dev *dev) -{ - return; -} -#endif - -/* ------------------------------------------------------------------ */ /* - * Buffer handling routines - * - * These routines are "generic", i.e. are intended to be used by more - * than one module, e.g. the video and the transport stream modules. - * To accomplish this generality, callbacks are used whenever some - * module-specific test or action is required. + * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps + * the PCI ID database up to date. Note that the entries must be + * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ - -/* resends a current buffer in queue after resume */ -int tw68_buffer_requeue(struct tw68_dev *dev, - struct tw68_dmaqueue *q) -{ - struct tw68_buf *buf, *prev; - - dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, - buf, buf->vb.i); - q->start_dma(dev, q, buf); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); - /* if nothing precedes this one */ - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); - buf->activate(dev, buf, NULL); - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - - } else if (q->buf_compat(prev, buf) && - (prev->fmt == buf->fmt)) { - list_move_tail(&buf->vb.queue, &q->active); - buf->activate(dev, buf, NULL); - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", - __func__, buf, buf->vb.i); - } else { - dprintk(DBG_BUFF, "%s: no action taken\n", __func__); - return 0; - } - prev = buf; - } -} - -/* nr of (tw68-)pages for the given buffer size */ -static int tw68_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - -/* calc max # of buffers from size (must not exceed the 4MB virtual - * address space per DMA channel) */ -int tw68_buffer_count(unsigned int size, unsigned int count) -{ - unsigned int maxcount; - - maxcount = 1024 / tw68_buffer_pages(size); - if (count > maxcount) - count = maxcount; - return count; -} - -/* - * tw68_wakeup - * - * Called when the driver completes filling a buffer, and tasks waiting - * for the data need to be awakened. - */ -void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) -{ - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (list_empty(&q->active)) { - dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", - __func__); - del_timer(&q->timeout); - return; - } - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - do_gettimeofday(&buf->vb.ts); - buf->vb.field_count = (*fc)++; - dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", - __func__, buf, buf->vb.i, *fc); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); -} - -/* - * tw68_buffer_queue - * - * Add specified buffer to specified queue - */ -void tw68_buffer_queue(struct tw68_dev *dev, - struct tw68_dmaqueue *q, - struct tw68_buf *buf) -{ - struct tw68_buf *prev; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - assert_spin_locked(&dev->slock); - dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); - - /* append a 'JUMP to stopper' to the buffer risc program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - - /* if this buffer is not "compatible" (in dimensions and format) - * with the currently active chain of buffers, we must change - * settings before filling it; if a previous buffer has already - * been determined to require changes, this buffer must follow - * it. To do this, we maintain a "queued" chain. If that - * chain exists, append this buffer to it */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", - __func__, buf, buf->vb.i); - - /* else if the 'active' chain doesn't yet exist we create it now */ - } else if (list_empty(&q->active)) { - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - list_add_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); /* 1st one - start dma */ - /* TODO - why have we removed buf->count and q->count? */ - buf->activate(dev, buf, NULL); - - /* else we would like to put this buffer on the tail of the - * active chain, provided it is "compatible". */ - } else { - /* "compatibility" depends upon the type of buffer */ - prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); - if (q->buf_compat(prev, buf)) { - /* If "compatible", append to active chain */ - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* the param 'prev' is only for debug printing */ - buf->activate(dev, buf, prev); - list_add_tail(&buf->vb.queue, &q->active); - dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", - __func__, buf, buf->vb.i); - } else { - /* If "incompatible", append to queued chain */ - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " - "to queued\n", __func__, buf, buf->vb.i); - } - } -} - -/* - * tw68_buffer_timeout - * - * This routine is set as the video_q.timeout.function - * - * Log the event, try to reset the h/w. - * Flag the current buffer as failed, try to start again with next buff - */ -void tw68_buffer_timeout(unsigned long data) -{ - struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - unsigned long flags; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - spin_lock_irqsave(&dev->slock, flags); - - /* flag all current active buffers as failed */ - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - tw68_buffer_requeue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} +struct pci_device_id tw68_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)}, + {0,} +}; /* ------------------------------------------------------------------ */ -/* early init (no i2c, no irq) */ -/* Called from tw68_hw_init1 and tw68_resume */ -static int tw68_hw_enable1(struct tw68_dev *dev) -{ - return 0; -} /* * The device is given a "soft reset". According to the specifications, @@ -367,7 +91,6 @@ static int tw68_hw_enable1(struct tw68_dev *dev) */ static int tw68_hw_init1(struct tw68_dev *dev) { - dprintk(DBG_FLOW, "%s: called\n", __func__); /* Assure all interrupts are disabled */ tw_writel(TW68_INTMASK, 0); /* 020 */ /* Clear any pending interrupts */ @@ -415,7 +138,7 @@ static int tw68_hw_init1(struct tw68_dev *dev) tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ -// tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ +/* tw_writeb(TW68_SYNCT, 0x38);*/ /* 294 Sync amplitude */ tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ @@ -465,80 +188,9 @@ static int tw68_hw_init1(struct tw68_dev *dev) /* Initialize any subsystems */ tw68_video_init1(dev); - tw68_vbi_init1(dev); - if (card_has_mpeg(dev)) - tw68_ts_init1(dev); - tw68_input_init1(dev); - - /* Do any other h/w early initialisation at this point */ - tw68_hw_enable1(dev); - - return 0; -} - -/* late init (with i2c + irq) */ -static int tw68_hw_enable2(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_I2C_INTS; -#endif - tw_setl(TW68_INTMASK, dev->pci_irqmask); return 0; } -static int tw68_hw_init2(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - tw68_video_init2(dev); /* initialise video function first */ - tw68_tvaudio_init2(dev);/* audio next */ - - /* all other board-related things, incl. enabling interrupts */ - tw68_hw_enable2(dev); - return 0; -} - -/* shutdown */ -static int tw68_hwfini(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (card_has_mpeg(dev)) - tw68_ts_fini(dev); - tw68_input_fini(dev); - tw68_vbi_fini(dev); - tw68_tvaudio_fini(dev); - return 0; -} - -static void __devinit must_configure_manually(void) -{ - unsigned int i, p; - - printk(KERN_WARNING - "tw68: \n" - "tw68: Congratulations! Your TV card vendor saved a few\n" - "tw68: cents for a eeprom, thus your pci board has no\n" - "tw68: subsystem ID and I can't identify it automatically\n" - "tw68: \n" - "tw68: I feel better now. Ok, here is the good news:\n" - "tw68: You can use the card= insmod option to specify\n" - "tw68: which board you have. The list:\n"); - for (i = 0; i < tw68_bcount; i++) { - printk(KERN_WARNING "tw68: card=%d -> %-40.40s", - i, tw68_boards[i].name); - for (p = 0; tw68_pci_tbl[p].driver_data; p++) { - if (tw68_pci_tbl[p].driver_data != i) - continue; - printk(" %04x:%04x", - tw68_pci_tbl[p].subvendor, - tw68_pci_tbl[p].subdevice); - } - printk("\n"); - } -} - - static irqreturn_t tw68_irq(int irq, void *dev_id) { struct tw68_dev *dev = dev_id; @@ -548,126 +200,39 @@ static irqreturn_t tw68_irq(int irq, void *dev_id) status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; /* Check if anything to do */ if (0 == status) - return IRQ_RETVAL(0); /* Nope - return */ + return IRQ_NONE; /* Nope - return */ for (loop = 0; loop < 10; loop++) { if (status & dev->board_virqmask) /* video interrupt */ tw68_irq_video_done(dev, status); -#ifdef TW68_TESTING - if (status & TW68_I2C_INTS) - tw68_irq_i2c(dev, status); -#endif status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; if (0 == status) - goto out; + return IRQ_HANDLED; } - dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" - " (orig 0x%08x, cur 0x%08x)", - dev->name, orig, tw_readl(TW68_INTSTAT)); - dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " - "0x%08x ****\n", dev->name, - dev->pci_irqmask, dev->board_virqmask); + dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)", + dev->name, orig, tw_readl(TW68_INTSTAT)); + dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n", + dev->name, dev->pci_irqmask, dev->board_virqmask); tw_clearl(TW68_INTMASK, dev->pci_irqmask); -out: - return IRQ_RETVAL(1); -} - -int tw68_set_dmabits(struct tw68_dev *dev) -{ - return 0; -} - -static struct video_device *vdev_init(struct tw68_dev *dev, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->parent = &dev->pci->dev; - vfd->release = video_device_release; - /* vfd->debug = tw_video_debug; */ - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, tw68_boards[dev->board].name); - return vfd; + return IRQ_HANDLED; } -static void tw68_unregister_video(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (dev->video_dev) { - if (-1 != dev->video_dev->minor) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } - if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } -} - -static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - int err; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (NULL != dev->mops) - return; - if (tw68_boards[dev->board].mpeg != ops->type) - return; - err = ops->init(dev); - if (0 != err) - return; - dev->mops = ops; -} - -static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - - if (NULL == dev->mops) - return; - if (dev->mops != ops) - return; - dev->mops->fini(dev); - dev->mops = NULL; -} - -static int __devinit tw68_initdev(struct pci_dev *pci_dev, +static int tw68_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct tw68_dev *dev; - struct tw68_mpeg_ops *mops; + int vidnr = -1; int err; - if (tw68_devcount == TW68_MAXBOARDS) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; + dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68", + &tw68_instance); + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); if (err) - goto fail0; + return err; /* pci init */ dev->pci = pci_dev; @@ -676,33 +241,10 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, goto fail1; } - dev->nr = tw68_devcount; - sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); + dev->name = dev->v4l2_dev.name; - /* pci quirks */ - if (pci_pci_problems) { - if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", - dev->name); - if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", - dev->name); - if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", - dev->name); - if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", - dev->name); -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " - "-- latency fixup\n", dev->name); - latency = 0x0A; - } -#endif - } if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", + pr_info("%s: setting pci latency timer to %d\n", dev->name, latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } @@ -710,13 +252,12 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, - (unsigned long long)pci_resource_start(pci_dev, 0)); + pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); + pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail1; } @@ -730,7 +271,7 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->vdecoder = TW6801; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; - case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ + case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */ dev->vdecoder = TW6804; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; @@ -739,35 +280,13 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; } - /* board config */ - dev->board = pci_id->driver_data; - if (card[dev->nr] >= 0 && - card[dev->nr] < tw68_bcount) - dev->board = card[dev->nr]; - if (TW68_BOARD_NOAUTO == dev->board) { - must_configure_manually(); - dev->board = TW68_BOARD_UNKNOWN; - } - dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = tw68_boards[dev->board].tuner_type; - dev->tuner_addr = tw68_boards[dev->board].tuner_addr; - dev->radio_type = tw68_boards[dev->board].radio_type; - dev->radio_addr = tw68_boards[dev->board].radio_addr; - dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; - if (UNSET != tuner[dev->nr]) - dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, pci_dev->subsystem_vendor, - pci_dev->subsystem_device, tw68_boards[dev->board].name, - dev->board, dev->autodetected ? - "autodetected" : "insmod option"); /* get mmio */ if (!request_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0), dev->name)) { err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + pr_err("%s: can't get MMIO memory @ 0x%llx\n", dev->name, (unsigned long long)pci_resource_start(pci_dev, 0)); goto fail1; @@ -777,185 +296,75 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + pr_err("%s: can't ioremap() MMIO memory\n", dev->name); goto fail2; } /* initialize hardware #1 */ - /* First, take care of anything unique to a particular card */ - tw68_board_init1(dev); /* Then do any initialisation wanted before interrupts are on */ tw68_hw_init1(dev); /* get irq */ - err = request_irq(pci_dev->irq, tw68_irq, + err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); goto fail3; } -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_SBDONE; - tw_setl(TW68_INTMASK, dev->pci_irqmask); - printk(KERN_INFO "Calling tw68_i2c_register\n"); - /* Register the i2c bus */ - tw68_i2c_register(dev); -#endif - /* * Now do remainder of initialisation, first for * things unique for this card, then for general board */ - tw68_board_init2(dev); - - tw68_hw_init2(dev); - -#if 0 - /* load i2c helpers */ - if (card_is_empress(dev)) { - struct v4l2_subdev *sd = - v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", - "saa6752hs", 0x20); - - if (sd) - sd->grp_id = GRP_EMPRESS; - } - - request_submodules(dev); -#endif - - v4l2_prio_init(&dev->prio); - - mutex_lock(&tw68_devlist_lock); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_attach(mops, dev); - list_add_tail(&dev->devlist, &tw68_devlist); - mutex_unlock(&tw68_devlist_lock); - - /* check for signal */ - tw68_irq_video_signalchange(dev); - -#if 0 - if (TUNER_ABSENT != dev->tuner_type) - tw_call_all(dev, core, s_standby, 0); -#endif - - dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); - err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, - video_nr[dev->nr]); + if (dev->instance < TW68_MAXBOARDS) + vidnr = video_nr[dev->instance]; + /* initialise video function first */ + err = tw68_video_init2(dev, vidnr); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_err("%s: can't register video device\n", dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->num); - - dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); - - err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register vbi device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device vbi%d\n", - dev->name, dev->vbi_dev->num); - - if (card_has_radio(dev)) { - dev->radio_dev = vdev_init(dev, &tw68_radio_template, - "radio"); - err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->nr]); - if (err < 0) { - /* TODO - need to unregister vbi? */ - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device radio%d\n", - dev->name, dev->radio_dev->num); - } - - /* everything worked */ - tw68_devcount++; + tw_setl(TW68_INTMASK, dev->pci_irqmask); - if (tw68_dmasound_init && !dev->dmasound.priv_data) - tw68_dmasound_init(dev); + pr_info("%s: registered device %s\n", + dev->name, video_device_node_name(&dev->vdev)); return 0; - fail4: - tw68_unregister_video(dev); -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - free_irq(pci_dev->irq, dev); - fail3: - tw68_hwfini(dev); +fail4: + video_unregister_device(&dev->vdev); +fail3: iounmap(dev->lmmio); - fail2: +fail2: release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); - fail1: +fail1: v4l2_device_unregister(&dev->v4l2_dev); - fail0: - kfree(dev); return err; } -static void __devexit tw68_finidev(struct pci_dev *pci_dev) +static void tw68_finidev(struct pci_dev *pci_dev) { struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - struct tw68_mpeg_ops *mops; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - /* Release DMA sound modules if present */ - if (tw68_dmasound_exit && dev->dmasound.priv_data) - tw68_dmasound_exit(dev); /* shutdown subsystems */ - tw68_hwfini(dev); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); tw_writel(TW68_INTMASK, 0); /* unregister */ - mutex_lock(&tw68_devlist_lock); - list_del(&dev->devlist); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_detach(mops, dev); - mutex_unlock(&tw68_devlist_lock); - tw68_devcount--; - -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - tw68_unregister_video(dev); - - - /* the DMA sound modules should be unloaded before reaching - this, but just in case they are still present... */ - if (dev->dmasound.priv_data != NULL) { - free_irq(pci_dev->irq, &dev->dmasound); - dev->dmasound.priv_data = NULL; - } - + video_unregister_device(&dev->vdev); + v4l2_ctrl_handler_free(&dev->hdl); /* release resources */ - free_irq(pci_dev->irq, dev); iounmap(dev->lmmio); release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); v4l2_device_unregister(&dev->v4l2_dev); - - /* free memory */ - kfree(dev); } #ifdef CONFIG_PM @@ -966,28 +375,15 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - dprintk(DBG_FLOW, "%s: called\n", __func__); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask &= ~TW68_VID_INTS; tw_writel(TW68_INTMASK, 0); - dev->insuspend = 1; synchronize_irq(pci_dev->irq); - /* Disable timeout timers - if we have active buffers, we will - fill them on resume*/ - - del_timer(&dev->video_q.timeout); - del_timer(&dev->vbi_q.timeout); - del_timer(&dev->ts_q.timeout); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_stop(dev); -#endif - pci_save_state(pci_dev); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + vb2_discard_done(&dev->vidq); return 0; } @@ -997,54 +393,25 @@ static int tw68_resume(struct pci_dev *pci_dev) struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); + struct tw68_buf *buf; unsigned long flags; - dprintk(DBG_FLOW, "%s: called\n", __func__); pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); /* Do things that are done in tw68_initdev , except of initializing memory structures.*/ - tw68_board_init1(dev); - - /* tw68_hw_init1 */ - if (tw68_boards[dev->board].video_out) - tw68_videoport_init(dev); - if (card_has_mpeg(dev)) - tw68_ts_init_hw(dev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_start(dev, dev->remote); -#endif - tw68_hw_enable1(dev); - msleep(100); - tw68_board_init2(dev); - - /*tw68_hw_init2*/ tw68_set_tvnorm_hw(dev); - tw68_tvaudio_setmute(dev); -/* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ - tw68_tvaudio_init(dev); - tw68_irq_video_signalchange(dev); /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); - tw68_buffer_requeue(dev, &dev->video_q); - tw68_buffer_requeue(dev, &dev->vbi_q); - tw68_buffer_requeue(dev, &dev->ts_q); - - /* FIXME: Disable DMA audio sound - temporary till proper support - is implemented*/ + buf = container_of(dev->active.next, struct tw68_buf, list); - dev->dmasound.dma_running = 0; + tw68_video_start_dma(dev, buf); - /* start DMA now*/ - dev->insuspend = 0; - smp_wmb(); - tw68_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); return 0; @@ -1057,35 +424,11 @@ static struct pci_driver tw68_pci_driver = { .name = "tw68", .id_table = tw68_pci_tbl, .probe = tw68_initdev, - .remove = __devexit_p(tw68_finidev), + .remove = tw68_finidev, #ifdef CONFIG_PM .suspend = tw68_suspend, .resume = tw68_resume #endif }; -static int tw68_init(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - INIT_LIST_HEAD(&tw68_devlist); - printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", - (TW68_VERSION_CODE >> 16) & 0xff, - (TW68_VERSION_CODE >> 8) & 0xff, - TW68_VERSION_CODE & 0xff); -#if 0 - printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&tw68_pci_driver); -} - -static void module_cleanup(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - pci_unregister_driver(&tw68_pci_driver); -} - -module_init(tw68_init); -module_exit(module_cleanup); +module_pci_driver(tw68_pci_driver); diff --git a/drivers/media/pci/tw68/tw68-i2c.c b/drivers/media/pci/tw68/tw68-i2c.c deleted file mode 100644 index 38659d0b1e18..000000000000 --- a/drivers/media/pci/tw68/tw68-i2c.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * tw68 code to handle the i2c interface. - * - * Much of this code is derived from the bt87x driver. The original - * work was by Gerd Knorr; more recently the code was enhanced by Mauro - * Carvalho Chehab. Their work is gratefully acknowledged. Full credit - * goes to them - any problems within this code are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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 -#include -#include -#include -#include - -#include "tw68.h" -#include -#include - -/*----------------------------------------------------------------*/ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#if 0 -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#endif - -#define d1printk if (1 == i2c_debug) printk - -#define I2C_CLOCK 0xa6 /* 99.4 kHz */ - -/*----------------------------------------------------------------------*/ -/* Although the TW68xx i2c controller has a "hardware" mode, where all of - * the low-level i2c/smbbus is handled by the chip, it appears that mode - * is not suitable for linux i2c handling routines because extended "bursts" - * of data (sequences of bytes without intervening START/STOP bits) are - * not possible. Instead, we put the chip into "software" mode, and handle - * the i2c bus at a low level. To accomplish this, we use the routines - * from the i2c modules. - * - * Because the particular boards which I had for testing did not have any - * devices attached to the i2c bus, I have been unable to test these - * routines. - */ - -/*----------------------------------------------------------------------*/ -/* I2C functions - "bit-banging" adapter (software i2c) */ - -/* tw68_bit_setcl - * Handles "toggling" the i2c clock bit - */ -static void tw68_bit_setscl(void *data, int state) -{ - struct tw68_dev *dev = data; - - tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B); -} - -/* tw68_bit_setsda - * Handles "toggling" the i2c data bit - */ -static void tw68_bit_setsda(void *data, int state) -{ - struct tw68_dev *dev = data; - - tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B); -} - -/* tw68_bit_getscl - * - * Returns the current state of the clock bit - */ -static int tw68_bit_getscl(void *data) -{ - struct tw68_dev *dev = data; - - return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0; -} - -/* tw68_bit_getsda - * - * Returns the current state of the data bit - */ -static int tw68_bit_getsda(void *data) -{ - struct tw68_dev *dev = data; - - return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0; -} - -static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = { - .setsda = tw68_bit_setsda, - .setscl = tw68_bit_setscl, - .getsda = tw68_bit_getsda, - .getscl = tw68_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -static struct i2c_client tw68_client_template = { - .name = "tw68 internal", -}; - -/*----------------------------------------------------------------*/ - -static int attach_inform(struct i2c_client *client) -{ -/* struct tw68_dev *dev = client->adapter->algo_data; */ - - d1printk("%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, client->name); - - switch (client->addr) { - /* No info yet on what addresses to expect */ - } - - return 0; -} - -static struct i2c_adapter tw68_adap_sw_template = { - .owner = THIS_MODULE, - .name = "tw68_sw", - .client_register = attach_inform, -}; - -static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata, - int len) -{ - unsigned char buf; - int i, err; - - dev->i2c_client.addr = 0xa0 >> 1; - buf = 256 - len; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (1 != err) { - printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n", - dev->name, err); - return -1; - } - err = i2c_master_recv(&dev->i2c_client, eedata, len); - if (len != err) { - printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", - dev->name, err); - return -1; - } - - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", - dev->name, i); - printk(KERN_INFO " %02x", eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - return 0; -} - -#if 0 -static char *i2c_devs[128] = { - [0xa0 >> 1] = "eeprom", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i, rc; - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 1); - if (rc < 0) - continue; - printk(KERN_INFO "%s: i2c scan: found device " - "@ 0x%x [%s]\n", name, i << 1, - i2c_devs[i] ? i2c_devs[i] : "???"); - } -} -#endif - -int __devinit tw68_i2c_register(struct tw68_dev *dev) -{ - int rc; - -printk(KERN_DEBUG "%s: Registering i2c module\n", __func__); - tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */ - - memcpy(&dev->i2c_client, &tw68_client_template, - sizeof(tw68_client_template)); - - memcpy(&dev->i2c_adap, &tw68_adap_sw_template, - sizeof(tw68_adap_sw_template)); - dev->i2c_adap.algo_data = &dev->i2c_algo; - dev->i2c_adap.dev.parent = &dev->pci->dev; - - memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template, - sizeof(tw68_i2c_algo_bit_template)); - dev->i2c_algo.data = dev; - /* TODO - may want to set better name (see bttv code) */ - - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - dev->i2c_client.adapter = &dev->i2c_adap; - - /* Assure chip is in "software" mode */ - tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK); - tw68_bit_setscl(dev, 1); - tw68_bit_setsda(dev, 1); - - rc = i2c_bit_add_bus(&dev->i2c_adap); - - tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); -#if 0 - if (i2c_scan) - do_i2c_scan(dev->name, &dev->i2c_client); -#endif - - return rc; -} - -int tw68_i2c_unregister(struct tw68_dev *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h index 314bc43cd9d3..f60b3a896fa7 100644 --- a/drivers/media/pci/tw68/tw68-reg.h +++ b/drivers/media/pci/tw68/tw68-reg.h @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) William M. Brack + * Copyright (C) William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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,10 +23,6 @@ * 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 _TW68_REG_H_ diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c index 66273bbd51c5..7439db212a69 100644 --- a/drivers/media/pci/tw68/tw68-risc.c +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -9,7 +9,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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,16 +24,10 @@ * 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 "tw68.h" -#define NO_SYNC_LINE (-1U) - /** * @rp pointer to current risc program position * @sglist pointer to "scatter-gather list" of buffer pointers @@ -38,32 +36,35 @@ * @bpl number of bytes per scan line * @padding number of bytes of padding to add * @lines number of lines in field - * @lpi lines per IRQ, or 0 to not generate irqs - * Note: IRQ to be generated _after_ lpi lines are transferred + * @jump insert a jump at the start */ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) + unsigned int lines, bool jump) { struct scatterlist *sg; unsigned int line, todo, done; - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) { - if (sync_line == 1) - *(rp++) = cpu_to_le32(RISC_SYNCO); - else - *(rp++) = cpu_to_le32(RISC_SYNCE); + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); *(rp++) = 0; } + + /* sync instruction */ + if (sync_line == 1) + *(rp++) = cpu_to_le32(RISC_SYNCO); + else + *(rp++) = cpu_to_le32(RISC_SYNCE); + *(rp++) = 0; + /* scan lines */ sg = sglist; for (line = 0; line < lines; line++) { /* calculate next starting position */ while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); } if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ @@ -86,7 +87,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, done); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); todo -= done; - sg++; + sg = sg_next(sg); /* succeeding fragments have no offset */ while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_INLINE | @@ -94,7 +95,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); todo -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); done += sg_dma_len(sg); } if (todo) { @@ -107,9 +108,6 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, offset = todo; } offset += padding; - /* If this line needs an interrupt, put it in */ - if (lpi && line > 0 && !(line % lpi)) - *(rp-2) |= RISC_INT_BIT; } return rp; @@ -118,25 +116,25 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, /** * tw68_risc_buffer * - * This routine is called by tw68-video. It allocates - * memory for the dma controller "program" and then fills in that - * memory with the appropriate "instructions". + * This routine is called by tw68-video. It allocates + * memory for the dma controller "program" and then fills in that + * memory with the appropriate "instructions". * - * @pci_dev structure with info about the pci - * slot which our device is in. - * @risc structure with info about the memory - * used for our controller program. - * @sglist scatter-gather list entry - * @top_offset offset within the risc program area for the - * first odd frame line - * @bottom_offset offset within the risc program area for the - * first even frame line - * @bpl number of data bytes per scan line - * @padding number of extra bytes to add at end of line - * @lines number of scan lines + * @pci_dev structure with info about the pci + * slot which our device is in. + * @risc structure with info about the memory + * used for our controller program. + * @sglist scatter-gather list entry + * @top_offset offset within the risc program area for the + * first odd frame line + * @bottom_offset offset within the risc program area for the + * first even frame line + * @bpl number of data bytes per scan line + * @padding number of extra bytes to add at end of line + * @lines number of scan lines */ int tw68_risc_buffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct tw68_buf *buf, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, @@ -146,7 +144,6 @@ int tw68_risc_buffer(struct pci_dev *pci, { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -155,29 +152,31 @@ int tw68_risc_buffer(struct pci_dev *pci, fields++; /* * estimate risc mem: worst case is one write per page border + - * one write per scan line + syncs + jump (all 2 dwords). + * one write per scan line + syncs + 2 jumps (all 2 dwords). * Padding can cause next bpl to start close to a page border. * First DMA region may be smaller than PAGE_SIZE */ instructions = fields * (1 + (((bpl + padding) * lines) / - PAGE_SIZE) + lines) + 2; - rc = btcx_riscmem_alloc(pci, risc, instructions * 8); - if (rc < 0) - return rc; + PAGE_SIZE) + lines) + 4; + buf->size = instructions * 8; + buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma); + if (buf->cpu == NULL) + return -ENOMEM; /* write risc instructions */ - rp = risc->cpu; + rp = buf->cpu; if (UNSET != top_offset) /* generates SYNCO */ rp = tw68_risc_field(rp, sglist, top_offset, 1, - bpl, padding, lines, 0); + bpl, padding, lines, true); if (UNSET != bottom_offset) /* generates SYNCE */ rp = tw68_risc_field(rp, sglist, bottom_offset, 2, - bpl, padding, lines, 0); + bpl, padding, lines, top_offset == UNSET); /* save pointer to jmp instruction address */ - risc->jmp = rp; + buf->jmp = rp; + buf->cpu[1] = cpu_to_le32(buf->dma + 8); /* assure risc buffer hasn't overflowed */ - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size); return 0; } @@ -204,65 +203,28 @@ static void tw68_risc_decode(u32 risc, u32 addr) p = RISC_OP(risc); if (!(risc & 0x80000000) || !instr[p].name) { - printk(KERN_DEBUG "0x%08x [ INVALID ]\n", risc); + pr_debug("0x%08x [ INVALID ]\n", risc); return; } - printk(KERN_DEBUG "0x%08x %-9s IRQ=%d", + pr_debug("0x%08x %-9s IRQ=%d", risc, instr[p].name, (risc >> 27) & 1); if (instr[p].has_data_type) - printk(KERN_DEBUG " Type=%d", (risc >> 24) & 7); + pr_debug(" Type=%d", (risc >> 24) & 7); if (instr[p].has_byte_info) - printk(KERN_DEBUG " Start=0x%03x Count=%03u", + pr_debug(" Start=0x%03x Count=%03u", (risc >> 12) & 0xfff, risc & 0xfff); if (instr[p].has_addr) - printk(KERN_DEBUG " StartAddr=0x%08x", addr); - printk(KERN_DEBUG "\n"); + pr_debug(" StartAddr=0x%08x", addr); + pr_debug("\n"); } -void tw68_risc_program_dump(struct tw68_core *core, - struct btcx_riscmem *risc) +void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf) { - __le32 *addr; + const __le32 *addr; - printk(KERN_DEBUG "%s: risc_program_dump: risc=%p, " - "risc->cpu=0x%p, risc->jmp=0x%p\n", - core->name, risc, risc->cpu, risc->jmp); - for (addr = risc->cpu; addr <= risc->jmp; addr += 2) + pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n", + core->name, buf, buf->cpu, buf->jmp); + for (addr = buf->cpu; addr <= buf->jmp; addr += 2) tw68_risc_decode(*addr, *(addr+1)); } -EXPORT_SYMBOL_GPL(tw68_risc_program_dump); #endif - -/* - * tw68_risc_stopper - * Normally, the risc code generated for a buffer ends with a - * JUMP instruction to direct the DMAP processor to the code for - * the next buffer. However, when there is no additional buffer - * currently available, the code instead jumps to this routine. - * - * My first try for a "stopper" program was just a simple - * "jump to self" instruction. Unfortunately, this caused the - * video FIFO to overflow. My next attempt was to just disable - * the DMAP processor. Unfortunately, this caused the video - * decoder to lose its synchronization. The solution to this was to - * add a "Sync-Odd" instruction, which "eats" all the video data - * until the start of the next odd field. - */ -int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 8*4); - if (rc < 0) - return rc; - - /* write risc inststructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_SYNCO); - *(rp++) = 0; - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - risc->jmp = risc->cpu; - return 0; -} diff --git a/drivers/media/pci/tw68/tw68-ts.c b/drivers/media/pci/tw68/tw68-ts.c deleted file mode 100644 index dacd6e621bae..000000000000 --- a/drivers/media/pci/tw68/tw68-ts.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * tw68_ts.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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 "tw68.h" - -int tw68_ts_init1(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_ts_ini(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_ts_fini(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status) -{ - return; -} - -int tw68_ts_register(struct tw68_mpeg_ops *ops) -{ - return 0; -} - -void tw68_ts_unregister(struct tw68_mpeg_ops *ops) -{ - return; -} - -int tw68_ts_init_hw(struct tw68_dev *dev) -{ - return 0; -} - - diff --git a/drivers/media/pci/tw68/tw68-tvaudio.c b/drivers/media/pci/tw68/tw68-tvaudio.c deleted file mode 100644 index 656d462196f4..000000000000 --- a/drivers/media/pci/tw68/tw68-tvaudio.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * tw68_controls.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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 "tw68.h" - -int tw68_tvaudio_rx2mode(u32 rx) -{ - return 0; -} - -void tw68_tvaudio_setmute(struct tw68_dev *dev) -{ - return; -} - -void tw68_tvaudio_setinput(struct tw68_dev *dev, struct tw68_input *in) -{ - return; -} - -void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level) -{ - return; -} - -int tw68_tvaudio_getstereo(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_tvaudio_init(struct tw68_dev *dev) -{ - return; -} - -int tw68_tvaudio_init2(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_tvaudio_fini(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_tvaudio_do_scan(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_enable_i2s(struct tw68_dev *dev) -{ - return; -} - diff --git a/drivers/media/pci/tw68/tw68-vbi.c b/drivers/media/pci/tw68/tw68-vbi.c deleted file mode 100644 index fbad3b998848..000000000000 --- a/drivers/media/pci/tw68/tw68-vbi.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * tw68_controls.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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 "tw68.h" - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) { - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); - return 0; -} -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); - return 0; -} -static void buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); -} -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); -} -struct videobuf_queue_ops tw68_vbi_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -int tw68_vbi_init1(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_vbi_fini(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status) -{ - return; -} - diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index ca08ca38d3bd..66fae2345fdd 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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,39 +23,16 @@ * 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 -#include +#include +#include #include "tw68.h" #include "tw68-reg.h" -unsigned int video_debug; - -static unsigned int gbuffers = 8; -static unsigned int noninterlaced; /* 0 */ -static unsigned int gbufsz = 768*576*4; -static unsigned int gbufsz_max = 768*576*4; -static char secam[] = "--"; - -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers, "number of capture buffers, range 2-32"); -module_param(noninterlaced, int, 0644); -MODULE_PARM_DESC(noninterlaced, "capture non interlaced video"); -module_param_string(secam, secam, sizeof(secam), 0644); -MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); - -#define dprintk(level, fmt, arg...) if (video_debug & (level)) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) - /* ------------------------------------------------------------------ */ /* data structs for video */ /* @@ -60,7 +41,7 @@ MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); * as "planar". These affect overlay mode, and are flagged with a field * ".planar" in the format. Do we need to implement this in this driver? */ -static struct tw68_format formats[] = { +static const struct tw68_format formats[] = { { .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, @@ -145,47 +126,8 @@ static struct tw68_format formats[] = { * match, then for an entry which contains the desired id. The table * entries should therefore be ordered in ascending order of specificity. */ -static struct tw68_tvnorm tvnorms[] = { +static const struct tw68_tvnorm tvnorms[] = { { - .name = "PAL-BG", - .id = V4L2_STD_PAL_BG, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { - .name = "PAL-I", - .id = V4L2_STD_PAL_I, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { - .name = "PAL-DK", - .id = V4L2_STD_PAL_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { .name = "PAL", /* autodetect */ .id = V4L2_STD_PAL, NORM_625_50, @@ -197,7 +139,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPALBDGHI, - }, { .name = "NTSC", .id = V4L2_STD_NTSC, @@ -210,46 +151,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x0e, .vgate_misc = 0x18, .format = VideoFormatNTSC, - - }, { - .name = "SECAM-DK", - .id = V4L2_STD_SECAM_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - - }, { - .name = "SECAM-L", - .id = V4L2_STD_SECAM_L, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - - }, { - .name = "SECAM-LC", - .id = V4L2_STD_SECAM_LC, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - }, { .name = "SECAM", .id = V4L2_STD_SECAM, @@ -262,7 +163,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x00, .vgate_misc = 0x1c, .format = VideoFormatSECAM, - }, { .name = "PAL-M", .id = V4L2_STD_PAL_M, @@ -275,7 +175,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x0e, .vgate_misc = 0x18, .format = VideoFormatPALM, - }, { .name = "PAL-Nc", .id = V4L2_STD_PAL_Nc, @@ -288,7 +187,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPALNC, - }, { .name = "PAL-60", .id = V4L2_STD_PAL_60, @@ -309,127 +207,11 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPAL60, - - }, { -/* - * FIXME: The following are meant to be "catch-all", and need - * to be further thought out! - */ - .name = "STD-525-60", - .id = V4L2_STD_525_60, - NORM_525_60, - - .sync_control = 0x59, - .luma_control = 0x40, - .chroma_ctrl1 = 0x89, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x0e, - .vgate_misc = 0x18, - .format = VideoFormatNTSC, - - }, { - .name = "STD-625-50", - .id = V4L2_STD_625_50, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, } }; #define TVNORMS ARRAY_SIZE(tvnorms) -static const struct v4l2_queryctrl no_ctrl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl video_ctrls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 20, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 100, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_COLOR_KILLER, - .name = "Color Killer", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_CHROMA_AGC, - .name = "Chroma AGC", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - /* --- 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 = -15, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; -static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); - -/* - * Routine to lookup a control by its ID, and return a pointer - * to the entry in the video_ctrls array for that control. - */ -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CTRLS; i++) - if (video_ctrls[i].id == id) - return video_ctrls+i; - return NULL; -} - -static struct tw68_format *format_by_fourcc(unsigned int fourcc) +static const struct tw68_format *format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -439,99 +221,22 @@ static struct tw68_format *format_by_fourcc(unsigned int fourcc) return NULL; } -/* ----------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct tw68_fh *fh, unsigned int bit) -{ - struct tw68_dev *dev = fh->dev; - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&fh->dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(DBG_FLOW, "%s: %d\n", __func__, bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct tw68_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct tw68_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct tw68_fh *fh, - unsigned int bits) -{ - struct tw68_dev *dev = fh->dev; - - BUG_ON((fh->resources & bits) != bits); - - mutex_lock(&fh->dev->lock); - fh->resources &= ~bits; - fh->dev->resources &= ~bits; - dprintk(DBG_FLOW, "%s: %d\n", __func__, bits); - mutex_unlock(&fh->dev->lock); -} /* ------------------------------------------------------------------ */ /* * Note that the cropping rectangles are described in terms of a single * frame, i.e. line positions are only 1/2 the interlaced equivalent */ -static void set_tvnorm(struct tw68_dev *dev, struct tw68_tvnorm *norm) +static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm) { - dprintk(DBG_FLOW, "%s: %s\n", __func__, norm->name); - dev->tvnorm = norm; - - /* setup cropping */ - dev->crop_bounds.left = norm->h_start; - dev->crop_defrect.left = norm->h_start; - dev->crop_bounds.width = norm->h_stop - norm->h_start + 1; - dev->crop_defrect.width = norm->h_stop - norm->h_start + 1; - - dev->crop_bounds.top = norm->video_v_start; - dev->crop_defrect.top = norm->video_v_start; - dev->crop_bounds.height = (((norm->id & V4L2_STD_525_60) ? - 524 : 624)) / 2 - dev->crop_bounds.top; - dev->crop_defrect.height = (norm->video_v_stop - - norm->video_v_start + 1); - - dev->crop_current = dev->crop_defrect; - if (norm != dev->tvnorm) { + dev->width = 720; + dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576; dev->tvnorm = norm; tw68_set_tvnorm_hw(dev); } } -static void video_mux(struct tw68_dev *dev, int input) -{ - dprintk(DBG_FLOW, "%s: input = %d [%s]\n", __func__, input, - card_in(dev, input).name); - /* - * dev->input shows current application request, - * dev->hw_input shows current hardware setting - */ - dev->input = &card_in(dev, input); - tw68_tvaudio_setinput(dev, &card_in(dev, input)); -} - /* * tw68_set_scale * @@ -544,7 +249,7 @@ static void video_mux(struct tw68_dev *dev, int input) * before scaling. HDELAY represents the number of pixels skipped * between the start of the horizontal sync and the start of the image. * HSCALE is calculated using the formula - * HSCALE = (HACTIVE / (#pixels desired)) * 256 + * HSCALE = (HACTIVE / (#pixels desired)) * 256 * * The vertical registers are similar, except based upon the total number * of lines in the image, and the first line of the image (i.e. ignoring @@ -555,16 +260,16 @@ static void video_mux(struct tw68_dev *dev, int input) * these values, especially HSCALE. * * Parameters: - * @dev pointer to the device structure, needed for - * getting current norm (as well as debug print) - * @width actual image width (from user buffer) - * @height actual image height - * @field indicates Top, Bottom or Interlaced + * @dev pointer to the device structure, needed for + * getting current norm (as well as debug print) + * @width actual image width (from user buffer) + * @height actual image height + * @field indicates Top, Bottom or Interlaced */ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, unsigned int height, enum v4l2_field field) { - + const struct tw68_tvnorm *norm = dev->tvnorm; /* set individually for debugging clarity */ int hactive, hdelay, hscale; int vactive, vdelay, vscale; @@ -573,41 +278,38 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ height /= 2; /* we must set for 1-frame */ - dprintk(DBG_FLOW, "%s: width=%d, height=%d, both=%d\n Crop rect: " - "top=%d, left=%d, width=%d height=%d\n" - " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " - "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, + pr_debug("%s: width=%d, height=%d, both=%d\n" + " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " + "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, width, height, V4L2_FIELD_HAS_BOTH(field), - dev->crop_bounds.top, dev->crop_bounds.left, - dev->crop_bounds.width, dev->crop_bounds.height, - dev->tvnorm->h_delay, dev->tvnorm->h_start, dev->tvnorm->h_stop, - dev->tvnorm->v_delay, dev->tvnorm->video_v_start, - dev->tvnorm->video_v_stop); + norm->h_delay, norm->h_start, norm->h_stop, + norm->v_delay, norm->video_v_start, + norm->video_v_stop); switch (dev->vdecoder) { case TW6800: - hdelay = dev->tvnorm->h_delay0; + hdelay = norm->h_delay0; break; default: - hdelay = dev->tvnorm->h_delay; + hdelay = norm->h_delay; break; } - hdelay += dev->crop_bounds.left; - hactive = dev->crop_bounds.width; + + hdelay += norm->h_start; + hactive = norm->h_stop - norm->h_start + 1; hscale = (hactive * 256) / (width); - vdelay = dev->tvnorm->v_delay + dev->crop_bounds.top - - dev->crop_defrect.top; - vactive = dev->crop_bounds.height; + vdelay = norm->v_delay; + vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start; vscale = (vactive * 256) / height; - dprintk(DBG_FLOW, "%s: %dx%d [%s%s,%s]\n", __func__, + pr_debug("%s: %dx%d [%s%s,%s]\n", __func__, width, height, V4L2_FIELD_HAS_TOP(field) ? "T" : "", V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", v4l2_norm_to_name(dev->tvnorm->id)); - dprintk(DBG_FLOW, "%s: hactive=%d, hdelay=%d, hscale=%d; " + pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; " "vactive=%d, vdelay=%d, vscale=%d\n", __func__, hactive, hdelay, hscale, vactive, vdelay, vscale); @@ -615,7 +317,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, ((vactive & 0x300) >> 4) | ((hdelay & 0x300) >> 6) | ((hactive & 0x300) >> 8); - dprintk(DBG_FLOW, "%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " + pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", __func__, comb, vdelay, vactive, hdelay, hactive); tw_writeb(TW68_CROP_HI, comb); @@ -625,7 +327,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); - dprintk(DBG_FLOW, "%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " + pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); tw_writeb(TW68_SCALE_HI, comb); tw_writeb(TW68_VSCALE_LO, vscale); @@ -636,28 +338,21 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, /* ------------------------------------------------------------------ */ -static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, - struct tw68_buf *buf) { - - dprintk(DBG_FLOW, "%s: Starting risc program\n", __func__); - /* Assure correct input */ - if (dev->hw_input != dev->input) { - dev->hw_input = dev->input; - tw_andorb(TW68_INFORM, 0x03 << 2, dev->input->vmux << 2); - } +int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) +{ /* Set cropping and scaling */ - tw68_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + tw68_set_scale(dev, dev->width, dev->height, dev->field); /* * Set start address for RISC program. Note that if the DMAP * processor is currently running, it must be stopped before * a new address can be set. */ tw_clearl(TW68_DMAC, TW68_DMAP_EN); - tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->risc.dma)); + tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->dma)); /* Clear any pending interrupts */ tw_writel(TW68_INTSTAT, dev->board_virqmask); /* Enable the risc engine and the fifo */ - tw_andorl(TW68_DMAC, 0xff, buf->fmt->twformat | + tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat | ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask |= dev->board_virqmask; tw_setl(TW68_INTMASK, dev->pci_irqmask); @@ -665,693 +360,295 @@ static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, } /* ------------------------------------------------------------------ */ -/* videobuf queue operations */ -/* - * check_buf_fmt - * - * callback from tw68-core buffer_queue to determine whether the - * current buffer and the previous one are "compatible" (i.e. the - * risc programs can be chained without requiring a format change) - */ -static int tw68_check_video_fmt(struct tw68_buf *prev, struct tw68_buf *buf) +/* nr of (tw68-)pages for the given buffer size */ +static int tw68_buffer_pages(int size) { - return (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt); + size = PAGE_ALIGN(size); + size += PAGE_SIZE; /* for non-page-aligned buffers */ + size /= 4096; + return size; } -/* - * buffer_setup - * - * Calculate required size of buffer and maximum number allowed - */ -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +/* calc max # of buffers from size (must not exceed the 4MB virtual + * address space per DMA channel) */ +static int tw68_buffer_count(unsigned int size, unsigned int count) { - struct tw68_fh *fh = q->priv_data; + unsigned int maxcount; - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = gbuffers; - *count = tw68_buffer_count(*size, *count); - return 0; + maxcount = 1024 / tw68_buffer_pages(size); + if (count > maxcount) + count = maxcount; + return count; } -static int buffer_activate(struct tw68_dev *dev, struct tw68_buf *buf, - struct tw68_buf *next) -{ - dprintk(DBG_BUFF, "%s: dev=%p, buf=%p, next=%p\n", - __func__, dev, buf, next); - if (dev->hw_input != dev->input) { - dev->hw_input = dev->input; - tw_andorb(TW68_INFORM, 0x03 << 2, - dev->hw_input->vmux << 2); - } - buf->vb.state = VIDEOBUF_ACTIVE; - /* TODO - need to assure scaling/cropping are set correctly */ - mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} +/* ------------------------------------------------------------- */ +/* vb2 queue operations */ -/* -* buffer_prepare -* -* Set the ancilliary information into the buffer structure. This -* includes generating the necessary risc program if it hasn't already -* been done for the current buffer format. -* The structure fh contains the details of the format requested by the -* user - type, width, height and #fields. This is compared with the -* last format set for the current buffer. If they differ, the risc -* code (which controls the filling of the buffer) is (re-)generated. -*/ -static int -buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int tw68_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 tw68_fh *fh = q->priv_data; - struct tw68_dev *dev = fh->dev; - struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - int rc, init_buffer = 0; - unsigned int maxw, maxh; - - BUG_ON(NULL == fh->fmt); - maxw = dev->tvnorm->h_stop - dev->tvnorm->h_start + 1; - maxh = 2*(dev->tvnorm->video_v_stop - dev->tvnorm->video_v_start + 1); - if (fh->width < 48 || fh->width > maxw || fh->height > maxh - || fh->height < 16) { - dprintk(DBG_UNEXPECTED, "%s: invalid dimensions - " - "fh->width=%d, fh->height=%d, maxw=%d, maxh=%d\n", - __func__, fh->width, fh->height, maxw, maxh); - return -EINVAL; - } - buf->vb.size = (fh->width * fh->height * (fh->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) { - dprintk(DBG_BUFF, "%s: buf - fmt=%p, width=%3d, height=%3d, " - "field=%d\n%s: fh - fmt=%p, width=%3d, height=%3d, " - "field=%d\n", __func__, buf->fmt, buf->vb.width, - buf->vb.height, buf->vb.field, __func__, fh->fmt, - fh->width, fh->height, field); - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; /* force risc code re-generation */ - } - buf->input = dev->input; + struct tw68_dev *dev = vb2_get_drv_priv(q); + unsigned tot_bufs = q->num_buffers + *num_buffers; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - init_buffer = 1; /* force risc code re-generation */ - } - dprintk(DBG_BUFF, "%s: q=%p, vb=%p, init_buffer=%d\n", - __func__, q, vb, init_buffer); - - if (init_buffer) { - buf->bpl = buf->vb.width * (buf->fmt->depth) >> 3; - dprintk(DBG_TESTING, "%s: Generating new risc code " - "[%dx%dx%d](%d)\n", __func__, buf->vb.width, - buf->vb.height, buf->fmt->depth, buf->bpl); - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, UNSET, - buf->bpl, 0, - buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - UNSET, 0, - buf->bpl, 0, - buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); - } - } - dprintk(DBG_BUFF, "%s: [%p/%d] - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - __func__, buf, buf->vb.i, fh->width, fh->height, - fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; + /* + * We allow create_bufs, but only if the sizeimage is the same as the + * current sizeimage. The tw68_buffer_count calculation becomes quite + * difficult otherwise. + */ + if (fmt && fmt->fmt.pix.sizeimage < sizes[0]) + return -EINVAL; + *num_planes = 1; + if (tot_bufs < 2) + tot_bufs = 2; + tot_bufs = tw68_buffer_count(sizes[0], tot_bufs); + *num_buffers = tot_bufs - q->num_buffers; - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; return 0; - - fail: - tw68_dma_free(q, buf); - return rc; } /* - * buffer_queue + * The risc program for each buffers works as follows: it starts with a simple + * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the + * buffer follows and at the end we have a JUMP back to the start + 8 (skipping + * the initial JUMP). + * + * This is the program of the first buffer to be queued if the active list is + * empty and it just keeps DMAing this buffer without generating any interrupts. + * + * If a new buffer is added then the initial JUMP in the program generates an + * interrupt as well which signals that the previous buffer has been DMAed + * successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. * - * Callback whenever a buffer has been requested (by read() or QBUF) + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. */ -static void -buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void tw68_buf_queue(struct vb2_buffer *vb) { - struct tw68_fh *fh = q->priv_data; - struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct tw68_buf *prev; + unsigned long flags; + + spin_lock_irqsave(&dev->slock, flags); - tw68_buffer_queue(fh->dev, &fh->dev->video_q, buf); + /* append a 'JUMP to start of buffer' to the buffer risc program */ + buf->jmp[0] = cpu_to_le32(RISC_JUMP); + buf->jmp[1] = cpu_to_le32(buf->dma + 8); + + if (!list_empty(&dev->active)) { + prev = list_entry(dev->active.prev, struct tw68_buf, list); + buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT); + prev->jmp[1] = cpu_to_le32(buf->dma); + } + list_add_tail(&buf->list, &dev->active); + spin_unlock_irqrestore(&dev->slock, flags); } /* - * buffer_release + * buffer_prepare * - * Free a buffer previously allocated. + * Set the ancilliary information into the buffer structure. This + * includes generating the necessary risc program if it hasn't already + * been done for the current buffer format. + * The structure fh contains the details of the format requested by the + * user - type, width, height and #fields. This is compared with the + * last format set for the current buffer. If they differ, the risc + * code (which controls the filling of the buffer) is (re-)generated. */ -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static int tw68_buf_prepare(struct vb2_buffer *vb) { + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); + unsigned size, bpl; + int rc; - tw68_dma_free(q, buf); -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ + size = (dev->width * dev->height * dev->fmt->depth) >> 3; + if (vb2_plane_size(vb, 0) < size) + return -EINVAL; + vb2_set_plane_payload(vb, 0, size); -static int tw68_g_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, - struct v4l2_control *c) -{ - const struct v4l2_queryctrl *ctrl; + rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); + if (!rc) + return -EIO; - dprintk(DBG_FLOW, "%s\n", __func__); - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = (char)tw_readb(TW68_BRIGHT); - break; - case V4L2_CID_HUE: - c->value = (char)tw_readb(TW68_HUE); - break; - case V4L2_CID_CONTRAST: - c->value = tw_readb(TW68_CONTRAST); - break; - case V4L2_CID_SATURATION: - c->value = tw_readb(TW68_SAT_U); - break; - case V4L2_CID_COLOR_KILLER: - c->value = 0 != (tw_readb(TW68_MISC2) & 0xe0); + bpl = (dev->width * dev->fmt->depth) >> 3; + switch (dev->field) { + case V4L2_FIELD_TOP: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, UNSET, bpl, 0, dev->height); break; - case V4L2_CID_CHROMA_AGC: - c->value = 0 != (tw_readb(TW68_LOOP) & 0x30); + case V4L2_FIELD_BOTTOM: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + UNSET, 0, bpl, 0, dev->height); break; - case V4L2_CID_AUDIO_MUTE: - /*hack to suppresss tvtime complaint */ - c->value = 0; + case V4L2_FIELD_SEQ_TB: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, bpl * (dev->height >> 1), + bpl, 0, dev->height >> 1); break; -#if 0 - case V4L2_CID_AUDIO_VOLUME: - c->value = dev->ctl_volume; + case V4L2_FIELD_SEQ_BT: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + bpl * (dev->height >> 1), 0, + bpl, 0, dev->height >> 1); break; -#endif + case V4L2_FIELD_INTERLACED: default: - return -EINVAL; + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, bpl, bpl, bpl, dev->height >> 1); + break; } return 0; } -static int tw68_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +static void tw68_buf_finish(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); + struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); + + pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma); +} + +static int tw68_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct tw68_dev *dev = vb2_get_drv_priv(q); + struct tw68_buf *buf = + container_of(dev->active.next, struct tw68_buf, list); + + dev->seqnr = 0; + tw68_video_start_dma(dev, buf); + return 0; +} + +static void tw68_stop_streaming(struct vb2_queue *q) { - struct tw68_fh *fh = priv; + struct tw68_dev *dev = vb2_get_drv_priv(q); + + /* Stop risc & fifo */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + while (!list_empty(&dev->active)) { + struct tw68_buf *buf = + container_of(dev->active.next, struct tw68_buf, list); - return tw68_g_ctrl_internal(fh->dev, fh, c); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } } -static int tw68_s_ctrl_value(struct tw68_dev *dev, __u32 id, int val) +static struct vb2_ops tw68_video_qops = { + .queue_setup = tw68_queue_setup, + .buf_queue = tw68_buf_queue, + .buf_prepare = tw68_buf_prepare, + .buf_finish = tw68_buf_finish, + .start_streaming = tw68_start_streaming, + .stop_streaming = tw68_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* ------------------------------------------------------------------ */ + +static int tw68_s_ctrl(struct v4l2_ctrl *ctrl) { - int err = 0; + struct tw68_dev *dev = + container_of(ctrl->handler, struct tw68_dev, hdl); - dprintk(DBG_FLOW, "%s\n", __func__); - switch (id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - tw_writeb(TW68_BRIGHT, val); + tw_writeb(TW68_BRIGHT, ctrl->val); break; case V4L2_CID_HUE: - tw_writeb(TW68_HUE, val); + tw_writeb(TW68_HUE, ctrl->val); break; case V4L2_CID_CONTRAST: - tw_writeb(TW68_CONTRAST, val); + tw_writeb(TW68_CONTRAST, ctrl->val); break; case V4L2_CID_SATURATION: - tw_writeb(TW68_SAT_U, val); - tw_writeb(TW68_SAT_V, val); + tw_writeb(TW68_SAT_U, ctrl->val); + tw_writeb(TW68_SAT_V, ctrl->val); break; case V4L2_CID_COLOR_KILLER: - if (val) + if (ctrl->val) tw_andorb(TW68_MISC2, 0xe0, 0xe0); else tw_andorb(TW68_MISC2, 0xe0, 0x00); break; case V4L2_CID_CHROMA_AGC: - if (val) + if (ctrl->val) tw_andorb(TW68_LOOP, 0x30, 0x20); else tw_andorb(TW68_LOOP, 0x30, 0x00); break; - case V4L2_CID_AUDIO_MUTE: - /* hack to suppress tvtime complaint */ - break; -#if 0 - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = val; - tw68_tvaudio_setvolume(dev, dev->ctl_volume); - break; - case V4L2_CID_HFLIP: - dev->ctl_mirror = val; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->ctl_automute = val; - if (dev->tda9887_conf) { - if (dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - else - dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - - tw_call_all(dev, tuner, s_config, &tda9887_cfg); - } - break; - } -#endif - default: - err = -EINVAL; } - return err; + return 0; } -static int tw68_s_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, - struct v4l2_control *c) -{ - const struct v4l2_queryctrl *ctrl; - int err; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (fh) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - return err; - } +/* ------------------------------------------------------------------ */ - mutex_lock(&dev->lock); +/* + * Note that this routine returns what is stored in the fh structure, and + * does not interrogate any of the device registers. + */ +static int tw68_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_dev *dev = video_drvdata(file); - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) { - err = -EINVAL; - goto error; - } - - dprintk(DBG_BUFF, "%s: name=%s val=%d\n", __func__, - ctrl->name, c->value); - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (c->value < ctrl->minimum) - c->value = ctrl->minimum; - if (c->value > ctrl->maximum) - c->value = ctrl->maximum; - break; - default: - /* nothing */; - }; - err = tw68_s_ctrl_value(dev, c->id, c->value); - -error: - mutex_unlock(&dev->lock); - return err; -} - -static int tw68_s_ctrl(struct file *file, void *f, struct v4l2_control *c) -{ - struct tw68_fh *fh = f; - - return tw68_s_ctrl_internal(fh->dev, fh, c); -} - -/* ------------------------------------------------------------------ */ - -/* - * Returns a pointer to the currently used queue (e.g. video, vbi, etc.) - */ -static struct videobuf_queue *tw68_queue(struct tw68_fh *fh) -{ - struct videobuf_queue *q = NULL; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &fh->cap; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - q = &fh->vbi; - break; - default: - BUG(); - } - return q; -} - -static int tw68_resource(struct tw68_fh *fh) -{ - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return RESOURCE_VIDEO; - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return RESOURCE_VBI; - - BUG(); - return 0; -} - -static int video_open(struct file *file) -{ - int minor = video_devdata(file)->minor; - struct tw68_dev *dev; - struct tw68_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int radio = 0; - - mutex_lock(&tw68_devlist_lock); - list_for_each_entry(dev, &tw68_devlist, devlist) { - if (dev->video_dev && (dev->video_dev->minor == minor)) - goto found; - if (dev->radio_dev && (dev->radio_dev->minor == minor)) { - radio = 1; - goto found; - } - if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - goto found; - } - } - mutex_unlock(&tw68_devlist_lock); - return -ENODEV; - -found: - mutex_unlock(&tw68_devlist_lock); - - dprintk(DBG_FLOW, "%s: minor=%d radio=%d type=%s\n", __func__, minor, - radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - 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, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct tw68_buf), -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - fh -#else - fh, &dev->lock -#endif - ); - videobuf_queue_sg_init(&fh->vbi, &tw68_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct tw68_buf), -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - fh -#else - fh, &dev->lock -#endif - ); - if (fh->radio) { - /* switch to radio mode */ - tw68_tvaudio_setinput(dev, &card(dev).radio); - tw_call_all(dev, tuner, s_radio); - } else { - /* switch to video/vbi mode */ - tw68_tvaudio_setinput(dev, dev->input); - } - return 0; -} - -static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct tw68_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(tw68_queue(fh), - data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(tw68_queue(fh), - data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - break; - default: - BUG(); - return 0; - } -} - -static unsigned int -video_poll(struct file *file, struct poll_table_struct *wait) -{ - struct tw68_fh *fh = file->private_data; - struct videobuf_buffer *buf = NULL; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) - return videobuf_poll_stream(file, &fh->vbi, wait); - - if (res_check(fh, RESOURCE_VIDEO)) { - if (!list_empty(&fh->cap.stream)) - buf = list_entry(fh->cap.stream.next, - struct videobuf_buffer, stream); - } else { - mutex_lock(&fh->cap.vb_lock); - if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ - if (res_locked(fh->dev, RESOURCE_VIDEO)) - goto err; - if (0 != fh->cap.ops->buf_prepare(&fh->cap, - fh->cap.read_buf, fh->cap.field)) - goto err; - fh->cap.ops->buf_queue(&fh->cap, fh->cap.read_buf); - fh->cap.read_off = 0; - } - mutex_unlock(&fh->cap.vb_lock); - buf = fh->cap.read_buf; - } - - if (!buf) - return POLLERR; - - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - return 0; - -err: - mutex_unlock(&fh->cap.vb_lock); - return POLLERR; -} - -static int video_release(struct file *file) -{ - struct tw68_fh *fh = file->private_data; - struct tw68_dev *dev = fh->dev; - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_streamoff(&fh->cap); - res_free(fh , RESOURCE_VIDEO); - } - if (fh->cap.read_buf) { - buffer_release(&fh->cap, fh->cap.read_buf); - kfree(fh->cap.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbi); - res_free(fh, RESOURCE_VBI); - } - -#if 0 - tw_call_all(dev, core, s_standby, 0); -#endif - - /* free stuff */ - videobuf_mmap_free(&fh->cap); - videobuf_mmap_free(&fh->vbi); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - v4l2_prio_close(&dev->prio, &fh->prio); -#else - v4l2_prio_close(&dev->prio, fh->prio); -#endif - file->private_data = NULL; - kfree(fh); - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct tw68_fh *fh = file->private_data; - - return videobuf_mmap_mapper(tw68_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ - -#if 0 -static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - struct tw68_tvnorm *norm = dev->tvnorm; - - 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; - f->fmt.vbi.offset = 64 * 4; - f->fmt.vbi.start[0] = norm->vbi_v_start_0; - f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; - f->fmt.vbi.start[1] = norm->vbi_v_start_1; - f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; - f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ - -#if 0 - if (V4L2_STD_PAL == norm->id) { - /* FIXME */ - f->fmt.vbi.start[0] += 3; - f->fmt.vbi.start[1] += 3*2; - } -#endif - return 0; -} -#endif - -/* - * Note that this routine returns what is stored in the fh structure, and - * does not interrogate any of the device registers. - */ -static int tw68_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = dev->field; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * (fh->fmt->depth)) >> 3; + (f->fmt.pix.width * (dev->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 tw68_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - struct tw68_format *fmt; + struct tw68_dev *dev = video_drvdata(file); + const struct tw68_format *fmt; enum v4l2_field field; - unsigned int maxw, maxh; + unsigned int maxh; - dprintk(DBG_FLOW, "%s\n", __func__); fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576; - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: break; case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_SEQ_TB: maxh = maxh * 2; break; default: - return -EINVAL; + field = (f->fmt.pix.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + break; } f->fmt.pix.field = field; @@ -1359,8 +656,8 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = 48; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; + if (f->fmt.pix.width > 720) + f->fmt.pix.width = 720; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; f->fmt.pix.width &= ~0x03; @@ -1368,7 +665,7 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, (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; return 0; } @@ -1381,76 +678,35 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, static int tw68_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); int err; - dprintk(DBG_FLOW, "%s\n", __func__); err = tw68_try_fmt_vid_cap(file, priv, f); if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - /* - * The following lines are to make v4l2-test program happy. - * The docs should be checked to assure they make sense. - */ - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; - return 0; -} - -static int tw68_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) -#if 0 - && (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1) -#endif - ) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - *c = *ctrl; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->field = f->fmt.pix.field; return 0; } static int tw68_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); unsigned int n; n = i->index; - dprintk(DBG_FLOW, "%s: index is %d\n", __func__, n); - if (n >= TW68_INPUT_MAX) { - dprintk(DBG_FLOW, "%s: INPUT_MAX reached\n", __func__); + if (n >= TW68_INPUT_MAX) return -EINVAL; - } - if (NULL == card_in(dev, n).name) { - dprintk(DBG_FLOW, "%s: End of list\n", __func__); - return -EINVAL; - } - memset(i, 0, sizeof(*i)); i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, card_in(dev, n).name); - if (card_in(dev, n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; + i->type = V4L2_INPUT_TYPE_CAMERA; + snprintf(i->name, sizeof(i->name), "Composite %d", n); + /* If the query is for the current input, get live data */ - if (n == dev->hw_input->vmux) { + if (n == dev->input) { int v1 = tw_readb(TW68_STATUS1); int v2 = tw_readb(TW68_MVSN); @@ -1465,305 +721,86 @@ static int tw68_enum_input(struct file *file, void *priv, if (0 != (v2 & (1 << 2))) i->status |= V4L2_IN_ST_MACROVISION; } - i->std = TW68_NORMS; + i->std = video_devdata(file)->tvnorms; return 0; } static int tw68_g_input(struct file *file, void *priv, unsigned int *i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); - *i = dev->input->vmux; + *i = dev->input; return 0; } static int tw68_s_input(struct file *file, void *priv, unsigned int i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - - if (i < 0 || i >= TW68_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i).name) + if (i >= TW68_INPUT_MAX) return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); + dev->input = i; + tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2); return 0; } static int tw68_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - unsigned int tuner_type = dev->tuner_type; - - dprintk(DBG_FLOW, "%s\n", __func__); strcpy(cap->driver, "tw68"); - strlcpy(cap->card, tw68_boards[dev->board].name, + strlcpy(cap->card, "Techwell Capture Card", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = TW68_VERSION_CODE; - cap->capabilities = + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; + V4L2_CAP_STREAMING; - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -static int tw68_s_std_internal(struct tw68_dev *dev, struct tw68_fh *fh, - v4l2_std_id *id) +static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id) { -/* unsigned long flags; */ + struct tw68_dev *dev = video_drvdata(file); unsigned int i; - v4l2_std_id fixup; - int err; - dprintk(DBG_FLOW, "%s\n", __func__); - if (fh) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - } + if (vb2_is_busy(&dev->vidq)) + return -EBUSY; /* Look for match on complete norm id (may have mult bits) */ for (i = 0; i < TVNORMS; i++) { - if (*id == tvnorms[i].id) + if (id == tvnorms[i].id) break; } /* If no exact match, look for norm which contains this one */ - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) { - if (*id & tvnorms[i].id) + if (i == TVNORMS) { + for (i = 0; i < TVNORMS; i++) + if (id & tvnorms[i].id) break; - } + } /* If still not matched, give up */ if (i == TVNORMS) return -EINVAL; - /* TODO - verify this additional work with SECAM applies to TW */ - 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; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; - } - for (i = 0; i < TVNORMS; i++) - if (fixup == tvnorms[i].id) - break; - } - - *id = tvnorms[i].id; - mutex_lock(&dev->lock); set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ - tw68_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); return 0; } -static int tw68_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - return tw68_s_std_internal(fh->dev, fh, id); -} - static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); *id = dev->tvnorm->id; return 0; } -static int tw68_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int n; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - for (n = 0; n < TW68_INPUT_MAX; n++) - if (card_in(dev, n).tv) - break; - if (n == TW68_INPUT_MAX) - return -EINVAL; -#if 0 - if (NULL != card_in(dev, n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = tw68_tvaudio_getstereo(dev); - t->audmode = tw68_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(TW68_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; -#endif - return 0; -} - -static int tw68_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; -#if 0 - int rx, mode -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - -#if 0 - mode = dev->thread.mode; - if (UNSET == mode) { - rx = tw68_tvaudio_getstereo(dev); - mode = tw68_tvaudio_rx2mode(t->rxsubchans); - } - if (mode != t->audmode) - dev->thread.mode = t->audmode; -#endif - return 0; -} - -static int tw68_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - if (unlikely(dev->tuner_type)) - return -EINVAL; - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; -/* f->frequency = dev->ctl_freq; */ - - return 0; -} - -static int tw68_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); -/* dev->ctl_freq = f->frequency; */ - - tw_call_all(dev, tuner, s_frequency, f); - - tw68_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} - -static int tw68_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - strcpy(a->name, "audio"); - return 0; -} - -static int tw68_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return 0; -} - -static int tw68_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - *p = v4l2_prio_max(&dev->prio); - return 0; -} - -static int tw68_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - return v4l2_prio_change(&dev->prio, &fh->prio, prio); -} - static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); if (f->index >= FORMATS) return -EINVAL; @@ -1775,149 +812,6 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int tw68_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; - } - return 0; -} - -static int tw68_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - crop->c = dev->crop_current; - return 0; -} - -static int tw68_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - struct v4l2_rect *b = &dev->crop_bounds; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - - if ((crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (crop->c.height < 0) || (crop->c.width < 0)) { - dprintk(DBG_UNEXPECTED, "%s: invalid request\n", __func__); - return -EINVAL; - } - - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dprintk(DBG_FLOW, "%s: setting cropping rectangle: top=%d, left=%d, " - "width=%d, height=%d\n", __func__, crop->c.top, - crop->c.left, crop->c.width, crop->c.height); - dev->crop_current = crop->c; - return 0; -} - -/* - * Wrappers for the v4l2_ioctl_ops functions - */ -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) -{ - struct tw68_fh *fh = file->private_data; - return videobuf_cgmbuf(tw68_queue(fh), mbuf, 8); -} -#endif - -static int tw68_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct tw68_fh *fh = priv; - return videobuf_reqbufs(tw68_queue(fh), p); -} - -static int tw68_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_querybuf(tw68_queue(fh), b); -} - -static int tw68_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_qbuf(tw68_queue(fh), b); -} - -static int tw68_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_dqbuf(tw68_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - -static int tw68_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int res = tw68_resource(fh); - - dprintk(DBG_FLOW, "%s\n", __func__); - if (!res_get(fh, res)) - return -EBUSY; - - tw68_buffer_requeue(dev, &dev->video_q); - return videobuf_streamon(tw68_queue(fh)); -} - -static int tw68_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int err; - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int res = tw68_resource(fh); - - dprintk(DBG_FLOW, "%s\n", __func__); - err = videobuf_streamoff(tw68_queue(fh)); - if (err < 0) - return err; - res_free(fh, res); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG /* * Used strictly for internal development and debugging, this routine * prints out the current register contents for the tw68xx device. @@ -1928,7 +822,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) int i, j, k; unsigned char *cptr; - printk(KERN_DEBUG "Full dump of TW68 registers:\n"); + pr_info("Full dump of TW68 registers:\n"); /* First we do the PCI regs, 8 4-byte regs per line */ for (i = 0; i < 0x100; i += 32) { cptr = line; @@ -1941,7 +835,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) cptr += sprintf(cptr, "%08x ", tw_readl(j)); *cptr++ = '\n'; *cptr = 0; - printk(KERN_DEBUG "%s", line); + pr_info("%s", line); } /* Next the control regs, which are single-byte, address mod 4 */ while (i < 0x400) { @@ -1958,29 +852,24 @@ static void tw68_dump_regs(struct tw68_dev *dev) } *cptr++ = '\n'; *cptr = 0; - printk(KERN_DEBUG "%s", line); + pr_info("%s", line); } } static int vidioc_log_status(struct file *file, void *priv) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); tw68_dump_regs(dev); - return 0; + return v4l2_ctrl_log_status(file, priv); } +#ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; /* needed for tw_readb */ + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); - if (!v4l2_chip_match_host(®->match)) - dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); - return -EINVAL; if (reg->size == 1) reg->val = tw_readb(reg->reg); else @@ -1989,17 +878,10 @@ 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 tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; /* needed for tw_writeb */ + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s: request to set reg 0x%04x to 0x%02x\n", - __func__, (unsigned int)reg->reg, (unsigned int)reg->val); - if (!v4l2_chip_match_host(®->match)) { - dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); - return -EINVAL; - } if (reg->size == 1) tw_writeb(reg->reg, reg->val); else @@ -2008,151 +890,120 @@ static int vidioc_s_register(struct file *file, void *priv, } #endif +static const struct v4l2_ctrl_ops tw68_ctrl_ops = { + .s_ctrl = tw68_s_ctrl, +}; + static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_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 video_ioctl_ops = { .vidioc_querycap = tw68_querycap, .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, - .vidioc_reqbufs = tw68_reqbufs, - .vidioc_querybuf = tw68_querybuf, - .vidioc_qbuf = tw68_qbuf, - .vidioc_dqbuf = tw68_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_s_std = tw68_s_std, .vidioc_g_std = tw68_g_std, .vidioc_enum_input = tw68_enum_input, .vidioc_g_input = tw68_g_input, .vidioc_s_input = tw68_s_input, - .vidioc_queryctrl = tw68_queryctrl, - .vidioc_g_ctrl = tw68_g_ctrl, - .vidioc_s_ctrl = tw68_s_ctrl, - .vidioc_streamon = tw68_streamon, - .vidioc_streamoff = tw68_streamoff, - .vidioc_g_priority = tw68_g_priority, - .vidioc_s_priority = tw68_s_priority, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, - .vidioc_cropcap = tw68_cropcap, - .vidioc_g_crop = tw68_g_crop, - .vidioc_s_crop = tw68_s_crop, -/* - * Functions not yet implemented / not yet passing tests. - */ - -#if 0 - .vidioc_g_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, -#endif - .vidioc_g_audio = tw68_g_audio, - .vidioc_s_audio = tw68_s_audio, - .vidioc_g_tuner = tw68_g_tuner, - .vidioc_s_tuner = tw68_s_tuner, - .vidioc_g_frequency = tw68_g_frequency, - .vidioc_s_frequency = tw68_s_frequency, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif -#ifdef CONFIG_VIDEO_ADV_DEBUG .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 = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif }; -/* ------------------------------------------------------------------ */ -/* exported stuff */ -struct video_device tw68_video_template = { +static struct video_device tw68_video_template = { .name = "tw68_video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, - .minor = -1, + .release = video_device_release_empty, .tvnorms = TW68_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -struct video_device tw68_radio_template = { - .name = "tw68_radio", }; -int tw68_videoport_init(struct tw68_dev *dev) -{ - return 0; -} - +/* ------------------------------------------------------------------ */ +/* exported stuff */ void tw68_set_tvnorm_hw(struct tw68_dev *dev) { tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); - return; } int tw68_video_init1(struct tw68_dev *dev) { - int i; - - dprintk(DBG_FLOW, "%s\n", __func__); - /* sanitycheck insmod options */ - if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) - gbuffers = 2; - if (gbufsz < 0 || gbufsz > gbufsz_max) - gbufsz = gbufsz_max; - gbufsz = (gbufsz + PAGE_SIZE - 1) & PAGE_MASK; - - /* put some sensible defaults into the data structures ... */ - for (i = 0; i < CTRLS; i++) - tw68_s_ctrl_value(dev, video_ctrls[i].id, - video_ctrls[i].default_value); -#if 0 - if (dev->tda9887_conf && dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - dev->automute = 0; -#endif - INIT_LIST_HEAD(&dev->video_q.queued); - INIT_LIST_HEAD(&dev->video_q.active); - init_timer(&dev->video_q.timeout); - dev->video_q.timeout.function = tw68_buffer_timeout; - dev->video_q.timeout.data = (unsigned long)(&dev->video_q); - dev->video_q.dev = dev; - dev->video_q.buf_compat = tw68_check_video_fmt; - dev->video_q.start_dma = tw68_video_start_dma; - tw68_risc_stopper(dev->pci, &dev->video_q.stopper); - - if (tw68_boards[dev->board].video_out) - tw68_videoport_init(dev); - + struct v4l2_ctrl_handler *hdl = &dev->hdl; + + v4l2_ctrl_handler_init(hdl, 6); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 20); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 100); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + /* NTSC only */ + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; + } + dev->v4l2_dev.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); return 0; } -int tw68_video_init2(struct tw68_dev *dev) +int tw68_video_init2(struct tw68_dev *dev, int video_nr) { - dprintk(DBG_FLOW, "%s\n", __func__); + int ret; + set_tvnorm(dev, &tvnorms[0]); - video_mux(dev, 0); -/* - tw68_tvaudio_setmut(dev); - tw68_tvaudio_setvolume(dev, dev->ctl_volume); -*/ - return 0; -} -/* - * tw68_irq_video_signalchange - * - * TODO: - * Check for presence of video signal. If not present, mute audio. - * If present, log type of signal present. - */ -void tw68_irq_video_signalchange(struct tw68_dev *dev) -{ - return; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + dev->width = 720; + dev->height = 576; + dev->field = V4L2_FIELD_INTERLACED; + + INIT_LIST_HEAD(&dev->active); + dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; + dev->vidq.ops = &tw68_video_qops; + dev->vidq.mem_ops = &vb2_dma_sg_memops; + dev->vidq.drv_priv = dev; + dev->vidq.gfp_flags = __GFP_DMA32; + dev->vidq.buf_struct_size = sizeof(struct tw68_buf); + dev->vidq.lock = &dev->lock; + dev->vidq.min_buffers_needed = 2; + ret = vb2_queue_init(&dev->vidq); + if (ret) + return ret; + dev->vdev = tw68_video_template; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->lock; + dev->vdev.queue = &dev->vidq; + video_set_drvdata(&dev->vdev, dev); + return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); } /* @@ -2171,60 +1022,39 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) * for the current buffer. */ if (status & TW68_DMAPI) { - struct tw68_dmaqueue *q = &dev->video_q; - dprintk(DBG_FLOW | DBG_TESTING, "DMAPI interrupt\n"); + struct tw68_buf *buf; + spin_lock(&dev->slock); - /* - * tw68_wakeup will take care of the buffer handling, - * plus any non-video requirements. - */ - tw68_wakeup(q, &dev->video_fieldcount); + buf = list_entry(dev->active.next, struct tw68_buf, list); + list_del(&buf->list); spin_unlock(&dev->slock); - /* Check whether we have gotten into 'stopper' code */ - reg = tw_readl(TW68_DMAP_PP); - if ((reg >= q->stopper.dma) && - (reg < q->stopper.dma + q->stopper.size)) { - /* Yes - log the information */ - dprintk(DBG_FLOW | DBG_TESTING, - "%s: stopper risc code entered\n", __func__); - } + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.field = dev->field; + buf->vb.v4l2_buf.sequence = dev->seqnr++; + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); status &= ~(TW68_DMAPI); if (0 == status) return; } - if (status & (TW68_VLOCK | TW68_HLOCK)) { /* lost sync */ - dprintk(DBG_UNUSUAL, "Lost sync\n"); - } - if (status & TW68_PABORT) { /* TODO - what should we do? */ - dprintk(DBG_UNEXPECTED, "PABORT interrupt\n"); - } - if (status & TW68_DMAPERR) { - dprintk(DBG_UNEXPECTED, "DMAPERR interrupt\n"); -#if 0 - /* Stop risc & fifo */ - tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); - tw_clearl(TW68_INTMASK, dev->board_virqmask); - dev->pci_irqmask &= ~dev->board_virqmask; -#endif - } + if (status & (TW68_VLOCK | TW68_HLOCK)) + dev_dbg(&dev->pci->dev, "Lost sync\n"); + if (status & TW68_PABORT) + dev_err(&dev->pci->dev, "PABORT interrupt\n"); + if (status & TW68_DMAPERR) + dev_err(&dev->pci->dev, "DMAPERR interrupt\n"); /* * On TW6800, FDMIS is apparently generated if video input is switched * during operation. Therefore, it is not enabled for that chip. */ - if (status & TW68_FDMIS) { /* logic error somewhere */ - dprintk(DBG_UNEXPECTED, "FDMIS interrupt\n"); - /* Stop risc & fifo */ -// tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); -// tw_clearl(TW68_INTMASK, dev->board_virqmask); -// dev->pci_irqmask &= ~dev->board_virqmask; - } - if (status & TW68_FFOF) { /* probably a logic error */ + if (status & TW68_FDMIS) + dev_dbg(&dev->pci->dev, "FDMIS interrupt\n"); + if (status & TW68_FFOF) { + /* probably a logic error */ reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; tw_clearl(TW68_DMAC, TW68_FIFO_EN); - dprintk(DBG_UNUSUAL, "FFOF interrupt\n"); + dev_dbg(&dev->pci->dev, "FFOF interrupt\n"); tw_setl(TW68_DMAC, reg); } if (status & TW68_FFERR) - dprintk(DBG_UNEXPECTED, "FFERR interrupt\n"); - return; + dev_dbg(&dev->pci->dev, "FFERR interrupt\n"); } diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index e723efb5e623..2c8abe26b13b 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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,54 +23,26 @@ * 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 -#define TW68_VERSION_CODE KERNEL_VERSION(0, 0, 8) - #include -#include -#include #include -#include -#include #include #include #include - -#include +#include #include #include +#include #include +#include -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -# include -#endif -#include -#include - -#include "btcx-risc.h" #include "tw68-reg.h" #define UNSET (-1U) -/* - * dprintk statement within the code use a 'level' argument. For - * our purposes, we use the following levels: - */ -#define DBG_UNEXPECTED (1 << 0) -#define DBG_UNUSUAL (1 << 1) -#define DBG_TESTING (1 << 2) -#define DBG_BUFF (1 << 3) -#define DBG_FLOW (1 << 15) - /* system vendor and device ID's */ #define PCI_VENDOR_ID_TECHWELL 0x1797 #define PCI_DEVICE_ID_6800 0x6800 @@ -83,15 +59,9 @@ #define PCI_DEVICE_ID_6816_3 0x6812 #define PCI_DEVICE_ID_6816_4 0x6813 -/* subsystem vendor ID's */ -#define TW68_PCI_ID_TECHWELL 0x1797 - -#define TW68_NORMS (\ - V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60 | \ - V4L2_STD_525_60 | V4L2_STD_625_50 | \ - V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC | V4L2_STD_SECAM_DK) +#define TW68_NORMS ( \ + V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60) #define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ TW68_FFOF | TW68_DMAPI) @@ -101,12 +71,13 @@ #define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ TW68_SBDONE2) -typedef enum { +enum tw68_decoder_type { TW6800, TW6801, TW6804, TWXXXX, -} TW68_DECODER_TYPE; +}; + /* ----------------------------------------------------------- */ /* static data */ @@ -153,164 +124,24 @@ struct tw68_format { #define TW68_BOARD_GENERIC_6802 1 #define TW68_MAXBOARDS 16 -#define TW68_INPUT_MAX 8 - -/* ----------------------------------------------------------- */ -/* enums */ - -enum tw68_mpeg_type { - TW68_MPEG_UNUSED, - TW68_MPEG_EMPRESS, - TW68_MPEG_DVB, -}; - -enum tw68_audio_in { - TV = 1, - LINE1 = 2, - LINE2 = 3, - LINE2_LEFT, -}; - -enum tw68_video_out { - CCIR656 = 1, -}; - -/* Structs for card definition */ -struct tw68_input { - char *name; /* text description */ - unsigned int vmux; /* mux value */ - enum tw68_audio_in mux; - unsigned int gpio; - unsigned int tv:1; -}; - -struct tw68_board { - char *name; - unsigned int audio_clock; - - /* input switching */ - unsigned int gpiomask; - struct tw68_input inputs[TW68_INPUT_MAX]; - struct tw68_input radio; - struct tw68_input mute; - - /* i2c chip info */ - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - unsigned int tda9887_conf; - unsigned int tuner_config; - - enum tw68_video_out video_out; - enum tw68_mpeg_type mpeg; - unsigned int vid_port_opts; -}; - -#define card_has_radio(dev) (NULL != tw68_boards[dev->board].radio.name) -#define card_has_mpeg(dev) (TW68_MPEG_UNUSED != \ - tw68_boards[dev->board].mpeg) -#define card_in(dev, n) (tw68_boards[dev->board].inputs[n]) -#define card(dev) (tw68_boards[dev->board]) +#define TW68_INPUT_MAX 4 /* ----------------------------------------------------------- */ /* device / file handle status */ -#define RESOURCE_VIDEO 1 -#define RESOURCE_VBI 2 - -#define INTERLACE_AUTO 0 -#define INTERLACE_ON 1 -#define INTERLACE_OFF 2 - #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ struct tw68_dev; /* forward delclaration */ -/* tvaudio thread status */ -struct tw68_thread { - struct task_struct *thread; - unsigned int scan1; - unsigned int scan2; - unsigned int mode; - unsigned int stopped; -}; - /* buffer for one video/vbi/ts frame */ struct tw68_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* tw68 specific */ - struct tw68_format *fmt; - struct tw68_input *input; - unsigned int top_seen; - int (*activate)(struct tw68_dev *dev, - struct tw68_buf *buf, - struct tw68_buf *next); - struct btcx_riscmem risc; - unsigned int bpl; -}; + struct vb2_buffer vb; + struct list_head list; -struct tw68_dmaqueue { - struct tw68_dev *dev; - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - int (*buf_compat)(struct tw68_buf *prev, - struct tw68_buf *buf); - int (*start_dma)(struct tw68_dev *dev, - struct tw68_dmaqueue *q, - struct tw68_buf *buf); -}; - -/* video filehandle status */ -struct tw68_fh { - struct tw68_dev *dev; - unsigned int radio; - enum v4l2_buf_type type; - unsigned int resources; - enum v4l2_priority prio; - - /* video capture */ - struct tw68_format *fmt; - unsigned int width, height; - struct videobuf_queue cap; /* also used for overlay */ - - /* vbi capture */ - struct videobuf_queue vbi; -}; - -/* dmasound dsp status */ -struct tw68_dmasound { - struct mutex lock; - int minor_mixer; - int minor_dsp; - unsigned int users_dsp; - - /* mixer */ - enum tw68_audio_in input; - unsigned int count; - unsigned int line1; - unsigned int line2; - - /* dsp */ - unsigned int afmt; - unsigned int rate; - unsigned int channels; - unsigned int recording_on; - unsigned int dma_running; - unsigned int blocks; - unsigned int blksize; - unsigned int bufsize; - struct videobuf_dmabuf dma; - unsigned int dma_blk; - unsigned int read_offset; - unsigned int read_count; - void *priv_data; - struct snd_pcm_substream *substream; + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; }; struct tw68_fmt { @@ -321,58 +152,20 @@ struct tw68_fmt { u32 twformat; }; -/* ts/mpeg status */ -struct tw68_ts { - /* TS capture */ - int nr_packets; - int nr_bufs; -}; - -/* ts/mpeg ops */ -struct tw68_mpeg_ops { - enum tw68_mpeg_type type; - struct list_head next; - int (*init)(struct tw68_dev *dev); - int (*fini)(struct tw68_dev *dev); - void (*signal_change)(struct tw68_dev *dev); -}; - -enum tw68_ts_status { - TW68_TS_STOPPED, - TW68_TS_BUFF_DONE, - TW68_TS_STARTED, -}; - /* global device status */ struct tw68_dev { - struct list_head devlist; struct mutex lock; spinlock_t slock; - struct v4l2_prio_state prio; + u16 instance; struct v4l2_device v4l2_dev; - /* workstruct for loading modules */ - struct work_struct request_module_wk; - - /* insmod option/autodetected */ - int autodetected; /* various device info */ - TW68_DECODER_TYPE vdecoder; - unsigned int resources; - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; - struct tw68_dmasound dmasound; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - /* infrared remote */ - int has_remote; - struct card_ir *remote; -#endif + enum tw68_decoder_type vdecoder; + struct video_device vdev; + struct v4l2_ctrl_handler hdl; /* pci i/o */ - char name[32]; - int nr; + char *name; struct pci_dev *pci; unsigned char pci_rev, pci_lat; u32 __iomem *lmmio; @@ -381,75 +174,18 @@ struct tw68_dev { /* The irq mask to be used will depend upon the chip type */ u32 board_virqmask; - /* config info */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - unsigned int tda9887_conf; - unsigned int gpio_value; - - /* i2c i/o */ - struct i2c_algo_bit_data i2c_algo; - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - u32 i2c_state; - u32 i2c_done; - wait_queue_head_t i2c_queue; - int i2c_rc; - unsigned char eedata[256]; - - /* video+ts+vbi capture */ - struct tw68_dmaqueue video_q; - struct tw68_dmaqueue vbi_q; - unsigned int video_fieldcount; - unsigned int vbi_fieldcount; + /* video capture */ + const struct tw68_format *fmt; + unsigned width, height; + unsigned seqnr; + unsigned field; + struct vb2_queue vidq; + struct list_head active; /* various v4l controls */ - struct tw68_tvnorm *tvnorm; /* video */ - struct tw68_tvaudio *tvaudio; -#if 0 - unsigned int ctl_input; - int ctl_bright; - int ctl_contrast; - int ctl_hue; - int ctl_saturation; - int ctl_freq; - int ctl_mute; /* audio */ - int ctl_volume; - int ctl_invert; /* private */ - int ctl_mirror; - int ctl_y_odd; - int ctl_y_even; - int ctl_automute; -#endif - - /* crop */ - struct v4l2_rect crop_bounds; - struct v4l2_rect crop_defrect; - struct v4l2_rect crop_current; - - /* other global state info */ - unsigned int automute; - struct tw68_thread thread; - /* input is latest requested by app, hw_input is current hw setting */ - struct tw68_input *input; - struct tw68_input *hw_input; - unsigned int hw_mute; - int last_carrier; - int nosignal; - unsigned int insuspend; - - /* TW68_MPEG_* */ - struct tw68_ts ts; - struct tw68_dmaqueue ts_q; - enum tw68_ts_status ts_state; - unsigned int buff_cnt; - struct tw68_mpeg_ops *mops; - - void (*gate_ctrl)(struct tw68_dev *dev, int open); + const struct tw68_tvnorm *tvnorm; /* video */ + + int input; }; /* ----------------------------------------------------------- */ @@ -473,116 +209,23 @@ struct tw68_dev { #define tw_clearb(reg, bit) \ writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ dev->bmmio + (reg)) -#define tw_call_all(dev, o, f, args...) do { \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 1); \ - v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 0); \ -} while (0) #define tw_wait(us) { udelay(us); } -static inline struct tw68_dev *to_tw68_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct tw68_dev, v4l2_dev); -} - -/* ----------------------------------------------------------- */ -/* tw68-core.c */ - -extern struct list_head tw68_devlist; -extern struct mutex tw68_devlist_lock; -extern unsigned int irq_debug; - -int tw68_buffer_count(unsigned int size, unsigned int count); -void tw68_buffer_queue(struct tw68_dev *dev, struct tw68_dmaqueue *q, - struct tw68_buf *buf); -void tw68_buffer_timeout(unsigned long data); -int tw68_set_dmabits(struct tw68_dev *dev); -void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf); -void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *field_count); -int tw68_buffer_requeue(struct tw68_dev *dev, struct tw68_dmaqueue *q); - -/* ----------------------------------------------------------- */ -/* tw68-cards.c */ - -extern struct tw68_board tw68_boards[]; -extern const unsigned int tw68_bcount; -extern struct pci_device_id __devinitdata tw68_pci_tbl[]; - -int tw68_board_init1(struct tw68_dev *dev); -int tw68_board_init2(struct tw68_dev *dev); -int tw68_tuner_callback(void *priv, int component, int command, int arg); - -/* ----------------------------------------------------------- */ -/* tw68-i2c.c */ - -int tw68_i2c_register(struct tw68_dev *dev); -int tw68_i2c_unregister(struct tw68_dev *dev); -void tw68_irq_i2c(struct tw68_dev *dev, int status); - /* ----------------------------------------------------------- */ /* tw68-video.c */ -extern unsigned int video_debug; -extern struct video_device tw68_video_template; -extern struct video_device tw68_radio_template; - -int tw68_videoport_init(struct tw68_dev *dev); void tw68_set_tvnorm_hw(struct tw68_dev *dev); int tw68_video_init1(struct tw68_dev *dev); -int tw68_video_init2(struct tw68_dev *dev); -void tw68_irq_video_signalchange(struct tw68_dev *dev); +int tw68_video_init2(struct tw68_dev *dev, int video_nr); void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); - -/* ----------------------------------------------------------- */ -/* tw68-ts.c */ - -int tw68_ts_init1(struct tw68_dev *dev); -int tw68_ts_fini(struct tw68_dev *dev); -void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status); - -int tw68_ts_register(struct tw68_mpeg_ops *ops); -void tw68_ts_unregister(struct tw68_mpeg_ops *ops); - -int tw68_ts_init_hw(struct tw68_dev *dev); - -/* ----------------------------------------------------------- */ -/* tw68-vbi.c */ - -extern struct videobuf_queue_ops tw68_vbi_qops; -extern struct video_device tw68_vbi_template; - -int tw68_vbi_init1(struct tw68_dev *dev); -int tw68_vbi_fini(struct tw68_dev *dev); -void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status); - -/* ----------------------------------------------------------- */ -/* tw68-tvaudio.c */ - -int tw68_tvaudio_rx2mode(u32 rx); - -void tw68_tvaudio_setmute(struct tw68_dev *dev); -void tw68_tvaudio_setinput(struct tw68_dev *dev, - struct tw68_input *in); -void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level); -int tw68_tvaudio_getstereo(struct tw68_dev *dev); -void tw68_tvaudio_init(struct tw68_dev *dev); -int tw68_tvaudio_init2(struct tw68_dev *dev); -int tw68_tvaudio_fini(struct tw68_dev *dev); -int tw68_tvaudio_do_scan(struct tw68_dev *dev); -int tw_dsp_writel(struct tw68_dev *dev, int reg, u32 value); -void tw68_enable_i2s(struct tw68_dev *dev); +int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf); /* ----------------------------------------------------------- */ /* tw68-risc.c */ -int tw68_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); -int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc); -int tw68_risc_overlay(struct tw68_fh *fh, struct btcx_riscmem *risc, - int field_type); -- cgit v1.2.3 From ce9e1ac1b9becb9481f8492d9ccf713398a07ef8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 4 Sep 2014 11:31:58 -0300 Subject: [media] tw68: make tw68_pci_tbl static and constify drivers/media/pci/tw68/tw68-core.c:72:22: warning: symbol 'tw68_pci_tbl' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index baf93af1d764..a6fb48cf7aae 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -69,7 +69,7 @@ static atomic_t tw68_instance = ATOMIC_INIT(0); * the PCI ID database up to date. Note that the entries must be * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ -struct pci_device_id tw68_pci_tbl[] = { +static const struct pci_device_id tw68_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, -- cgit v1.2.3 From 04da2daee383391954b34e7d0fe0281d75447d61 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 20:44:04 -0300 Subject: [media] ngene: properly handle __user ptr Sparse is complaining about ngene's bad usage of a __user ptr: >> drivers/media/pci/ngene/ngene-dvb.c:62:48: sparse: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-dvb.c:62:48: expected unsigned char const [usertype] *buf drivers/media/pci/ngene/ngene-dvb.c:62:48: got char const [noderef] *buf As this is intercepting a .write() file ops, we can't just memcpy. We need to use copy_from_user. Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_ringbuffer.c | 26 ++++++++++++++++++++++++++ drivers/media/dvb-core/dvb_ringbuffer.h | 2 ++ drivers/media/pci/ngene/ngene-dvb.c | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index a5712cd7c65f..1100e98a7b1d 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -166,6 +166,31 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t return len; } +ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len) +{ + int status; + size_t todo = len; + size_t split; + + split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + + if (split > 0) { + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); + if (status) + return len - todo; + buf += split; + todo -= split; + rbuf->pwrite = 0; + } + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); + if (status) + return len - todo; + rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; + + return len; +} + ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) { int status; @@ -297,3 +322,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read_user); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); +EXPORT_SYMBOL(dvb_ringbuffer_write_user); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 41f04dae69b6..9e1e11b7c39c 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h @@ -133,6 +133,8 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len); +extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len); /** diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index a8a4045f66d7..59bb2858c8d0 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -59,7 +59,7 @@ static ssize_t ts_write(struct file *file, const char __user *buf, (&dev->tsout_rbuf) >= count) < 0) return 0; - dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count); return count; } -- cgit v1.2.3 From c65fde192257d3007030c1aca5f4953235394e74 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Aug 2014 05:16:39 -0300 Subject: [media] MAINTAINERS: add tw68 entry Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aefa94841ff3..78b38e9e5e0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9227,6 +9227,14 @@ T: git git://linuxtv.org/media_tree.git S: Odd fixes F: drivers/media/usb/tm6000/ +TW68 VIDEO4LINUX 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/pci/tw68/ + TPM DEVICE DRIVER M: Peter Huewe M: Ashley Lai -- cgit v1.2.3 From eb773df5d2cf68be127b2ee146336f888962a521 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 16:27:55 -0300 Subject: [media] m88ts2022: rename device state (priv => dev) foo_dev seems to be most correct term for the structure holding data of each device instance. It is most used term in Kernel and also examples from book Linux Device Drivers, Third Edition, uses it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/m88ts2022.c | 190 +++++++++++++++++----------------- drivers/media/tuners/m88ts2022_priv.h | 2 +- 2 files changed, 96 insertions(+), 96 deletions(-) diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index f51b107ddf29..94f0d3b7536a 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -19,7 +19,7 @@ #include "m88ts2022_priv.h" /* write multiple registers */ -static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, +static int m88ts2022_wr_regs(struct m88ts2022_dev *dev, u8 reg, const u8 *val, int len) { #define MAX_WR_LEN 3 @@ -28,7 +28,7 @@ static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, u8 buf[MAX_WR_XFER_LEN]; struct i2c_msg msg[1] = { { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = 0, .len = 1 + len, .buf = buf, @@ -41,11 +41,11 @@ static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->client->adapter, msg, 1); + ret = i2c_transfer(dev->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "%s: i2c wr failed=%d reg=%02x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -55,7 +55,7 @@ static int m88ts2022_wr_regs(struct m88ts2022_priv *priv, } /* read multiple registers */ -static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, +static int m88ts2022_rd_regs(struct m88ts2022_dev *dev, u8 reg, u8 *val, int len) { #define MAX_RD_LEN 1 @@ -64,12 +64,12 @@ static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, u8 buf[MAX_RD_XFER_LEN]; struct i2c_msg msg[2] = { { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = 0, .len = 1, .buf = ®, }, { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = I2C_M_RD, .len = len, .buf = buf, @@ -79,12 +79,12 @@ static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, if (WARN_ON(len > MAX_RD_LEN)) return -EINVAL; - ret = i2c_transfer(priv->client->adapter, msg, 2); + ret = i2c_transfer(dev->client->adapter, msg, 2); if (ret == 2) { memcpy(val, buf, len); ret = 0; } else { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "%s: i2c rd failed=%d reg=%02x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -94,19 +94,19 @@ static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg, } /* write single register */ -static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val) +static int m88ts2022_wr_reg(struct m88ts2022_dev *dev, u8 reg, u8 val) { - return m88ts2022_wr_regs(priv, reg, &val, 1); + return m88ts2022_wr_regs(dev, reg, &val, 1); } /* read single register */ -static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val) +static int m88ts2022_rd_reg(struct m88ts2022_dev *dev, u8 reg, u8 *val) { - return m88ts2022_rd_regs(priv, reg, val, 1); + return m88ts2022_rd_regs(dev, reg, val, 1); } /* write single register with mask */ -static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv, +static int m88ts2022_wr_reg_mask(struct m88ts2022_dev *dev, u8 reg, u8 val, u8 mask) { int ret; @@ -114,7 +114,7 @@ static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv, /* no need for read if whole reg is written */ if (mask != 0xff) { - ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1); + ret = m88ts2022_rd_regs(dev, reg, &u8tmp, 1); if (ret) return ret; @@ -123,13 +123,13 @@ static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv, val |= u8tmp; } - return m88ts2022_wr_regs(priv, reg, &val, 1); + return m88ts2022_wr_regs(dev, reg, &val, 1); } static int m88ts2022_cmd(struct dvb_frontend *fe, int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret, i; u8 u8tmp; struct m88ts2022_reg_val reg_vals[] = { @@ -140,12 +140,12 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, }; for (i = 0; i < 2; i++) { - dev_dbg(&priv->client->dev, + dev_dbg(&dev->client->dev, "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n", __func__, i, op, reg, mask, val); for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, + ret = m88ts2022_wr_reg(dev, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; @@ -153,7 +153,7 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, usleep_range(sleep * 1000, sleep * 10000); - ret = m88ts2022_rd_reg(priv, reg, &u8tmp); + ret = m88ts2022_rd_reg(dev, reg, &u8tmp); if (ret) goto err; @@ -169,7 +169,7 @@ err: static int m88ts2022_set_params(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; unsigned int frequency_khz, frequency_offset_khz, f_3db_hz; @@ -177,14 +177,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; u16 u16tmp; - dev_dbg(&priv->client->dev, + dev_dbg(&dev->client->dev, "%s: frequency=%d symbol_rate=%d rolloff=%d\n", __func__, c->frequency, c->symbol_rate, c->rolloff); /* * Integer-N PLL synthesizer * kHz is used for all calculations to keep calculations within 32-bit */ - f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000); + f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000); div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000); if (c->symbol_rate < 5000000) @@ -204,14 +204,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = u8tmp; buf[1] = 0x40; - ret = m88ts2022_wr_regs(priv, 0x10, buf, 2); + ret = m88ts2022_wr_regs(dev, 0x10, buf, 2); if (ret) goto err; f_vco_khz = frequency_khz * div_out; pll_n = f_vco_khz * div_ref / f_ref_khz; pll_n += pll_n % 2; - priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; + dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; if (pll_n < 4095) u16tmp = pll_n - 1024; @@ -223,31 +223,31 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = (u16tmp >> 8) & 0x3f; buf[1] = (u16tmp >> 0) & 0xff; buf[2] = div_ref - 8; - ret = m88ts2022_wr_regs(priv, 0x01, buf, 3); + ret = m88ts2022_wr_regs(dev, 0x01, buf, 3); if (ret) goto err; - dev_dbg(&priv->client->dev, + dev_dbg(&dev->client->dev, "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", - __func__, priv->frequency_khz, - priv->frequency_khz - c->frequency, f_vco_khz, pll_n, + __func__, dev->frequency_khz, + dev->frequency_khz - c->frequency, f_vco_khz, pll_n, div_ref, div_out); ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) goto err; - ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x14, &u8tmp); if (ret) goto err; u8tmp &= 0x7f; if (u8tmp < 64) { - ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80); + ret = m88ts2022_wr_reg_mask(dev, 0x10, 0x80, 0x80); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x11, 0x6f); + ret = m88ts2022_wr_reg(dev, 0x11, 0x6f); if (ret) goto err; @@ -256,13 +256,13 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x14, &u8tmp); if (ret) goto err; u8tmp &= 0x1f; if (u8tmp > 19) { - ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02); + ret = m88ts2022_wr_reg_mask(dev, 0x10, 0x00, 0x02); if (ret) goto err; } @@ -271,26 +271,26 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x25, 0x00); + ret = m88ts2022_wr_reg(dev, 0x25, 0x00); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x27, 0x70); + ret = m88ts2022_wr_reg(dev, 0x27, 0x70); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x41, 0x09); + ret = m88ts2022_wr_reg(dev, 0x41, 0x09); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x08, 0x0b); + ret = m88ts2022_wr_reg(dev, 0x08, 0x0b); if (ret) goto err; /* filters */ gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U); - ret = m88ts2022_wr_reg(priv, 0x04, gdiv28); + ret = m88ts2022_wr_reg(dev, 0x04, gdiv28); if (ret) goto err; @@ -300,7 +300,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(priv, 0x41, 0x0d); + ret = m88ts2022_wr_reg(dev, 0x41, 0x0d); if (ret) goto err; @@ -328,11 +328,11 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max); - ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv); + ret = m88ts2022_wr_reg(dev, 0x04, lpf_mxdiv); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm); + ret = m88ts2022_wr_reg(dev, 0x06, lpf_gm); if (ret) goto err; @@ -342,7 +342,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(priv, 0x41, 0x09); + ret = m88ts2022_wr_reg(dev, 0x41, 0x09); if (ret) goto err; @@ -354,15 +354,15 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = (cap_code + u8tmp) / 2; u8tmp = cap_code | 0x80; - ret = m88ts2022_wr_reg(priv, 0x25, u8tmp); + ret = m88ts2022_wr_reg(dev, 0x25, u8tmp); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x27, 0x30); + ret = m88ts2022_wr_reg(dev, 0x27, 0x30); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x08, 0x09); + ret = m88ts2022_wr_reg(dev, 0x08, 0x09); if (ret) goto err; @@ -371,14 +371,14 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int m88ts2022_init(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret, i; u8 u8tmp; static const struct m88ts2022_reg_val reg_vals[] = { @@ -395,23 +395,23 @@ static int m88ts2022_init(struct dvb_frontend *fe) {0x12, 0xa0}, }; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "%s:\n", __func__); - ret = m88ts2022_wr_reg(priv, 0x00, 0x01); + ret = m88ts2022_wr_reg(dev, 0x00, 0x01); if (ret) goto err; - ret = m88ts2022_wr_reg(priv, 0x00, 0x03); + ret = m88ts2022_wr_reg(dev, 0x00, 0x03); if (ret) goto err; - switch (priv->cfg.clock_out) { + switch (dev->cfg.clock_out) { case M88TS2022_CLOCK_OUT_DISABLED: u8tmp = 0x60; break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); + ret = m88ts2022_wr_reg(dev, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -422,61 +422,61 @@ static int m88ts2022_init(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); + ret = m88ts2022_wr_reg(dev, 0x42, u8tmp); if (ret) goto err; - if (priv->cfg.loop_through) + if (dev->cfg.loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); + ret = m88ts2022_wr_reg(dev, 0x62, u8tmp); if (ret) goto err; for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val); + ret = m88ts2022_wr_reg(dev, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; } err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int m88ts2022_sleep(struct dvb_frontend *fe) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "%s:\n", __func__); - ret = m88ts2022_wr_reg(priv, 0x00, 0x00); + ret = m88ts2022_wr_reg(dev, 0x00, 0x00); if (ret) goto err; err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "%s:\n", __func__); - *frequency = priv->frequency_khz; + *frequency = dev->frequency_khz; return 0; } static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; - dev_dbg(&priv->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "%s:\n", __func__); *frequency = 0; /* Zero-IF */ return 0; @@ -484,27 +484,27 @@ static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) { - struct m88ts2022_priv *priv = fe->tuner_priv; + struct m88ts2022_dev *dev = fe->tuner_priv; int ret; u8 u8tmp; u16 gain, u16tmp; unsigned int gain1, gain2, gain3; - ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x3d, &u8tmp); if (ret) goto err; gain1 = (u8tmp >> 0) & 0x1f; gain1 = clamp(gain1, 0U, 15U); - ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x21, &u8tmp); if (ret) goto err; gain2 = (u8tmp >> 0) & 0x1f; gain2 = clamp(gain2, 2U, 16U); - ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x66, &u8tmp); if (ret) goto err; @@ -520,7 +520,7 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000); err: if (ret) - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -545,44 +545,44 @@ static int m88ts2022_probe(struct i2c_client *client, { struct m88ts2022_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct m88ts2022_priv *priv; + struct m88ts2022_dev *dev; int ret; u8 chip_id, u8tmp; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); goto err; } - memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config)); - priv->client = client; + memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config)); + dev->client = client; /* check if the tuner is there */ - ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp); + ret = m88ts2022_rd_reg(dev, 0x00, &u8tmp); if (ret) goto err; if ((u8tmp & 0x03) == 0x00) { - ret = m88ts2022_wr_reg(priv, 0x00, 0x01); + ret = m88ts2022_wr_reg(dev, 0x00, 0x01); if (ret < 0) goto err; usleep_range(2000, 50000); } - ret = m88ts2022_wr_reg(priv, 0x00, 0x03); + ret = m88ts2022_wr_reg(dev, 0x00, 0x03); if (ret) goto err; usleep_range(2000, 50000); - ret = m88ts2022_rd_reg(priv, 0x00, &chip_id); + ret = m88ts2022_rd_reg(dev, 0x00, &chip_id); if (ret) goto err; - dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&dev->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); switch (chip_id) { case 0xc3: @@ -592,13 +592,13 @@ static int m88ts2022_probe(struct i2c_client *client, goto err; } - switch (priv->cfg.clock_out) { + switch (dev->cfg.clock_out) { case M88TS2022_CLOCK_OUT_DISABLED: u8tmp = 0x60; break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div); + ret = m88ts2022_wr_reg(dev, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -609,50 +609,50 @@ static int m88ts2022_probe(struct i2c_client *client, goto err; } - ret = m88ts2022_wr_reg(priv, 0x42, u8tmp); + ret = m88ts2022_wr_reg(dev, 0x42, u8tmp); if (ret) goto err; - if (priv->cfg.loop_through) + if (dev->cfg.loop_through) u8tmp = 0xec; else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(priv, 0x62, u8tmp); + ret = m88ts2022_wr_reg(dev, 0x62, u8tmp); if (ret) goto err; /* sleep */ - ret = m88ts2022_wr_reg(priv, 0x00, 0x00); + ret = m88ts2022_wr_reg(dev, 0x00, 0x00); if (ret) goto err; - dev_info(&priv->client->dev, + dev_info(&dev->client->dev, "%s: Montage M88TS2022 successfully identified\n", KBUILD_MODNAME); - fe->tuner_priv = priv; + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops, sizeof(struct dvb_tuner_ops)); - i2c_set_clientdata(client, priv); + i2c_set_clientdata(client, dev); return 0; err: dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); + kfree(dev); return ret; } static int m88ts2022_remove(struct i2c_client *client) { - struct m88ts2022_priv *priv = i2c_get_clientdata(client); - struct dvb_frontend *fe = priv->cfg.fe; + struct m88ts2022_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->cfg.fe; dev_dbg(&client->dev, "%s:\n", __func__); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(priv); + kfree(dev); return 0; } diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h index 0363dd866a2d..e7f6c91a7f72 100644 --- a/drivers/media/tuners/m88ts2022_priv.h +++ b/drivers/media/tuners/m88ts2022_priv.h @@ -19,7 +19,7 @@ #include "m88ts2022.h" -struct m88ts2022_priv { +struct m88ts2022_dev { struct m88ts2022_config cfg; struct i2c_client *client; struct dvb_frontend *fe; -- cgit v1.2.3 From b8d67ab656288457a6728284d3a054544f629979 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 17:07:17 -0300 Subject: [media] m88ts2022: clean up logging There is no need to print module name nor function name as those are done by kernel logging system when dev_xxx logging is used and driver is proper I2C driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/m88ts2022.c | 51 +++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 94f0d3b7536a..4d7f7e178a04 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -46,8 +46,8 @@ static int m88ts2022_wr_regs(struct m88ts2022_dev *dev, ret = 0; } else { dev_warn(&dev->client->dev, - "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + "i2c wr failed=%d reg=%02x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -85,8 +85,8 @@ static int m88ts2022_rd_regs(struct m88ts2022_dev *dev, u8 reg, ret = 0; } else { dev_warn(&dev->client->dev, - "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + "i2c rd failed=%d reg=%02x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -141,8 +141,8 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, for (i = 0; i < 2; i++) { dev_dbg(&dev->client->dev, - "%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n", - __func__, i, op, reg, mask, val); + "i=%d op=%02x reg=%02x mask=%02x val=%02x\n", + i, op, reg, mask, val); for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { ret = m88ts2022_wr_reg(dev, reg_vals[i].reg, @@ -178,8 +178,8 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) u16 u16tmp; dev_dbg(&dev->client->dev, - "%s: frequency=%d symbol_rate=%d rolloff=%d\n", - __func__, c->frequency, c->symbol_rate, c->rolloff); + "frequency=%d symbol_rate=%d rolloff=%d\n", + c->frequency, c->symbol_rate, c->rolloff); /* * Integer-N PLL synthesizer * kHz is used for all calculations to keep calculations within 32-bit @@ -228,10 +228,9 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; dev_dbg(&dev->client->dev, - "%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", - __func__, dev->frequency_khz, - dev->frequency_khz - c->frequency, f_vco_khz, pll_n, - div_ref, div_out); + "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", + dev->frequency_khz, dev->frequency_khz - c->frequency, + f_vco_khz, pll_n, div_ref, div_out); ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) @@ -371,7 +370,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -395,7 +394,7 @@ static int m88ts2022_init(struct dvb_frontend *fe) {0x12, 0xa0}, }; - dev_dbg(&dev->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); ret = m88ts2022_wr_reg(dev, 0x00, 0x01); if (ret) @@ -442,7 +441,7 @@ static int m88ts2022_init(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -451,14 +450,14 @@ static int m88ts2022_sleep(struct dvb_frontend *fe) struct m88ts2022_dev *dev = fe->tuner_priv; int ret; - dev_dbg(&dev->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); ret = m88ts2022_wr_reg(dev, 0x00, 0x00); if (ret) goto err; err: if (ret) - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -466,7 +465,7 @@ static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct m88ts2022_dev *dev = fe->tuner_priv; - dev_dbg(&dev->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); *frequency = dev->frequency_khz; return 0; @@ -476,7 +475,7 @@ static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct m88ts2022_dev *dev = fe->tuner_priv; - dev_dbg(&dev->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); *frequency = 0; /* Zero-IF */ return 0; @@ -520,7 +519,7 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000); err: if (ret) - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -552,7 +551,7 @@ static int m88ts2022_probe(struct i2c_client *client, dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -582,7 +581,7 @@ static int m88ts2022_probe(struct i2c_client *client, if (ret) goto err; - dev_dbg(&dev->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id); switch (chip_id) { case 0xc3: @@ -627,9 +626,7 @@ static int m88ts2022_probe(struct i2c_client *client, if (ret) goto err; - dev_info(&dev->client->dev, - "%s: Montage M88TS2022 successfully identified\n", - KBUILD_MODNAME); + dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n"); fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops, @@ -638,7 +635,7 @@ static int m88ts2022_probe(struct i2c_client *client, i2c_set_clientdata(client, dev); return 0; err: - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(dev); return ret; } @@ -648,7 +645,7 @@ static int m88ts2022_remove(struct i2c_client *client) struct m88ts2022_dev *dev = i2c_get_clientdata(client); struct dvb_frontend *fe = dev->cfg.fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; -- cgit v1.2.3 From 35c77a85463cacf7fe2fa8e998698170c42e80f6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 18:22:05 -0300 Subject: [media] m88ts2022: convert to RegMap I2C API Use RegMap to cover I2C register routines. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 1 + drivers/media/tuners/m88ts2022.c | 231 ++++++++++------------------------ drivers/media/tuners/m88ts2022_priv.h | 2 + 3 files changed, 69 insertions(+), 165 deletions(-) diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index d79fd1ce5a18..83199964b54e 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -226,6 +226,7 @@ config MEDIA_TUNER_FC2580 config MEDIA_TUNER_M88TS2022 tristate "Montage M88TS2022 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Montage M88TS2022 silicon tuner driver. diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 4d7f7e178a04..9f7ebcfc2fa1 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -18,120 +18,12 @@ #include "m88ts2022_priv.h" -/* write multiple registers */ -static int m88ts2022_wr_regs(struct m88ts2022_dev *dev, - u8 reg, const u8 *val, int len) -{ -#define MAX_WR_LEN 3 -#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) - int ret; - u8 buf[MAX_WR_XFER_LEN]; - struct i2c_msg msg[1] = { - { - .addr = dev->client->addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_WR_LEN)) - return -EINVAL; - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(dev->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&dev->client->dev, - "i2c wr failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* read multiple registers */ -static int m88ts2022_rd_regs(struct m88ts2022_dev *dev, u8 reg, - u8 *val, int len) -{ -#define MAX_RD_LEN 1 -#define MAX_RD_XFER_LEN (MAX_RD_LEN) - int ret; - u8 buf[MAX_RD_XFER_LEN]; - struct i2c_msg msg[2] = { - { - .addr = dev->client->addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = dev->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_RD_LEN)) - return -EINVAL; - - ret = i2c_transfer(dev->client->adapter, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&dev->client->dev, - "i2c rd failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int m88ts2022_wr_reg(struct m88ts2022_dev *dev, u8 reg, u8 val) -{ - return m88ts2022_wr_regs(dev, reg, &val, 1); -} - -/* read single register */ -static int m88ts2022_rd_reg(struct m88ts2022_dev *dev, u8 reg, u8 *val) -{ - return m88ts2022_rd_regs(dev, reg, val, 1); -} - -/* write single register with mask */ -static int m88ts2022_wr_reg_mask(struct m88ts2022_dev *dev, - u8 reg, u8 val, u8 mask) -{ - int ret; - u8 u8tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = m88ts2022_rd_regs(dev, reg, &u8tmp, 1); - if (ret) - return ret; - - val &= mask; - u8tmp &= ~mask; - val |= u8tmp; - } - - return m88ts2022_wr_regs(dev, reg, &val, 1); -} - static int m88ts2022_cmd(struct dvb_frontend *fe, int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val) { struct m88ts2022_dev *dev = fe->tuner_priv; int ret, i; - u8 u8tmp; + unsigned int utmp; struct m88ts2022_reg_val reg_vals[] = { {0x51, 0x1f - op}, {0x51, 0x1f}, @@ -145,7 +37,7 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, i, op, reg, mask, val); for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(dev, reg_vals[i].reg, + ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; @@ -153,16 +45,16 @@ static int m88ts2022_cmd(struct dvb_frontend *fe, usleep_range(sleep * 1000, sleep * 10000); - ret = m88ts2022_rd_reg(dev, reg, &u8tmp); + ret = regmap_read(dev->regmap, reg, &utmp); if (ret) goto err; - if ((u8tmp & mask) != val) + if ((utmp & mask) != val) break; } if (reg_val) - *reg_val = u8tmp; + *reg_val = utmp; err: return ret; } @@ -172,7 +64,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) struct m88ts2022_dev *dev = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int frequency_khz, frequency_offset_khz, f_3db_hz; + unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz; unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28; u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; u16 u16tmp; @@ -204,7 +96,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = u8tmp; buf[1] = 0x40; - ret = m88ts2022_wr_regs(dev, 0x10, buf, 2); + ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2); if (ret) goto err; @@ -223,7 +115,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) buf[0] = (u16tmp >> 8) & 0x3f; buf[1] = (u16tmp >> 0) & 0xff; buf[2] = div_ref - 8; - ret = m88ts2022_wr_regs(dev, 0x01, buf, 3); + ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3); if (ret) goto err; @@ -236,17 +128,17 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_rd_reg(dev, 0x14, &u8tmp); + ret = regmap_read(dev->regmap, 0x14, &utmp); if (ret) goto err; - u8tmp &= 0x7f; - if (u8tmp < 64) { - ret = m88ts2022_wr_reg_mask(dev, 0x10, 0x80, 0x80); + utmp &= 0x7f; + if (utmp < 64) { + ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x11, 0x6f); + ret = regmap_write(dev->regmap, 0x11, 0x6f); if (ret) goto err; @@ -255,13 +147,13 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_rd_reg(dev, 0x14, &u8tmp); + ret = regmap_read(dev->regmap, 0x14, &utmp); if (ret) goto err; - u8tmp &= 0x1f; - if (u8tmp > 19) { - ret = m88ts2022_wr_reg_mask(dev, 0x10, 0x00, 0x02); + utmp &= 0x1f; + if (utmp > 19) { + ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00); if (ret) goto err; } @@ -270,26 +162,26 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x25, 0x00); + ret = regmap_write(dev->regmap, 0x25, 0x00); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x27, 0x70); + ret = regmap_write(dev->regmap, 0x27, 0x70); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x41, 0x09); + ret = regmap_write(dev->regmap, 0x41, 0x09); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x08, 0x0b); + ret = regmap_write(dev->regmap, 0x08, 0x0b); if (ret) goto err; /* filters */ gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U); - ret = m88ts2022_wr_reg(dev, 0x04, gdiv28); + ret = regmap_write(dev->regmap, 0x04, gdiv28); if (ret) goto err; @@ -299,7 +191,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(dev, 0x41, 0x0d); + ret = regmap_write(dev->regmap, 0x41, 0x0d); if (ret) goto err; @@ -327,11 +219,11 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max); - ret = m88ts2022_wr_reg(dev, 0x04, lpf_mxdiv); + ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x06, lpf_gm); + ret = regmap_write(dev->regmap, 0x06, lpf_gm); if (ret) goto err; @@ -341,7 +233,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = u8tmp & 0x3f; - ret = m88ts2022_wr_reg(dev, 0x41, 0x09); + ret = regmap_write(dev->regmap, 0x41, 0x09); if (ret) goto err; @@ -353,15 +245,15 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) cap_code = (cap_code + u8tmp) / 2; u8tmp = cap_code | 0x80; - ret = m88ts2022_wr_reg(dev, 0x25, u8tmp); + ret = regmap_write(dev->regmap, 0x25, u8tmp); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x27, 0x30); + ret = regmap_write(dev->regmap, 0x27, 0x30); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x08, 0x09); + ret = regmap_write(dev->regmap, 0x08, 0x09); if (ret) goto err; @@ -396,11 +288,11 @@ static int m88ts2022_init(struct dvb_frontend *fe) dev_dbg(&dev->client->dev, "\n"); - ret = m88ts2022_wr_reg(dev, 0x00, 0x01); + ret = regmap_write(dev->regmap, 0x00, 0x01); if (ret) goto err; - ret = m88ts2022_wr_reg(dev, 0x00, 0x03); + ret = regmap_write(dev->regmap, 0x00, 0x03); if (ret) goto err; @@ -410,7 +302,7 @@ static int m88ts2022_init(struct dvb_frontend *fe) break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(dev, 0x05, dev->cfg.clock_out_div); + ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -421,7 +313,7 @@ static int m88ts2022_init(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_wr_reg(dev, 0x42, u8tmp); + ret = regmap_write(dev->regmap, 0x42, u8tmp); if (ret) goto err; @@ -430,12 +322,12 @@ static int m88ts2022_init(struct dvb_frontend *fe) else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(dev, 0x62, u8tmp); + ret = regmap_write(dev->regmap, 0x62, u8tmp); if (ret) goto err; for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = m88ts2022_wr_reg(dev, reg_vals[i].reg, reg_vals[i].val); + ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val); if (ret) goto err; } @@ -452,7 +344,7 @@ static int m88ts2022_sleep(struct dvb_frontend *fe) dev_dbg(&dev->client->dev, "\n"); - ret = m88ts2022_wr_reg(dev, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; err: @@ -485,29 +377,28 @@ static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) { struct m88ts2022_dev *dev = fe->tuner_priv; int ret; - u8 u8tmp; u16 gain, u16tmp; - unsigned int gain1, gain2, gain3; + unsigned int utmp, gain1, gain2, gain3; - ret = m88ts2022_rd_reg(dev, 0x3d, &u8tmp); + ret = regmap_read(dev->regmap, 0x3d, &utmp); if (ret) goto err; - gain1 = (u8tmp >> 0) & 0x1f; + gain1 = (utmp >> 0) & 0x1f; gain1 = clamp(gain1, 0U, 15U); - ret = m88ts2022_rd_reg(dev, 0x21, &u8tmp); + ret = regmap_read(dev->regmap, 0x21, &utmp); if (ret) goto err; - gain2 = (u8tmp >> 0) & 0x1f; + gain2 = (utmp >> 0) & 0x1f; gain2 = clamp(gain2, 2U, 16U); - ret = m88ts2022_rd_reg(dev, 0x66, &u8tmp); + ret = regmap_read(dev->regmap, 0x66, &utmp); if (ret) goto err; - gain3 = (u8tmp >> 3) & 0x07; + gain3 = (utmp >> 3) & 0x07; gain3 = clamp(gain3, 0U, 6U); gain = gain1 * 265 + gain2 * 338 + gain3 * 285; @@ -546,7 +437,12 @@ static int m88ts2022_probe(struct i2c_client *client, struct dvb_frontend *fe = cfg->fe; struct m88ts2022_dev *dev; int ret; - u8 chip_id, u8tmp; + u8 u8tmp; + unsigned int utmp; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { @@ -557,33 +453,38 @@ static int m88ts2022_probe(struct i2c_client *client, memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config)); dev->client = client; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err; + } /* check if the tuner is there */ - ret = m88ts2022_rd_reg(dev, 0x00, &u8tmp); + ret = regmap_read(dev->regmap, 0x00, &utmp); if (ret) goto err; - if ((u8tmp & 0x03) == 0x00) { - ret = m88ts2022_wr_reg(dev, 0x00, 0x01); - if (ret < 0) + if ((utmp & 0x03) == 0x00) { + ret = regmap_write(dev->regmap, 0x00, 0x01); + if (ret) goto err; usleep_range(2000, 50000); } - ret = m88ts2022_wr_reg(dev, 0x00, 0x03); + ret = regmap_write(dev->regmap, 0x00, 0x03); if (ret) goto err; usleep_range(2000, 50000); - ret = m88ts2022_rd_reg(dev, 0x00, &chip_id); + ret = regmap_read(dev->regmap, 0x00, &utmp); if (ret) goto err; - dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id); + dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp); - switch (chip_id) { + switch (utmp) { case 0xc3: case 0x83: break; @@ -597,7 +498,7 @@ static int m88ts2022_probe(struct i2c_client *client, break; case M88TS2022_CLOCK_OUT_ENABLED: u8tmp = 0x70; - ret = m88ts2022_wr_reg(dev, 0x05, dev->cfg.clock_out_div); + ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); if (ret) goto err; break; @@ -608,7 +509,7 @@ static int m88ts2022_probe(struct i2c_client *client, goto err; } - ret = m88ts2022_wr_reg(dev, 0x42, u8tmp); + ret = regmap_write(dev->regmap, 0x42, u8tmp); if (ret) goto err; @@ -617,12 +518,12 @@ static int m88ts2022_probe(struct i2c_client *client, else u8tmp = 0x6c; - ret = m88ts2022_wr_reg(dev, 0x62, u8tmp); + ret = regmap_write(dev->regmap, 0x62, u8tmp); if (ret) goto err; /* sleep */ - ret = m88ts2022_wr_reg(dev, 0x00, 0x00); + ret = regmap_write(dev->regmap, 0x00, 0x00); if (ret) goto err; diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h index e7f6c91a7f72..56c107160f4e 100644 --- a/drivers/media/tuners/m88ts2022_priv.h +++ b/drivers/media/tuners/m88ts2022_priv.h @@ -18,10 +18,12 @@ #define M88TS2022_PRIV_H #include "m88ts2022.h" +#include struct m88ts2022_dev { struct m88ts2022_config cfg; struct i2c_client *client; + struct regmap *regmap; struct dvb_frontend *fe; u32 frequency_khz; }; -- cgit v1.2.3 From f461694b965b8cdf67c330d14c802a74acf7bec1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Aug 2014 18:32:28 -0300 Subject: [media] m88ts2022: change parameter type of m88ts2022_cmd It is driver internal function and does not need anything from frontend structure. Due to that change parameter type to driver state which is better for driver internal functions. Also remove one unused variable from state itself. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/m88ts2022.c | 21 ++++++++++----------- drivers/media/tuners/m88ts2022_priv.h | 1 - 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c index 9f7ebcfc2fa1..caa542346891 100644 --- a/drivers/media/tuners/m88ts2022.c +++ b/drivers/media/tuners/m88ts2022.c @@ -18,10 +18,9 @@ #include "m88ts2022_priv.h" -static int m88ts2022_cmd(struct dvb_frontend *fe, - int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val) +static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg, + u8 mask, u8 val, u8 *reg_val) { - struct m88ts2022_dev *dev = fe->tuner_priv; int ret, i; unsigned int utmp; struct m88ts2022_reg_val reg_vals[] = { @@ -124,7 +123,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) dev->frequency_khz, dev->frequency_khz - c->frequency, f_vco_khz, pll_n, div_ref, div_out); - ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) goto err; @@ -142,7 +141,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); if (ret) goto err; } @@ -158,7 +157,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) goto err; } - ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL); if (ret) goto err; @@ -185,7 +184,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -195,7 +194,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -227,7 +226,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -237,7 +236,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); + ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); if (ret) goto err; @@ -257,7 +256,7 @@ static int m88ts2022_set_params(struct dvb_frontend *fe) if (ret) goto err; - ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL); + ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL); if (ret) goto err; err: diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h index 56c107160f4e..feeb5ad6beef 100644 --- a/drivers/media/tuners/m88ts2022_priv.h +++ b/drivers/media/tuners/m88ts2022_priv.h @@ -24,7 +24,6 @@ struct m88ts2022_dev { struct m88ts2022_config cfg; struct i2c_client *client; struct regmap *regmap; - struct dvb_frontend *fe; u32 frequency_khz; }; -- cgit v1.2.3 From 59234e5973b31dd7f7253233a00ae05b3176439f Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Wed, 4 Jun 2014 09:03:39 -0300 Subject: [media] trivial: drivers/media/usb/gspca/gspca.c: fix the indentation of a comment Fix indentation of a comment, put it on the same level of the code it refers to. Signed-off-by: Antonio Ospite Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index e8cf23c91cef..43d65057a5fe 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -876,9 +876,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) ep_tb[0].alt = gspca_dev->alt; alt_idx = 1; } else { - - /* else, compute the minimum bandwidth - * and build the endpoint table */ + /* else, compute the minimum bandwidth + * and build the endpoint table */ alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb); if (alt_idx <= 0) { pr_err("no transfer endpoint found\n"); -- cgit v1.2.3 From 751e78d0f5c3e90203682b6acc2a5cdf447a646d Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Wed, 4 Jun 2014 09:03:40 -0300 Subject: [media] trivial: drivers/media/usb/gspca/gspca.h: indent with TABs, not spaces Signed-off-by: Antonio Ospite Cc: Hans de Goede Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index f06253cd7469..d39adf90303b 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -235,6 +235,6 @@ int gspca_resume(struct usb_interface *intf); int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum, int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev, - int avg_lum, int desired_avg_lum, int deadzone); + int avg_lum, int desired_avg_lum, int deadzone); #endif /* GSPCAV2_H */ -- cgit v1.2.3 From 1d54b3a43cd1228dc90dcd331eb735f79e3b021e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 04:18:23 -0300 Subject: [media] vivid: remove duplicate and unused g/s_edid functions I'm not sure how I missed this, but they should be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-out.c | 57 ---------------------------- drivers/media/platform/vivid/vivid-vid-out.h | 1 - 2 files changed, 58 deletions(-) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 8ed9f6d9f505..d0e0e955b3de 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1113,63 +1113,6 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, return 0; } -#if 0 -int vivid_vid_out_g_edid(struct file *file, void *_fh, - struct v4l2_edid *edid) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - memset(edid->reserved, 0, sizeof(edid->reserved)); - if (vdev->vfl_dir == VFL_DIR_RX) { - if (edid->pad >= dev->num_inputs) - return -EINVAL; - if (dev->input_type[edid->pad] != HDMI) - return -EINVAL; - } else { - if (edid->pad >= dev->num_outputs) - return -EINVAL; - if (dev->output_type[edid->pad] != HDMI) - return -EINVAL; - } - if (edid->start_block == 0 && edid->blocks == 0) { - edid->blocks = dev->edid_blocks; - return 0; - } - if (dev->edid_blocks == 0) - return -ENODATA; - if (edid->start_block >= dev->edid_blocks) - return -EINVAL; - if (edid->start_block + edid->blocks > dev->edid_blocks) - edid->blocks = dev->edid_blocks - edid->start_block; - memcpy(edid->edid, dev->edid, edid->blocks * 128); - return 0; -} - -int vivid_vid_out_s_edid(struct file *file, void *_fh, - struct v4l2_edid *edid) -{ - struct vivid_dev *dev = video_drvdata(file); - - memset(edid->reserved, 0, sizeof(edid->reserved)); - if (edid->pad >= dev->num_inputs) - return -EINVAL; - if (dev->input_type[edid->pad] != HDMI || edid->start_block) - return -EINVAL; - if (edid->blocks == 0) { - dev->edid_blocks = 0; - return 0; - } - if (edid->blocks > dev->edid_max_blocks) { - edid->blocks = dev->edid_max_blocks; - return -E2BIG; - } - dev->edid_blocks = edid->blocks; - memcpy(dev->edid, edid->edid, edid->blocks * 128); - return 0; -} -#endif - int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h index a237465432e7..dfa84db184ed 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -51,7 +51,6 @@ int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); #endif -- cgit v1.2.3 From 5754d0d586a5d7c6a6fa43551f6e3b377c5f111d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 04:29:00 -0300 Subject: [media] vivid: add missing includes Fix kbuild test robot warnings about missing vmalloc.h and string.h includes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 1 + drivers/media/platform/vivid/vivid-rds-gen.c | 1 + drivers/media/platform/vivid/vivid-tpg.h | 1 + drivers/media/platform/vivid/vivid-vbi-gen.c | 1 + drivers/media/platform/vivid/vivid-vid-cap.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index fb3b0aad33ed..2c61a62ab48b 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c index dab5463e26fa..c382343fdb66 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ b/drivers/media/platform/vivid/vivid-rds-gen.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "vivid-rds-gen.h" diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 51ef7d1253c9..8ef3e52ba3be 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "vivid-tpg-colors.h" diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c index 22f4bcc6a6c0..450ec3ca5d9a 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "vivid-vbi-gen.h" diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 115437af1ee0..b016aeda7ff3 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 73d8102298719863d54264f62521362487f84256 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 10:18:57 -0300 Subject: [media] vivid: tpg_reset_source prototype mismatch Replaced enum v4l2_field by u32, just as the prototype in the header has. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 57ff428c897e..0c6fa53fa646 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -249,7 +249,7 @@ void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, } void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, - enum v4l2_field field) + u32 field) { unsigned p; -- cgit v1.2.3 From 453afdd9ce33293f640e84dc17e5f366701516e8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Aug 2014 06:43:01 -0300 Subject: [media] cx23885: convert to vb2 As usual, this patch is very large due to the fact that half a vb2 conversion isn't possible. And since this affects 417, alsa, core, dvb, vbi and video the changes are all over. What made this more difficult was the peculiar way the risc program was setup. The driver allowed for running out of buffers in which case the DMA would stop and restart when the next buffer was queued. There was also a complicated timeout system for when buffers weren't filled. This was replaced by a much simpler scheme where there is always one buffer around and the DMA will just cycle that buffer until a new buffer is queued. In that case the previous buffer will be chained to the new buffer. An interrupt is generated at the start of the new buffer telling the driver that the previous buffer can be passed on to userspace. Much simpler and more robust. The old code seems to be copied from the cx88 driver. But it didn't fit the vb2 ops very well and replacing it with the new scheme made the code easier to understand. Not to mention that this patch removes 600 lines of code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 4 +- drivers/media/pci/cx23885/altera-ci.c | 4 +- drivers/media/pci/cx23885/cx23885-417.c | 312 +++++------- drivers/media/pci/cx23885/cx23885-alsa.c | 4 +- drivers/media/pci/cx23885/cx23885-core.c | 305 ++++------- drivers/media/pci/cx23885/cx23885-dvb.c | 131 +++-- drivers/media/pci/cx23885/cx23885-vbi.c | 275 +++++----- drivers/media/pci/cx23885/cx23885-video.c | 810 ++++++++---------------------- drivers/media/pci/cx23885/cx23885.h | 61 +-- 9 files changed, 655 insertions(+), 1251 deletions(-) diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index e12c006e6e2d..38c3b7bc7c2a 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -7,8 +7,8 @@ config VIDEO_CX23885 select VIDEO_TUNER select VIDEO_TVEEPROM depends on RC_CORE - select VIDEOBUF_DVB - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DVB + select VIDEOBUF2_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 8302d444a0ba..2bbbf545b042 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -48,8 +48,8 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ -#include -#include +#include +#include #include "altera-ci.h" #include "dvb_ca_en50221.h" diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 56673b52c559..f1ef9017e2a7 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1138,47 +1138,100 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) /* ------------------------------------------------------------------ */ -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int 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 cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = q->drv_priv; - fh->q_dev->ts1.ts_packet_size = mpeglinesize; - fh->q_dev->ts1.ts_packet_count = mpeglines; + dev->ts1.ts_packet_size = mpeglinesize; + dev->ts1.ts_packet_count = mpeglines; + *num_planes = 1; + sizes[0] = mpeglinesize * mpeglines; + *num_buffers = mpegbufs; + return 0; +} - *size = fh->q_dev->ts1.ts_packet_size * fh->q_dev->ts1.ts_packet_count; - *count = mpegbufs; +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); - return 0; + return cx23885_buf_prepare(buf, &dev->ts1); } -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->q_dev->ts1, - (struct cx23885_buffer *)vb, - field); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->q_dev->ts1, (struct cx23885_buffer *)vb); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_buf_queue(&dev->ts1, buf); +} + +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq; + unsigned long flags; + int ret; + + ret = cx23885_initialize_codec(dev, 1); + if (ret == 0) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(&dev->ts1, dmaq, buf); + return 0; + } + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&dev->slock, flags); + return ret; } -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void cx23885_stop_streaming(struct vb2_queue *q) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); + struct cx23885_dev *dev = q->drv_priv; + + /* stop mpeg capture */ + cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); + + msleep(500); + cx23885_417_check_encoder(dev); + cx23885_cancel_buffers(&dev->ts1); } -static struct videobuf_queue_ops cx23885_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, +static struct vb2_ops cx23885_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, }; /* ------------------------------------------------------------------ */ @@ -1316,7 +1369,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1325,9 +1377,9 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = 0; f->fmt.pix.width = dev->ts1.width; f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } @@ -1335,15 +1387,15 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; 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->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } @@ -1357,58 +1409,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; f->fmt.pix.colorspace = 0; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->mpegq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->mpegq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->mpegq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx23885_fh *fh = priv; - - return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamon(&fh->mpegq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->mpegq); -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_dev *dev = video_drvdata(file); @@ -1420,120 +1426,14 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } -static int mpeg_open(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh; - - dprintk(2, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = fh; - fh->q_dev = dev; - - videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, - &dev->pci->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - v4l2_fh_add(&fh->fh); - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - msleep(500); - cx23885_417_check_encoder(dev); - - cx23885_cancel_buffers(&dev->ts1); - } - } - - if (fh->mpegq.streaming) - videobuf_streamoff(&fh->mpegq); - if (fh->mpegq.reading) - videobuf_read_stop(&fh->mpegq); - - videobuf_mmap_free(&fh->mpegq); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - file->private_data = NULL; - kfree(fh); - - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - /* 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) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev, 1) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s\n", __func__); - - return videobuf_poll_stream(file, &fh->mpegq, wait); -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->mpegq, vma); -} - static struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { @@ -1551,12 +1451,13 @@ static const struct v4l2_ioctl_ops mpeg_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_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .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, .vidioc_log_status = vidioc_log_status, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, @@ -1613,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev) /* FIXME: Port1 hardcoded here */ int err = -ENODEV; struct cx23885_tsport *tsport = &dev->ts1; + struct vb2_queue *q; dprintk(1, "%s()\n", __func__); @@ -1640,8 +1542,24 @@ int cx23885_417_register(struct cx23885_dev *dev) /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); + q = &dev->vb2_mpegq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; video_set_drvdata(dev->v4l_device, dev); dev->v4l_device->lock = &dev->lock; + dev->v4l_device->queue = q; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index c17e4740d47c..1b162ee8c8c6 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -389,6 +389,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, return -ENOMEM; buf->bpl = chip->period_size; + chip->buf = buf; ret = cx23885_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); @@ -409,8 +410,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - chip->buf = buf; - substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; @@ -419,6 +418,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, error: kfree(buf); + chip->buf = NULL; return ret; } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 0b6bbac6990f..8d77a5649777 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -416,39 +416,23 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -void cx23885_wakeup(struct cx23885_tsport *port, +static void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - int bc; - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.sequence = q->count++; + dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_sram_channel_setup(struct cx23885_dev *dev, @@ -478,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); + cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET); + cx_write(8 + 4, 12); cx_write(8 + 8, 0); /* write CDT */ @@ -695,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev) return -EBUSY; } -static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -715,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, port->nr = portno; INIT_LIST_HEAD(&port->mpegq.active); - INIT_LIST_HEAD(&port->mpegq.queued); - port->mpegq.timeout.function = cx23885_timeout; - port->mpegq.timeout.data = (unsigned long)port; - init_timer(&port->mpegq.timeout); - mutex_init(&port->frontends.lock); INIT_LIST_HEAD(&port->frontends.felist); port->frontends.active_fe_id = 0; @@ -772,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, BUG(); } - cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, - port->reg_dma_ctl, port->dma_ctl_val, 0x00); - return 0; } @@ -1085,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) + unsigned int lines, unsigned int lpi, bool jump) { struct scatterlist *sg; unsigned int line, todo, sol; + + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(0); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + } + /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); @@ -1164,7 +1143,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; + instructions += 5; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; @@ -1173,10 +1152,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines, 0); + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines, 0); + bpl, padding, lines, 0, UNSET == top_offset); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1200,7 +1179,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, than PAGE_SIZE */ /* Jump and write need an extra dword */ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; + instructions += 4; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) @@ -1209,7 +1188,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, /* write risc instructions */ rp = risc->cpu; rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, - bpl, 0, lines, lpi); + bpl, 0, lines, lpi, lpi == 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1239,7 +1218,7 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; + instructions += 5; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; @@ -1250,11 +1229,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, * in the userland vbi payload */ if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 6, - bpl, padding, lines, 0); + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, - bpl, padding, lines, 0); + bpl, padding, lines, 0, UNSET == top_offset); @@ -1265,38 +1244,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4*16); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + btcx_riscmem_free(dev->pci, &buf->risc); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) @@ -1351,7 +1302,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); } -static int cx23885_start_dma(struct cx23885_tsport *port, +int cx23885_start_dma(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { @@ -1359,7 +1310,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, u32 reg; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, - buf->vb.width, buf->vb.height, buf->vb.field); + dev->width, dev->height, dev->field); /* Stop the fifo and risc engine for this port */ cx_clear(port->reg_dma_ctl, port->dma_ctl_val); @@ -1375,7 +1326,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, } /* write TS length to chip */ - cx_write(port->reg_lngth, buf->vb.width); + cx_write(port->reg_lngth, port->ts_packet_size); if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { @@ -1404,7 +1355,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* NOTE: this is 2 (reserved) for portb, does it matter? */ /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); - q->count = 1; + q->count = 0; /* Set VIDB pins to input */ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { @@ -1493,134 +1444,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_buffer *buf; - - dprintk(5, "%s()\n", __func__); - if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; - - dprintk(5, "%s() queue is empty\n", __func__); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5, "[%p/%d] restart_queue - f/active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(5, "[%p/%d] restart_queue - m/active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } - return 0; - } - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_dma(port, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - /* ------------------------------------------------------------------ */ -int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field) +int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; int size = port->ts_packet_size * port->ts_packet_count; + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0); int rc; dprintk(1, "%s: %p\n", __func__, buf); - if (0 != buf->vb.baddr && buf->vb.bsize < size) + if (vb2_plane_size(&buf->vb, 0) < size) return -EINVAL; + vb2_set_plane_payload(&buf->vb, 0, size); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = port->ts_packet_size; - buf->vb.height = port->ts_packet_count; - buf->vb.size = size; - buf->vb.field = field /*V4L2_FIELD_TOP*/; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_databuffer(dev->pci, &buf->risc, - videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height, 0); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!rc) + return -EIO; - fail: - cx23885_free_buffer(q, buf); - return rc; + cx23885_risc_databuffer(dev->pci, &buf->risc, + sgt->sgl, + port->ts_packet_size, port->ts_packet_count, 0); + return 0; } +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) { struct cx23885_buffer *prev; struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *cx88q = &port->mpegq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + spin_lock_irqsave(&dev->slock, flags); if (list_empty(&cx88q->active)) { - dprintk(1, "queue is empty - first active\n"); - list_add_tail(&buf->vb.queue, &cx88q->active); - cx23885_start_dma(port, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + list_add_tail(&buf->queue, &cx88q->active); dprintk(1, "[%p/%d] %s - first active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } else { - dprintk(1, "queue is not empty - append to active\n"); + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; + queue); + list_add_tail(&buf->queue, &cx88q->active); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk(1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } + spin_unlock_irqrestore(&dev->slock, flags); } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, - int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; @@ -1630,16 +1530,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); + queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", - buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); - } - if (restart) { - dprintk(1, "restarting queue\n"); - cx23885_restart_queue(port, q); + buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma); } spin_unlock_irqrestore(&port->slock, flags); } @@ -1647,27 +1542,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, void cx23885_cancel_buffers(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __func__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} - -static void cx23885_timeout(unsigned long data) -{ - struct cx23885_tsport *port = (struct cx23885_tsport *)data; - struct cx23885_dev *dev = port->dev; dprintk(1, "%s()\n", __func__); - - if (debug > 5) - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - cx23885_stop_dma(port); - do_cancel_buffers(port, "timeout", 1); + do_cancel_buffers(port, "cancel"); } int cx23885_irq_417(struct cx23885_dev *dev, u32 status) @@ -1717,11 +1595,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status) spin_lock(&port->slock); cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_B_MSK_RISCI2) { - dprintk(7, " VID_B_MSK_RISCI2\n"); - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); } if (status) { cx_write(port->reg_ts_int_stat, status); @@ -1773,14 +1646,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_BC_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - } if (status) { cx_write(port->reg_ts_int_stat, status); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index d71d59f6c6d6..332e6facc095 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -87,59 +87,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ -static int dvb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int 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 cx23885_tsport *port = q->priv_data; + struct cx23885_tsport *port = q->drv_priv; port->ts_packet_size = 188 * 4; port->ts_packet_count = 32; - - *size = port->ts_packet_size * port->ts_packet_count; - *count = 32; + *num_planes = 1; + sizes[0] = port->ts_packet_size * port->ts_packet_count; + *num_buffers = 32; return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) + +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + return cx23885_buf_prepare(buf, port); } -static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - cx23885_buf_queue(port, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void dvb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_buf_queue(port, buf); } static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { - struct videobuf_dvb_frontends *f; - struct videobuf_dvb_frontend *fe; + struct vb2_dvb_frontends *f; + struct vb2_dvb_frontend *fe; f = &port->frontends; if (f->gate <= 1) /* undefined or fe0 */ - fe = videobuf_dvb_get_frontend(f, 1); + fe = vb2_dvb_get_frontend(f, 1); else - fe = videobuf_dvb_get_frontend(f, f->gate); + fe = vb2_dvb_get_frontend(f, f->gate); if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); } -static struct videobuf_queue_ops dvb_qops = { - .buf_setup = dvb_buf_setup, - .buf_prepare = dvb_buf_prepare, - .buf_queue = dvb_buf_queue, - .buf_release = dvb_buf_release, +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_tsport *port = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &port->mpegq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(port, dmaq, buf); + return 0; +} + +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_tsport *port = q->drv_priv; + + cx23885_cancel_buffers(port); +} + +static struct vb2_ops dvb_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, }; static struct s5h1409_config hauppauge_generic_config = { @@ -859,16 +895,16 @@ static int dvb_register(struct cx23885_tsport *port) struct dib7000p_ops dib7000p_ops; struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + struct vb2_dvb_frontend *fe0, *fe1 = NULL; int mfe_shared = 0; /* bus not shared by default */ int ret; /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); if (!fe0) return -EINVAL; - /* init struct videobuf_dvb */ + /* init struct vb2_dvb */ fe0->dvb.name = dev->name; /* multi-frontend gate control is undefined or defaults to fe0 */ @@ -1388,7 +1424,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); } /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + fe1 = vb2_dvb_get_frontend(&port->frontends, 2); if (fe1 == NULL) goto frontend_detach; /* DVB-C init */ @@ -1528,7 +1564,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); /* register everything */ - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared); if (ret) goto frontend_detach; @@ -1577,14 +1613,14 @@ static int dvb_register(struct cx23885_tsport *port) frontend_detach: port->gate_ctrl = NULL; - videobuf_dvb_dealloc_frontends(&port->frontends); + vb2_dvb_dealloc_frontends(&port->frontends); return -EINVAL; } int cx23885_dvb_register(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; + struct vb2_dvb_frontend *fe0; struct cx23885_dev *dev = port->dev; int err, i; @@ -1601,13 +1637,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port) port->num_frontends); for (i = 1; i <= port->num_frontends; i++) { - if (videobuf_dvb_alloc_frontend( + struct vb2_queue *q; + + if (vb2_dvb_alloc_frontend( &port->frontends, i) == NULL) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } - fe0 = videobuf_dvb_get_frontend(&port->frontends, i); + fe0 = vb2_dvb_get_frontend(&port->frontends, i); if (!fe0) err = -EINVAL; @@ -1623,10 +1661,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), port, NULL); + q = &fe0->dvb.dvbq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = port; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &dvb_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; } err = dvb_register(port); if (err != 0) @@ -1638,7 +1687,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; + struct vb2_dvb_frontend *fe0; /* FIXME: in an error condition where the we have * an expected number of frontends (attach problem) @@ -1647,9 +1696,9 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) * This comment only applies to future boards IF they * implement MFE support. */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); if (fe0 && fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&port->frontends); + vb2_dvb_unregister_bus(&port->frontends); switch (port->dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 23790fadc6d5..67b71f9b41f4 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -38,9 +38,8 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ #define VBI_LINE_LENGTH 1440 -#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ -#define NTSC_VBI_END_LINE 21 -#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) +#define VBI_NTSC_LINE_COUNT 12 +#define VBI_PAL_LINE_COUNT 18 int cx23885_vbi_fmt(struct file *file, void *priv, @@ -48,22 +47,23 @@ int cx23885_vbi_fmt(struct file *file, void *priv, { struct cx23885_dev *dev = video_drvdata(file); + f->fmt.vbi.sampling_rate = 27000000; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sampling_rate = 27000000; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.flags = 0; f->fmt.vbi.start[0] = 10; - f->fmt.vbi.count[0] = 17; - f->fmt.vbi.start[1] = 263 + 10 + 1; - f->fmt.vbi.count[1] = 17; + f->fmt.vbi.start[1] = 272; + f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 - 1; - f->fmt.vbi.start[1] = 319 - 1; + f->fmt.vbi.start[0] = 6; + f->fmt.vbi.start[1] = 318; + f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT; } return 0; @@ -89,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) handled++; } - if (status & VID_BC_MSK_VBI_RISCI2) { - dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); - dprintk(2, "stopper vbi\n"); - spin_lock(&dev->slock); - cx23885_restart_vbi_queue(dev, &dev->vbiq); - spin_unlock(&dev->slock); - handled++; - } - return handled; } @@ -109,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], - buf->vb.width, buf->risc.dma); + VBI_LINE_LENGTH, buf->risc.dma); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); cx_write(VID_A_VBI_CTRL, 3); cx_write(VBI_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -128,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, return 0; } +/* ------------------------------------------------------------------ */ -int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +static int 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 cx23885_buffer *buf; - struct list_head *item; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_vbi_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + struct cx23885_dev *dev = q->drv_priv; + unsigned lines = VBI_PAL_LINE_COUNT; + + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; + *num_planes = 1; + sizes[0] = lines * VBI_LINE_LENGTH * 2; return 0; } -void cx23885_vbi_timeout(unsigned long data) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vbiq; - struct cx23885_buffer *buf; - unsigned long flags; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + unsigned lines = VBI_PAL_LINE_COUNT; + int ret; - /* Stop the VBI engine */ - cx_clear(VID_A_DMA_CTL, 0x22); + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx23885_restart_vbi_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} + if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2) + return -EINVAL; + vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2); -/* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 1440 -#define VBI_LINE_COUNT 17 + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; + cx23885_risc_vbibuffer(dev->pci, &buf->risc, + sgt->sgl, + 0, VBI_LINE_LENGTH * lines, + VBI_LINE_LENGTH, 0, + lines); return 0; } -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_vbibuffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); - fail: - cx23885_free_buffer(q, buf); - return rc; + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->q_dev; - struct cx23885_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_dmaqueue *q = &dev->vbiq; + unsigned long flags; + + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); dprintk(2, "[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; + queue); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } } -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - cx23885_free_buffer(q, buf); + cx23885_start_vbi_dma(dev, dmaq, buf); + return 0; } -struct videobuf_queue_ops cx23885_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + unsigned long flags; -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ + cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->slock, flags); +} + + +struct vb2_ops cx23885_vbi_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 9cd8cf48334b..c6921d4bb7dd 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -98,34 +98,18 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } + if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + buf->vb.v4l2_buf.sequence = q->count++; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) @@ -163,50 +147,6 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_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->resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); -} - int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) { /* 8 bit registers, 8 bit values */ @@ -356,7 +296,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -369,444 +309,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +static int 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 cx23885_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_video_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, - vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } + struct cx23885_dev *dev = q->drv_priv; - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; - - *size = (dev->fmt->depth * dev->width * dev->height) >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + *num_planes = 1; + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; return 0; } -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - int rc, init_buffer = 0; u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); int field_tff; + int ret; - if (WARN_ON(NULL == dev->fmt)) - return -EINVAL; + buf->bpl = (dev->width * dev->fmt->depth) >> 3; - if (dev->width < 48 || dev->width > norm_maxw(dev->tvnorm) || - dev->height < 32 || dev->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + if (vb2_plane_size(vb, 0) < dev->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, dev->height * buf->bpl); - if (buf->fmt != dev->fmt || - buf->vb.width != dev->width || - buf->vb.height != dev->height || - buf->vb.field != field) { - buf->fmt = dev->fmt; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - init_buffer = 1; - } + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } + switch (dev->field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) - /* NTSC or */ - field_tff = 1; - else - field_tff = 0; - - if (cx23885_boards[dev->board].force_bff) - /* PAL / SECAM OR 888 in NTSC MODE */ - field_tff = 0; - - if (field_tff) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating TFF/NTSC risc\n", + if (field_tff) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); + line0_offset = 0; + line1_offset = buf->bpl; } + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (dev->height >> 1), + buf->bpl, 0, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (dev->height >> 1), 0, + buf->bpl, 0, + dev->height >> 1); + break; + default: + BUG(); } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.v4l2_buf.index, dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} - fail: - cx23885_free_buffer(q, buf); - return rc; +static void buffer_finish(struct vb2_buffer *vb) +{ + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vidq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + /* add jump to start */ + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + spin_lock_irqsave(&dev->slock, flags); + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = file->private_data; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - return &fh->vidq; - case VFL_TYPE_VBI: - return &fh->vbiq; - default: - WARN_ON(1); - return NULL; - } -} - -static int get_resource(u32 type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - WARN_ON(1); - return 0; + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.v4l2_buf.index); } + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_open(struct file *file) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - - dprintk(1, "open dev=%s\n", - video_device_node_name(vdev)); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = &fh->fh; - fh->q_dev = dev; - - videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - - videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct cx23885_buffer), - fh, NULL); - - v4l2_fh_add(&fh->fh); - - dprintk(1, "post videobuf_queue_init()\n"); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + cx23885_start_video_dma(dev, dmaq, buf); return 0; } -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) +static void cx23885_stop_streaming(struct vb2_queue *q) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - if (res_locked(dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case VFL_TYPE_VBI: - if (!res_get(dev, fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - return -EINVAL; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - unsigned long req_events = poll_requested_events(wait); - unsigned int rc = 0; - - if (v4l2_event_pending(&fh->fh)) - rc = POLLPRI; - else - poll_wait(file, &fh->fh.wait, wait); - if (!(req_events & (POLLIN | POLLRDNORM))) - return rc; - - if (vdev->vfl_type == VFL_TYPE_VBI) { - if (!res_get(dev, fh, RESOURCE_VBI)) - return rc | POLLERR; - return rc | videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc |= POLLIN | POLLRDNORM; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + unsigned long flags; - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } + cx_clear(VID_A_DMA_CTL, 0x11); + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - - videobuf_mmap_free(&fh->vidq); - videobuf_mmap_free(&fh->vbiq); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - return videobuf_mmap_mapper(get_queue(file), vma); -} +static struct vb2_ops cx23885_video_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -815,11 +517,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = priv; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.field = dev->field; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -880,7 +581,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = priv; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -892,9 +592,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; + dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - dev->width, dev->height, fh->vidq.field); + dev->width, dev->height, dev->field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); @@ -936,82 +636,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - return videobuf_reqbufs(get_queue(file), p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_querybuf(get_queue(file), p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_qbuf(get_queue(file), p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_dqbuf(get_queue(file), p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(i)))) - return -EBUSY; - - /* Don't start VBI streaming unless vida streaming - * has already started. - */ - if ((i == V4L2_BUF_TYPE_VBI_CAPTURE) && - ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) - return -EINVAL; - - return videobuf_streamon(get_queue(file)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - int err, res; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - res = get_resource(i); - err = videobuf_streamoff(get_queue(file)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_dev *dev = video_drvdata(file); @@ -1288,7 +912,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, { struct v4l2_ctrl *mute; int old_mute_val = 1; - struct videobuf_dvb_frontend *vfe; + struct vb2_dvb_frontend *vfe; struct dvb_frontend *fe; struct analog_parameters params = { @@ -1312,7 +936,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, params.frequency, f->tuner, params.std); - vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { return -EINVAL; } @@ -1368,28 +992,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, /* ----------------------------------------------------------- */ -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx23885_video_irq(struct cx23885_dev *dev, u32 status) { u32 mask, count; @@ -1434,13 +1036,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) spin_unlock(&dev->slock); handled++; } - if (status & VID_BC_MSK_RISCI2) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } /* Allow the VBI framework to process it's payload */ handled += cx23885_vbi_irq(dev, status); @@ -1453,12 +1048,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1470,18 +1065,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .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, .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_log_status = vidioc_log_status, - .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, @@ -1517,7 +1113,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; - btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) @@ -1525,8 +1120,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->video_dev); dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } if (dev->audio_dev) @@ -1535,6 +1128,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) int cx23885_video_register(struct cx23885_dev *dev) { + struct vb2_queue *q; int err; dprintk(1, "%s()\n", __func__); @@ -1551,21 +1145,9 @@ int cx23885_video_register(struct cx23885_dev *dev) /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); /* init vbi dma queues */ INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vbiq.timeout.function = cx23885_vbi_timeout; - dev->vbiq.timeout.data = (unsigned long)dev; - init_timer(&dev->vbiq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, - VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1626,9 +1208,42 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); + q = &dev->vb2_vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_video_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + + q = &dev->vb2_vbiq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_vbi_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); + dev->video_dev->queue = &dev->vb2_vidq; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1642,6 +1257,7 @@ int cx23885_video_register(struct cx23885_dev *dev) /* register VBI device */ dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); + dev->vbi_dev->queue = &dev->vb2_vbiq; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 5f5d8e8aa472..388e420d88e9 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -25,8 +25,8 @@ #include #include #include -#include -#include +#include +#include #include #include "btcx-risc.h" @@ -35,7 +35,7 @@ #include -#define CX23885_VERSION "0.0.3" +#define CX23885_VERSION "0.0.4" #define UNSET (-1U) @@ -44,9 +44,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -136,20 +133,6 @@ struct cx23885_tvnorm { u32 cxoformat; }; -struct cx23885_fh { - struct v4l2_fh fh; - u32 resources; - struct cx23885_dev *q_dev; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; - enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, CX23885_VMUX_COMPOSITE2, @@ -172,7 +155,8 @@ enum cx23885_src_sel_type { /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head queue; /* cx23885 specific */ unsigned int bpl; @@ -248,9 +232,6 @@ struct cx23885_i2c { struct cx23885_dmaqueue { struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; u32 count; }; @@ -260,7 +241,7 @@ struct cx23885_tsport { int nr; int sram_chno; - struct videobuf_dvb_frontends frontends; + struct vb2_dvb_frontends frontends; /* dma queues */ struct cx23885_dmaqueue mpegq; @@ -389,7 +370,6 @@ struct cx23885_dev { } bridge; /* Analog video */ - u32 resources; unsigned int input; unsigned int audinput; /* Selectable audio input */ u32 tvaudio; @@ -420,16 +400,20 @@ struct cx23885_dev { /* video capture */ struct cx23885_fmt *fmt; unsigned int width, height; + unsigned field; struct cx23885_dmaqueue vidq; + struct vb2_queue vb2_vidq; struct cx23885_dmaqueue vbiq; + struct vb2_queue vb2_vbiq; + spinlock_t slock; /* MPEG Encoder ONLY settings */ u32 cx23417_mailbox; struct cx2341x_handler cxhdl; struct video_device *v4l_device; - atomic_t v4l_reader_count; + struct vb2_queue vb2_mpegq; struct cx23885_tvnorm encodernorm; /* Analog raw audio */ @@ -505,9 +489,6 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch); -extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, @@ -518,13 +499,11 @@ extern int cx23885_risc_vbibuffer(struct pci_dev *pci, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); +int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf); void cx23885_cancel_buffers(struct cx23885_tsport *port); -extern int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q); - -extern void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count); extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); @@ -558,13 +537,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, - struct cx23885_tsport *port, - struct cx23885_buffer *buf, - enum v4l2_field field); +extern int cx23885_buf_prepare(struct cx23885_buffer *buf, + struct cx23885_tsport *port); extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, +extern void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ @@ -586,9 +563,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); -extern struct videobuf_queue_ops cx23885_vbi_qops; -extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q); +extern struct vb2_ops cx23885_vbi_qops; extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ -- cgit v1.2.3 From 96f233e97587a7f6c0f47476118cdb9a23a9ebe0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 18:04:41 -0300 Subject: [media] cx23885: fix field handling Add missing SEQ_BT/TB support, bottom field is first for all 60 Hz formats, not just NTSC, restore an overwritten field value and initialize dev->field correctly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index c6921d4bb7dd..defdf7486eda 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -352,7 +352,7 @@ static int buffer_prepare(struct vb2_buffer *vb) buf->bpl, 0, dev->height); break; case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) + if (dev->tvnorm & V4L2_STD_525_60) /* NTSC or */ field_tff = 1; else @@ -559,6 +559,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: break; default: field = V4L2_FIELD_INTERLACED; @@ -598,6 +600,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + f->fmt.pix.field = dev->field; return 0; } @@ -1140,6 +1144,7 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->tvnorm = V4L2_STD_NTSC_M; dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); + dev->field = V4L2_FIELD_INTERLACED; dev->width = norm_maxw(dev->tvnorm); dev->height = norm_maxh(dev->tvnorm); -- cgit v1.2.3 From 4d63a25c4523b5d18e5307897d56aff785f43bf5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Aug 2014 06:26:01 -0300 Subject: [media] cx23885: remove btcx-risc dependency It's just as easy to do it in the driver. This dependency only uses a fraction of the btcx-risc module and doing it directly in the driver adds only a few lines. The btcx-risc module is really meant for the bttv driver, not for other drivers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 1 - drivers/media/pci/cx23885/Makefile | 1 - drivers/media/pci/cx23885/cx23885-alsa.c | 5 ++++- drivers/media/pci/cx23885/cx23885-core.c | 36 +++++++++++++++++--------------- drivers/media/pci/cx23885/cx23885.h | 18 ++++++++++------ 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 38c3b7bc7c2a..a883ea4968be 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -3,7 +3,6 @@ config VIDEO_CX23885 depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND select SND_PCM select I2C_ALGOBIT - select VIDEO_BTCX select VIDEO_TUNER select VIDEO_TVEEPROM depends on RC_CORE diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile index 2a2cafb8cf5b..a2cbdcf15a8c 100644 --- a/drivers/media/pci/cx23885/Makefile +++ b/drivers/media/pci/cx23885/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.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/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 1b162ee8c8c6..ae7c2e89ad1c 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -270,12 +270,15 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) static int dsp_buffer_free(struct cx23885_audio_dev *chip) { + struct cx23885_riscmem *risc; + BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); cx23885_alsa_dma_unmap(chip); cx23885_alsa_dma_free(chip->buf); - btcx_riscmem_free(chip->pci, &chip->buf->risc); + risc = &chip->buf->risc; + pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); chip->buf = NULL; diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8d77a5649777..cb94366b9504 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -570,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, } static void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) + struct cx23885_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -1121,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, return rp; } -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1144,9 +1143,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 5; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1164,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi) { u32 instructions; __le32 *rp; - int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + syncs + jump (all 2 dwords). Here @@ -1181,9 +1180,10 @@ int cx23885_risc_databuffer(struct pci_dev *pci, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 4; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1196,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } -int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1219,9 +1218,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 5; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1246,8 +1246,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { + struct cx23885_riscmem *risc = &buf->risc; + BUG_ON(in_interrupt()); - btcx_riscmem_free(dev->pci, &buf->risc); + pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 388e420d88e9..0e4f4061087f 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -29,7 +29,6 @@ #include #include -#include "btcx-risc.h" #include "cx23885-reg.h" #include "media/cx2341x.h" @@ -152,6 +151,13 @@ enum cx23885_src_sel_type { CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO }; +struct cx23885_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ @@ -160,7 +166,7 @@ struct cx23885_buffer { /* cx23885 specific */ unsigned int bpl; - struct btcx_riscmem risc; + struct cx23885_riscmem risc; struct cx23885_fmt *fmt; u32 count; }; @@ -300,7 +306,7 @@ struct cx23885_kernel_ir { struct cx23885_audio_buffer { unsigned int bpl; - struct btcx_riscmem risc; + struct cx23885_riscmem risc; void *vaddr; struct scatterlist *sglist; int sglen; @@ -489,13 +495,13 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch); -extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); extern int cx23885_risc_vbibuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, struct scatterlist *sglist, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); @@ -595,7 +601,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register( extern void cx23885_audio_unregister(struct cx23885_dev *dev); extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); extern int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, -- cgit v1.2.3 From f1b6a735328b507810d2436891ee977fb8cd62d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Aug 2014 06:43:36 -0300 Subject: [media] cx23885: Add busy checks before changing formats Before you can change the standard or the capture format, make sure the various vb2_queues aren't in use since you cannot change the buffer size from underneath a a busy vb2_queue. Also make sure that the return code of cx23885_set_tvnorm is returned correctly, otherwise the -EBUSY will be lost. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 10 +++++----- drivers/media/pci/cx23885/cx23885-video.c | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index f1ef9017e2a7..6973055f0814 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1248,18 +1248,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx23885_dev *dev = video_drvdata(file); unsigned int i; + int ret; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) if (id & cx23885_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; - dev->encodernorm = cx23885_tvnorms[i]; - - /* Have the drier core notify the subdevices */ - cx23885_set_tvnorm(dev, id); - return 0; + ret = cx23885_set_tvnorm(dev, id); + if (!ret) + dev->encodernorm = cx23885_tvnorms[i]; + return ret; } static int vidioc_enum_input(struct file *file, void *priv, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index defdf7486eda..f0ea904d4669 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -119,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) (unsigned int)norm, v4l2_norm_to_name(norm)); + if (dev->tvnorm != norm) { + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + } + dev->tvnorm = norm; call_all(dev, video, s_std, norm); @@ -591,6 +597,11 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; + + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; @@ -654,9 +665,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); - cx23885_set_tvnorm(dev, tvnorms); - - return 0; + return cx23885_set_tvnorm(dev, tvnorms); } int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) -- cgit v1.2.3 From 947b38bb110c90e0bc93e7afe9ab6f007b6799a7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Sep 2014 13:26:52 -0300 Subject: [media] tw68: simplify tw68_buffer_count The code to calculate the maximum number of buffers allowed in 4 MB is 1) wrong if PAGE_SIZE != 4096 and 2) unnecessarily complex. Fix and simplify the code. Reported-by: Mauro Carvalho Chehab Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 66fae2345fdd..498ead9a956d 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -361,22 +361,13 @@ int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) /* ------------------------------------------------------------------ */ -/* nr of (tw68-)pages for the given buffer size */ -static int tw68_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - /* calc max # of buffers from size (must not exceed the 4MB virtual * address space per DMA channel) */ static int tw68_buffer_count(unsigned int size, unsigned int count) { unsigned int maxcount; - maxcount = 1024 / tw68_buffer_pages(size); + maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE); if (count > maxcount) count = maxcount; return count; -- cgit v1.2.3 From 91f96e8b7255537da3a58805cf465003521d7c5f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Sep 2014 13:26:53 -0300 Subject: [media] tw68: drop bogus cpu_to_le32() call tw_writel maps to writel which maps to __raw_writel(__cpu_to_le32(b),addr). So tw_writel already calls cpu_to_le32 and it shouldn't be called again in the code. Reported-by: Mauro Carvalho Chehab Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 498ead9a956d..5c94ac7c88d9 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -348,7 +348,7 @@ int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) * a new address can be set. */ tw_clearl(TW68_DMAC, TW68_DMAP_EN); - tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->dma)); + tw_writel(TW68_DMAP_SA, buf->dma); /* Clear any pending interrupts */ tw_writel(TW68_INTSTAT, dev->board_virqmask); /* Enable the risc engine and the fifo */ -- cgit v1.2.3 From 4228cd5682f07b6cf5dfd3eb5e003766f5640ee2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Sep 2014 14:55:15 -0300 Subject: [media] disable COMPILE_TEST for omap1_camera This driver depends on a legacy OMAP DMA API. So, it won't compile-test on other archs. While we might add stubs to the functions, this is not a good idea, as the hole API should be replaced. So, for now, let's just remove COMPILE_TEST and wait for some time for people to fix. If not fixed, then we'll end by removing this driver as a hole. Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 6af6c6dccda8..f2776cd415ca 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -63,7 +63,7 @@ config VIDEO_SH_MOBILE_CEU config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" depends on VIDEO_DEV && SOC_CAMERA - depends on ARCH_OMAP1 || COMPILE_TEST + depends on ARCH_OMAP1 depends on HAS_DMA select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG -- cgit v1.2.3 From 8087c35fc48c9545ee1f07bd812217b286cf13bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Sep 2014 11:21:30 -0300 Subject: [media] s5p-jpeg: Fix compilation with COMPILE_TEST ERROR: "__bad_ndelay" [drivers/media/platform/s5p-jpeg/s5p-jpeg.ko] undefined! That happens because asm-generic doesn't like any ndelay time bigger than 20us. Currently, usleep_range() couldn't simply be used, since exynos4_jpeg_sw_reset() is called with a spinlock held. So, let's use udelay() instead. Reported-by: Stephen Rothwell Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index e51c078360f5..ab6d6f43c96f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -23,7 +23,7 @@ void exynos4_jpeg_sw_reset(void __iomem *base) reg = readl(base + EXYNOS4_JPEG_CNTL_REG); writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG); - ndelay(100000); + udelay(100); writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG); } -- cgit v1.2.3 From f5281fc81e9a0a3e80b78720c5ae2ed06da3bfae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Sep 2014 11:31:40 -0300 Subject: [media] vpif: Fix compilation with allmodconfig When vpif is compiled as module, those errors happen: ERROR: "vpif_lock" [drivers/media/platform/davinci/vpif_display.ko] undefined! ERROR: "vpif_lock" [drivers/media/platform/davinci/vpif_capture.ko] undefined! That's because vpif_lock symbol is not exported. Reported-by: Stephen Rothwell Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index cd08e5248387..3dad5bd7fe0a 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -38,6 +38,7 @@ MODULE_LICENSE("GPL"); #define VPIF_CH3_MAX_MODES 2 spinlock_t vpif_lock; +EXPORT_SYMBOL_GPL(vpif_lock); void __iomem *vpif_base; EXPORT_SYMBOL_GPL(vpif_base); -- cgit v1.2.3 From 6b831d78477c9bbfbcb4cb60af13e13bd2c7467e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 21:59:36 -0300 Subject: [media] airspy: fix error handling on start streaming Free all reserved USB buffers and URBs on failure. Return all queued buffers to vb2 with state queued on error case. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index cb0e515d80ae..56a1ae05ea7b 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -540,27 +540,49 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count) mutex_lock(&s->v4l2_lock); - set_bit(POWER_ON, &s->flags); - s->sequence = 0; + set_bit(POWER_ON, &s->flags); + ret = airspy_alloc_stream_bufs(s); if (ret) - goto err; + goto err_clear_bit; ret = airspy_alloc_urbs(s); if (ret) - goto err; + goto err_free_stream_bufs; ret = airspy_submit_urbs(s); if (ret) - goto err; + goto err_free_urbs; /* start hardware streaming */ ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0); if (ret) - goto err; -err: + goto err_kill_urbs; + + goto exit_mutex_unlock; + +err_kill_urbs: + airspy_kill_urbs(s); +err_free_urbs: + airspy_free_urbs(s); +err_free_stream_bufs: + airspy_free_stream_bufs(s); +err_clear_bit: + clear_bit(POWER_ON, &s->flags); + + /* return all queued buffers to vb2 */ + { + struct airspy_frame_buf *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &s->queued_bufs, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + +exit_mutex_unlock: mutex_unlock(&s->v4l2_lock); return ret; -- cgit v1.2.3 From 7057005db6482516099e7b48b3bebaf9a3f213cb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 18:31:52 -0300 Subject: [media] airspy: coding style issues Fix issues reported by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 56a1ae05ea7b..dee1fe2669a6 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -255,6 +255,7 @@ static unsigned int airspy_convert_stream(struct airspy *s, if (unlikely(time_is_before_jiffies(s->jiffies_next))) { #define MSECS 10000UL unsigned int samples = s->sample - s->sample_measured; + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample_measured = s->sample; dev_dbg(&s->udev->dev, @@ -462,6 +463,7 @@ static void airspy_cleanup_queued_bufs(struct airspy *s) spin_lock_irqsave(&s->queued_bufs_lock, flags); while (!list_empty(&s->queued_bufs)) { struct airspy_frame_buf *buf; + buf = list_entry(s->queued_bufs.next, struct airspy_frame_buf, list); list_del(&buf->list); @@ -772,6 +774,7 @@ static int airspy_g_frequency(struct file *file, void *priv, { struct airspy *s = video_drvdata(file); int ret = 0; + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", __func__, f->tuner, f->type); @@ -829,6 +832,7 @@ static int airspy_enum_freq_bands(struct file *file, void *priv, { struct airspy *s = video_drvdata(file); int ret; + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", __func__, band->tuner, band->type, band->index); -- cgit v1.2.3 From 617123ae383e66b3a2c5f57155b49af5bb4327db Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 19:14:32 -0300 Subject: [media] airspy: logging changes Kernel logging system needs pointer to usb interface device in order to print names and bus numbers properly. There was wrong device pointer given and log printings wasn't correct. Remove some debug logging from v4l2 ioctl functions. v4l2 core debug prints almost same information when enabled. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 172 ++++++++++++++------------------------ 1 file changed, 61 insertions(+), 111 deletions(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index dee1fe2669a6..de9fc52d3763 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -107,6 +107,7 @@ struct airspy { #define USB_STATE_URB_BUF (1 << 3) unsigned long flags; + struct device *dev; struct usb_device *udev; struct video_device vdev; struct v4l2_device v4l2_dev; @@ -154,16 +155,15 @@ struct airspy { unsigned int sample_measured; }; -#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \ +#define airspy_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \ char *_direction; \ if (_t & USB_DIR_IN) \ _direction = "<<<"; \ else \ _direction = ">>>"; \ - dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ - "%s %*ph\n", __func__, _t, _r, _v & 0xff, _v >> 8, \ - _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \ - _l, _b); \ + dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \ + _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \ + _l & 0xff, _l >> 8, _direction, _l, _b); \ } /* execute firmware command */ @@ -192,7 +192,7 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index, requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); break; default: - dev_err(&s->udev->dev, "Unknown command %02x\n", request); + dev_err(s->dev, "Unknown command %02x\n", request); ret = -EINVAL; goto err; } @@ -203,11 +203,10 @@ static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index, ret = usb_control_msg(s->udev, pipe, request, requesttype, value, index, s->buf, size, 1000); - airspy_dbg_usb_control_msg(s->udev, request, requesttype, value, + airspy_dbg_usb_control_msg(s->dev, request, requesttype, value, index, s->buf, size); if (ret < 0) { - dev_err(&s->udev->dev, - "usb_control_msg() failed %d request %02x\n", + dev_err(s->dev, "usb_control_msg() failed %d request %02x\n", ret, request); goto err; } @@ -258,8 +257,7 @@ static unsigned int airspy_convert_stream(struct airspy *s, s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample_measured = s->sample; - dev_dbg(&s->udev->dev, - "slen=%d samples=%u msecs=%lu sample rate=%lu\n", + dev_dbg(s->dev, "slen=%d samples=%u msecs=%lu sample rate=%lu\n", src_len, samples, MSECS, samples * 1000UL / MSECS); } @@ -279,9 +277,8 @@ static void airspy_urb_complete(struct urb *urb) struct airspy *s = urb->context; struct airspy_frame_buf *fbuf; - dev_dbg_ratelimited(&s->udev->dev, - "%s: status=%d length=%d/%d errors=%d\n", - __func__, urb->status, urb->actual_length, + dev_dbg_ratelimited(s->dev, "status=%d length=%d/%d errors=%d\n", + urb->status, urb->actual_length, urb->transfer_buffer_length, urb->error_count); switch (urb->status) { @@ -293,8 +290,7 @@ static void airspy_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dev_err_ratelimited(&s->udev->dev, "URB failed %d\n", - urb->status); + dev_err_ratelimited(s->dev, "URB failed %d\n", urb->status); break; } @@ -305,7 +301,7 @@ static void airspy_urb_complete(struct urb *urb) fbuf = airspy_get_next_fill_buf(s); if (unlikely(fbuf == NULL)) { s->vb_full++; - dev_notice_ratelimited(&s->udev->dev, + dev_notice_ratelimited(s->dev, "videobuf is full, %d packets dropped\n", s->vb_full); goto skip; @@ -329,7 +325,7 @@ static int airspy_kill_urbs(struct airspy *s) int i; for (i = s->urbs_submitted - 1; i >= 0; i--) { - dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i); + dev_dbg(s->dev, "kill urb=%d\n", i); /* stop the URB */ usb_kill_urb(s->urb_list[i]); } @@ -343,11 +339,10 @@ static int airspy_submit_urbs(struct airspy *s) int i, ret; for (i = 0; i < s->urbs_initialized; i++) { - dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i); + dev_dbg(s->dev, "submit urb=%d\n", i); ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); if (ret) { - dev_err(&s->udev->dev, - "Could not submit URB no. %d - get them all back\n", + dev_err(s->dev, "Could not submit URB no. %d - get them all back\n", i); airspy_kill_urbs(s); return ret; @@ -363,8 +358,7 @@ static int airspy_free_stream_bufs(struct airspy *s) if (s->flags & USB_STATE_URB_BUF) { while (s->buf_num) { s->buf_num--; - dev_dbg(&s->udev->dev, "%s: free buf=%d\n", - __func__, s->buf_num); + dev_dbg(s->dev, "free buf=%d\n", s->buf_num); usb_free_coherent(s->udev, s->buf_size, s->buf_list[s->buf_num], s->dma_addr[s->buf_num]); @@ -380,23 +374,20 @@ static int airspy_alloc_stream_bufs(struct airspy *s) s->buf_num = 0; s->buf_size = BULK_BUFFER_SIZE; - dev_dbg(&s->udev->dev, - "%s: all in all I will use %u bytes for streaming\n", - __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE); + dev_dbg(s->dev, "all in all I will use %u bytes for streaming\n", + MAX_BULK_BUFS * BULK_BUFFER_SIZE); for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, BULK_BUFFER_SIZE, GFP_ATOMIC, &s->dma_addr[s->buf_num]); if (!s->buf_list[s->buf_num]) { - dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n", - __func__, s->buf_num); + dev_dbg(s->dev, "alloc buf=%d failed\n", s->buf_num); airspy_free_stream_bufs(s); return -ENOMEM; } - dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", - __func__, s->buf_num, + dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num, s->buf_list[s->buf_num], (long long)s->dma_addr[s->buf_num]); s->flags |= USB_STATE_URB_BUF; @@ -413,8 +404,7 @@ static int airspy_free_urbs(struct airspy *s) for (i = s->urbs_initialized - 1; i >= 0; i--) { if (s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: free urb=%d\n", - __func__, i); + dev_dbg(s->dev, "free urb=%d\n", i); /* free the URBs */ usb_free_urb(s->urb_list[i]); } @@ -430,10 +420,10 @@ static int airspy_alloc_urbs(struct airspy *s) /* allocate the URBs */ for (i = 0; i < MAX_BULK_BUFS; i++) { - dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i); + dev_dbg(s->dev, "alloc urb=%d\n", i); s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: failed\n", __func__); + dev_dbg(s->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(s->urb_list[j]); return -ENOMEM; @@ -458,7 +448,7 @@ static void airspy_cleanup_queued_bufs(struct airspy *s) { unsigned long flags = 0; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); spin_lock_irqsave(&s->queued_bufs_lock, flags); while (!list_empty(&s->queued_bufs)) { @@ -478,7 +468,7 @@ static void airspy_disconnect(struct usb_interface *intf) struct v4l2_device *v = usb_get_intfdata(intf); struct airspy *s = container_of(v, struct airspy, v4l2_dev); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); mutex_lock(&s->vb_queue_lock); mutex_lock(&s->v4l2_lock); @@ -499,7 +489,7 @@ static int airspy_queue_setup(struct vb2_queue *vq, { struct airspy *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ if (vq->num_buffers + *nbuffers < 8) @@ -507,8 +497,7 @@ static int airspy_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", - __func__, *nbuffers, sizes[0]); + dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); return 0; } @@ -535,7 +524,7 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count) struct airspy *s = vb2_get_drv_priv(vq); int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); if (!s->udev) return -ENODEV; @@ -594,7 +583,7 @@ static void airspy_stop_streaming(struct vb2_queue *vq) { struct airspy *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); mutex_lock(&s->v4l2_lock); @@ -626,8 +615,6 @@ static int airspy_querycap(struct file *file, void *fh, { struct airspy *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); - strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); @@ -641,10 +628,6 @@ static int airspy_querycap(struct file *file, void *fh, static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct airspy *s = video_drvdata(file); - - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index); - if (f->index >= NUM_FORMATS) return -EINVAL; @@ -659,9 +642,6 @@ static int airspy_g_fmt_sdr_cap(struct file *file, void *priv, { struct airspy *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, - (char *)&s->pixelformat); - f->fmt.sdr.pixelformat = s->pixelformat; f->fmt.sdr.buffersize = s->buffersize; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); @@ -676,9 +656,6 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv, struct vb2_queue *q = &s->vb_queue; int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, - (char *)&f->fmt.sdr.pixelformat); - if (vb2_is_busy(q)) return -EBUSY; @@ -703,12 +680,8 @@ static int airspy_s_fmt_sdr_cap(struct file *file, void *priv, static int airspy_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct airspy *s = video_drvdata(file); int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, - (char *)&f->fmt.sdr.pixelformat); - memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); for (i = 0; i < NUM_FORMATS; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { @@ -726,11 +699,8 @@ static int airspy_try_fmt_sdr_cap(struct file *file, void *priv, static int airspy_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *v) { - struct airspy *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); - if (v->index == 0) ret = 0; else if (v->index == 1) @@ -743,11 +713,8 @@ static int airspy_s_tuner(struct file *file, void *priv, static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct airspy *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); - if (v->index == 0) { strlcpy(v->name, "AirSpy ADC", sizeof(v->name)); v->type = V4L2_TUNER_ADC; @@ -773,18 +740,18 @@ static int airspy_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct airspy *s = video_drvdata(file); - int ret = 0; - - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", - __func__, f->tuner, f->type); + int ret; if (f->tuner == 0) { f->type = V4L2_TUNER_ADC; f->frequency = s->f_adc; + dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc); ret = 0; } else if (f->tuner == 1) { f->type = V4L2_TUNER_RF; f->frequency = s->f_rf; + dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf); + ret = 0; } else { ret = -EINVAL; } @@ -799,22 +766,17 @@ static int airspy_s_frequency(struct file *file, void *priv, int ret; u8 buf[4]; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); - if (f->tuner == 0) { s->f_adc = clamp_t(unsigned int, f->frequency, bands[0].rangelow, bands[0].rangehigh); - dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", - __func__, s->f_adc); + dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc); ret = 0; } else if (f->tuner == 1) { s->f_rf = clamp_t(unsigned int, f->frequency, bands_rf[0].rangelow, bands_rf[0].rangehigh); - dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", - __func__, s->f_rf); + dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf); buf[0] = (s->f_rf >> 0) & 0xff; buf[1] = (s->f_rf >> 8) & 0xff; buf[2] = (s->f_rf >> 16) & 0xff; @@ -830,12 +792,8 @@ static int airspy_s_frequency(struct file *file, void *priv, static int airspy_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { - struct airspy *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); - if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands)) { ret = -EINVAL; @@ -918,10 +876,9 @@ static int airspy_set_lna_gain(struct airspy *s) int ret; u8 u8tmp; - dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n", - __func__, s->lna_gain_auto->cur.val, - s->lna_gain_auto->val, s->lna_gain->cur.val, - s->lna_gain->val); + dev_dbg(s->dev, "lna auto=%d->%d val=%d->%d\n", + s->lna_gain_auto->cur.val, s->lna_gain_auto->val, + s->lna_gain->cur.val, s->lna_gain->val); ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val, &u8tmp, 1); @@ -936,7 +893,7 @@ static int airspy_set_lna_gain(struct airspy *s) } err: if (ret) - dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(s->dev, "failed=%d\n", ret); return ret; } @@ -946,10 +903,9 @@ static int airspy_set_mixer_gain(struct airspy *s) int ret; u8 u8tmp; - dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n", - __func__, s->mixer_gain_auto->cur.val, - s->mixer_gain_auto->val, s->mixer_gain->cur.val, - s->mixer_gain->val); + dev_dbg(s->dev, "mixer auto=%d->%d val=%d->%d\n", + s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val, + s->mixer_gain->cur.val, s->mixer_gain->val); ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val, &u8tmp, 1); @@ -964,7 +920,7 @@ static int airspy_set_mixer_gain(struct airspy *s) } err: if (ret) - dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(s->dev, "failed=%d\n", ret); return ret; } @@ -974,8 +930,7 @@ static int airspy_set_if_gain(struct airspy *s) int ret; u8 u8tmp; - dev_dbg(&s->udev->dev, "%s: val=%d->%d\n", - __func__, s->if_gain->cur.val, s->if_gain->val); + dev_dbg(s->dev, "val=%d->%d\n", s->if_gain->cur.val, s->if_gain->val); ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val, &u8tmp, 1); @@ -983,7 +938,7 @@ static int airspy_set_if_gain(struct airspy *s) goto err; err: if (ret) - dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(s->dev, "failed=%d\n", ret); return ret; } @@ -1006,8 +961,8 @@ static int airspy_s_ctrl(struct v4l2_ctrl *ctrl) ret = airspy_set_if_gain(s); break; default: - dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n", - __func__, ctrl->id, ctrl->name); + dev_dbg(s->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -1021,15 +976,13 @@ static const struct v4l2_ctrl_ops airspy_ctrl_ops = { static int airspy_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(intf); - struct airspy *s = NULL; + struct airspy *s; int ret; u8 u8tmp, buf[BUF_SIZE]; s = kzalloc(sizeof(struct airspy), GFP_KERNEL); if (s == NULL) { - dev_err(&udev->dev, - "Could not allocate memory for airspy state\n"); + dev_err(&intf->dev, "Could not allocate memory for state\n"); return -ENOMEM; } @@ -1037,7 +990,8 @@ static int airspy_probe(struct usb_interface *intf, mutex_init(&s->vb_queue_lock); spin_lock_init(&s->queued_bufs_lock); INIT_LIST_HEAD(&s->queued_bufs); - s->udev = udev; + s->dev = &intf->dev; + s->udev = interface_to_usbdev(intf); s->f_adc = bands[0].rangelow; s->f_rf = bands_rf[0].rangelow; s->pixelformat = formats[0].pixelformat; @@ -1049,14 +1003,14 @@ static int airspy_probe(struct usb_interface *intf, ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0, buf, BUF_SIZE); if (ret) { - dev_err(&s->udev->dev, "Could not detect board\n"); + dev_err(s->dev, "Could not detect board\n"); goto err_free_mem; } buf[BUF_SIZE - 1] = '\0'; - dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp); - dev_info(&s->udev->dev, "Firmware version: %s\n", buf); + dev_info(s->dev, "Board ID: %02x\n", u8tmp); + dev_info(s->dev, "Firmware version: %s\n", buf); /* Init videobuf2 queue structure */ s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; @@ -1068,7 +1022,7 @@ static int airspy_probe(struct usb_interface *intf, s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&s->vb_queue); if (ret) { - dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); + dev_err(s->dev, "Could not initialize vb2 queue\n"); goto err_free_mem; } @@ -1082,8 +1036,7 @@ static int airspy_probe(struct usb_interface *intf, s->v4l2_dev.release = airspy_video_release; ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); if (ret) { - dev_err(&s->udev->dev, - "Failed to register v4l2-device (%d)\n", ret); + dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret); goto err_free_mem; } @@ -1103,7 +1056,7 @@ static int airspy_probe(struct usb_interface *intf, V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0); if (s->hdl.error) { ret = s->hdl.error; - dev_err(&s->udev->dev, "Could not initialize controls\n"); + dev_err(s->dev, "Could not initialize controls\n"); goto err_free_controls; } @@ -1115,16 +1068,13 @@ static int airspy_probe(struct usb_interface *intf, ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); if (ret) { - dev_err(&s->udev->dev, - "Failed to register as video device (%d)\n", + dev_err(s->dev, "Failed to register as video device (%d)\n", ret); goto err_unregister_v4l2_dev; } - dev_info(&s->udev->dev, "Registered as %s\n", + dev_info(s->dev, "Registered as %s\n", video_device_node_name(&s->vdev)); - dev_notice(&s->udev->dev, - "%s: SDR API is still slightly experimental and functionality changes may follow\n", - KBUILD_MODNAME); + dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n"); return 0; err_free_controls: -- cgit v1.2.3 From 8880f2cbdb0a981ea8e6a5ce2915abac26120523 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 19:27:43 -0300 Subject: [media] airspy: remove unneeded spinlock irq flags initialization There is no need to init flags before calling spin_lock_irqsave(). spin_lock_irqsave is a macro which stores value to 'flags'. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index de9fc52d3763..994c9914ab9b 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -223,7 +223,7 @@ err: /* Private functions */ static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s) { - unsigned long flags = 0; + unsigned long flags; struct airspy_frame_buf *buf = NULL; spin_lock_irqsave(&s->queued_bufs_lock, flags); @@ -446,7 +446,7 @@ static int airspy_alloc_urbs(struct airspy *s) /* Must be called with vb_queue_lock hold */ static void airspy_cleanup_queued_bufs(struct airspy *s) { - unsigned long flags = 0; + unsigned long flags; dev_dbg(s->dev, "\n"); @@ -506,7 +506,7 @@ static void airspy_buf_queue(struct vb2_buffer *vb) struct airspy *s = vb2_get_drv_priv(vb->vb2_queue); struct airspy_frame_buf *buf = container_of(vb, struct airspy_frame_buf, vb); - unsigned long flags = 0; + unsigned long flags; /* Check the device has not disconnected between prep and queuing */ if (unlikely(!s->udev)) { -- cgit v1.2.3 From b8843c7979fc8ea54efeaef8e9d524c33c42f099 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 20:11:27 -0300 Subject: [media] airspy: enhance sample rate debug calculation precision Sample rate calculation gives a little bit too large results because in real life there was around one milliseconds (~one usb packet) too much data for given time. Calculate time more accurate in order to provide better results. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 994c9914ab9b..4069234abed5 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -250,16 +250,18 @@ static unsigned int airspy_convert_stream(struct airspy *s, dst_len = 0; } - /* calculate samping rate and output it in 10 seconds intervals */ + /* calculate sample rate and output it in 10 seconds intervals */ if (unlikely(time_is_before_jiffies(s->jiffies_next))) { #define MSECS 10000UL + unsigned int msecs = jiffies_to_msecs(jiffies - + s->jiffies_next + msecs_to_jiffies(MSECS)); unsigned int samples = s->sample - s->sample_measured; s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample_measured = s->sample; - dev_dbg(s->dev, "slen=%d samples=%u msecs=%lu sample rate=%lu\n", - src_len, samples, MSECS, - samples * 1000UL / MSECS); + dev_dbg(s->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); } /* total number of samples */ -- cgit v1.2.3 From 100b7931f4c300fd6c278d890a92b9668feaf44d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 22:54:06 -0300 Subject: [media] msi2500: logging changes Kernel logging system needs pointer to usb interface device in order to print names and bus numbers properly. There was wrong device pointer given and log printings wasn't correct. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 157 +++++++++++++++--------------------- 1 file changed, 66 insertions(+), 91 deletions(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index e980aaa47b7c..647846b5904a 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -120,6 +120,7 @@ struct msi2500_frame_buf { }; struct msi2500_state { + struct device *dev; struct video_device vdev; struct v4l2_device v4l2_dev; struct v4l2_subdev *v4l2_subdev; @@ -153,7 +154,6 @@ struct msi2500_state { u32 next_sample; /* for track lost packets */ u32 sample; /* for sample rate calc */ unsigned long jiffies_next; - unsigned int sample_ctrl_bit[4]; }; /* Private functions */ @@ -269,7 +269,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, sample[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0; if (i == 0 && s->next_sample != sample[0]) { - dev_dbg_ratelimited(&s->udev->dev, + dev_dbg_ratelimited(s->dev, "%d samples lost, %d %08x:%08x\n", sample[0] - s->next_sample, src_len, s->next_sample, sample[0]); @@ -279,7 +279,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, * Dump all unknown 'garbage' data - maybe we will discover * someday if there is something rational... */ - dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]); + dev_dbg_ratelimited(s->dev, "%*ph\n", 12, &src[4]); src += 16; /* skip header */ @@ -322,8 +322,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, } case MSI2500_PIX_FMT_SDR_MSI2500_384: /* 384 x IQ samples */ /* Dump unknown 'garbage' data */ - dev_dbg_ratelimited(&s->udev->dev, - "%*ph\n", 24, &src[1000]); + dev_dbg_ratelimited(s->dev, "%*ph\n", 24, &src[1000]); memcpy(dst, src, 984); src += 984 + 24; dst += 984; @@ -365,8 +364,7 @@ static int msi2500_convert_stream(struct msi2500_state *s, u8 *dst, u8 *src, s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample = s->next_sample; - dev_dbg(&s->udev->dev, - "size=%u samples=%u msecs=%u sample rate=%lu\n", + dev_dbg(s->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n", src_len, samples, msecs, samples * 1000UL / msecs); } @@ -387,19 +385,16 @@ static void msi2500_isoc_handler(struct urb *urb) if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) { - dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n", + dev_dbg(s->dev, "URB (%p) unlinked %ssynchronuously\n", urb, urb->status == -ENOENT ? "" : "a"); return; } if (unlikely(urb->status != 0)) { - dev_dbg(&s->udev->dev, - "msi2500_isoc_handler() called with status %d\n", - urb->status); + dev_dbg(s->dev, "called with status %d\n", urb->status); /* Give up after a number of contiguous errors */ if (++s->isoc_errors > MAX_ISOC_ERRORS) - dev_dbg(&s->udev->dev, - "Too many ISOC errors, bailing out\n"); + dev_dbg(s->dev, "Too many ISOC errors, bailing out\n"); goto handler_end; } else { /* Reset ISOC error counter. We did get here, after all. */ @@ -413,7 +408,7 @@ static void msi2500_isoc_handler(struct urb *urb) /* Check frame error */ fstatus = urb->iso_frame_desc[i].status; if (unlikely(fstatus)) { - dev_dbg_ratelimited(&s->udev->dev, + dev_dbg_ratelimited(s->dev, "frame=%d/%d has error %d skipping\n", i, urb->number_of_packets, fstatus); continue; @@ -430,7 +425,7 @@ static void msi2500_isoc_handler(struct urb *urb) fbuf = msi2500_get_next_fill_buf(s); if (unlikely(fbuf == NULL)) { s->vb_full++; - dev_dbg_ratelimited(&s->udev->dev, + dev_dbg_ratelimited(s->dev, "videobuf is full, %d packets dropped\n", s->vb_full); continue; @@ -446,22 +441,19 @@ static void msi2500_isoc_handler(struct urb *urb) handler_end: i = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(i != 0)) - dev_dbg(&s->udev->dev, - "Error (%d) re-submitting urb in msi2500_isoc_handler\n", - i); + dev_dbg(s->dev, "Error (%d) re-submitting urb\n", i); } static void msi2500_iso_stop(struct msi2500_state *s) { int i; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (s->urbs[i]) { - dev_dbg(&s->udev->dev, "Unlinking URB %p\n", - s->urbs[i]); + dev_dbg(s->dev, "Unlinking URB %p\n", s->urbs[i]); usb_kill_urb(s->urbs[i]); } } @@ -471,12 +463,12 @@ static void msi2500_iso_free(struct msi2500_state *s) { int i; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); /* Freeing ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (s->urbs[i]) { - dev_dbg(&s->udev->dev, "Freeing URB\n"); + dev_dbg(s->dev, "Freeing URB\n"); if (s->urbs[i]->transfer_buffer) { usb_free_coherent(s->udev, s->urbs[i]->transfer_buffer_length, @@ -492,7 +484,7 @@ static void msi2500_iso_free(struct msi2500_state *s) /* Both v4l2_lock and vb_queue_lock should be locked when calling this */ static void msi2500_isoc_cleanup(struct msi2500_state *s) { - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); msi2500_iso_stop(s); msi2500_iso_free(s); @@ -504,7 +496,7 @@ static int msi2500_isoc_init(struct msi2500_state *s) struct urb *urb; int i, j, ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); s->isoc_errors = 0; @@ -516,13 +508,12 @@ static int msi2500_isoc_init(struct msi2500_state *s) for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { - dev_err(&s->udev->dev, - "Failed to allocate urb %d\n", i); + dev_err(s->dev, "Failed to allocate urb %d\n", i); msi2500_isoc_cleanup(s); return -ENOMEM; } s->urbs[i] = urb; - dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb); + dev_dbg(s->dev, "Allocated URB at 0x%p\n", urb); urb->interval = 1; urb->dev = s->udev; @@ -532,8 +523,7 @@ static int msi2500_isoc_init(struct msi2500_state *s) ISO_BUFFER_SIZE, GFP_KERNEL, &urb->transfer_dma); if (urb->transfer_buffer == NULL) { - dev_err(&s->udev->dev, - "Failed to allocate urb buffer %d\n", + dev_err(s->dev, "Failed to allocate urb buffer %d\n", i); msi2500_isoc_cleanup(s); return -ENOMEM; @@ -553,13 +543,12 @@ static int msi2500_isoc_init(struct msi2500_state *s) for (i = 0; i < MAX_ISO_BUFS; i++) { ret = usb_submit_urb(s->urbs[i], GFP_KERNEL); if (ret) { - dev_err(&s->udev->dev, - "isoc_init() submit_urb %d failed with error %d\n", + dev_err(s->dev, "usb_submit_urb %d failed with error %d\n", i, ret); msi2500_isoc_cleanup(s); return ret; } - dev_dbg(&s->udev->dev, "URB 0x%p submitted.\n", s->urbs[i]); + dev_dbg(s->dev, "URB 0x%p submitted.\n", s->urbs[i]); } /* All is done... */ @@ -571,7 +560,7 @@ static void msi2500_cleanup_queued_bufs(struct msi2500_state *s) { unsigned long flags = 0; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); spin_lock_irqsave(&s->queued_bufs_lock, flags); while (!list_empty(&s->queued_bufs)) { @@ -592,7 +581,7 @@ static void msi2500_disconnect(struct usb_interface *intf) struct msi2500_state *s = container_of(v, struct msi2500_state, v4l2_dev); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); mutex_lock(&s->vb_queue_lock); mutex_lock(&s->v4l2_lock); @@ -612,7 +601,7 @@ static int msi2500_querycap(struct file *file, void *fh, { struct msi2500_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); @@ -630,14 +619,13 @@ static int msi2500_queue_setup(struct vb2_queue *vq, { struct msi2500_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers); /* Absolute min and max number of buffers available for mmap() */ *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", - __func__, *nbuffers, sizes[0]); + dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); return 0; } @@ -664,16 +652,15 @@ static void msi2500_buf_queue(struct vb2_buffer *vb) #define CMD_STOP_STREAMING 0x45 #define CMD_READ_UNKNOW 0x48 -#define msi2500_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \ +#define msi2500_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \ char *_direction; \ if (_t & USB_DIR_IN) \ _direction = "<<<"; \ else \ _direction = ">>>"; \ - dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ - "%s %*ph\n", __func__, _t, _r, _v & 0xff, _v >> 8, \ - _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \ - _l, _b); \ + dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \ + _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \ + _l & 0xff, _l >> 8, _direction, _l, _b); \ } static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data) @@ -684,18 +671,16 @@ static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data) u16 value = (data >> 0) & 0xffff; u16 index = (data >> 16) & 0xffff; - msi2500_dbg_usb_control_msg(s->udev, + msi2500_dbg_usb_control_msg(s->dev, request, requesttype, value, index, NULL, 0); - ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0), request, requesttype, value, index, NULL, 0, 2000); - if (ret) - dev_err(&s->udev->dev, "%s: failed %d, cmd %02x, data %04x\n", - __func__, ret, cmd, data); + dev_err(s->dev, "failed %d, cmd %02x, data %04x\n", + ret, cmd, data); return ret; -}; +} #define F_REF 24000000 #define DIV_R_IN 2 @@ -784,8 +769,7 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) for (div_r_out = 4; div_r_out < 16; div_r_out += 2) { f_vco = f_sr * div_r_out * 12; - dev_dbg(&s->udev->dev, "%s: div_r_out=%d f_vco=%d\n", - __func__, div_r_out, f_vco); + dev_dbg(s->dev, "div_r_out=%d f_vco=%d\n", div_r_out, f_vco); if (f_vco >= 202000000) break; } @@ -799,10 +783,8 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */ reg4 |= ((fract >> 0) & 0x0fffff) << 8; /* [19:0] */ - dev_dbg(&s->udev->dev, - "%s: f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n", - __func__, f_sr, f_vco, div_n, div_m, div_r_out, reg3, - reg4); + dev_dbg(s->dev, "f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n", + f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4); ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00608008); if (ret) @@ -837,14 +819,14 @@ static int msi2500_set_usb_adc(struct msi2500_state *s) goto err; err: return ret; -}; +} static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count) { struct msi2500_state *s = vb2_get_drv_priv(vq); int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); if (!s->udev) return -ENODEV; @@ -872,7 +854,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq) { struct msi2500_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(s->dev, "\n"); mutex_lock(&s->v4l2_lock); @@ -908,7 +890,7 @@ static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, { struct msi2500_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index); + dev_dbg(s->dev, "index=%d\n", f->index); if (f->index >= s->num_formats) return -EINVAL; @@ -924,7 +906,7 @@ static int msi2500_g_fmt_sdr_cap(struct file *file, void *priv, { struct msi2500_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", (char *)&s->pixelformat); f->fmt.sdr.pixelformat = s->pixelformat; @@ -941,7 +923,7 @@ static int msi2500_s_fmt_sdr_cap(struct file *file, void *priv, struct vb2_queue *q = &s->vb_queue; int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); if (vb2_is_busy(q)) @@ -971,7 +953,7 @@ static int msi2500_try_fmt_sdr_cap(struct file *file, void *priv, struct msi2500_state *s = video_drvdata(file); int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(s->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); @@ -994,7 +976,7 @@ static int msi2500_s_tuner(struct file *file, void *priv, struct msi2500_state *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + dev_dbg(s->dev, "index=%d\n", v->index); if (v->index == 0) ret = 0; @@ -1011,7 +993,7 @@ static int msi2500_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) struct msi2500_state *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + dev_dbg(s->dev, "index=%d\n", v->index); if (v->index == 0) { strlcpy(v->name, "Mirics MSi2500", sizeof(v->name)); @@ -1035,8 +1017,7 @@ static int msi2500_g_frequency(struct file *file, void *priv, struct msi2500_state *s = video_drvdata(file); int ret = 0; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", - __func__, f->tuner, f->type); + dev_dbg(s->dev, "tuner=%d type=%d\n", f->tuner, f->type); if (f->tuner == 0) { f->frequency = s->f_adc; @@ -1057,15 +1038,14 @@ static int msi2500_s_frequency(struct file *file, void *priv, struct msi2500_state *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); + dev_dbg(s->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); if (f->tuner == 0) { s->f_adc = clamp_t(unsigned int, f->frequency, bands[0].rangelow, bands[0].rangehigh); - dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", - __func__, s->f_adc); + dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc); ret = msi2500_set_usb_adc(s); } else if (f->tuner == 1) { ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f); @@ -1082,8 +1062,8 @@ static int msi2500_enum_freq_bands(struct file *file, void *priv, struct msi2500_state *s = video_drvdata(file); int ret; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); + dev_dbg(s->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands)) { @@ -1168,8 +1148,7 @@ static int msi2500_transfer_one_message(struct spi_master *master, u32 data; list_for_each_entry(t, &m->transfers, transfer_list) { - dev_dbg(&s->udev->dev, "%s: msg=%*ph\n", - __func__, t->len, t->tx_buf); + dev_dbg(s->dev, "msg=%*ph\n", t->len, t->tx_buf); data = 0x09; /* reg 9 is SPI adapter */ data |= ((u8 *)t->tx_buf)[0] << 8; data |= ((u8 *)t->tx_buf)[1] << 16; @@ -1185,8 +1164,7 @@ static int msi2500_transfer_one_message(struct spi_master *master, static int msi2500_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(intf); - struct msi2500_state *s = NULL; + struct msi2500_state *s; struct v4l2_subdev *sd; struct spi_master *master; int ret; @@ -1199,7 +1177,7 @@ static int msi2500_probe(struct usb_interface *intf, s = kzalloc(sizeof(struct msi2500_state), GFP_KERNEL); if (s == NULL) { - pr_err("Could not allocate memory for msi2500_state\n"); + dev_err(&intf->dev, "Could not allocate memory for state\n"); return -ENOMEM; } @@ -1207,7 +1185,8 @@ static int msi2500_probe(struct usb_interface *intf, mutex_init(&s->vb_queue_lock); spin_lock_init(&s->queued_bufs_lock); INIT_LIST_HEAD(&s->queued_bufs); - s->udev = udev; + s->dev = &intf->dev; + s->udev = interface_to_usbdev(intf); s->f_adc = bands[0].rangelow; s->pixelformat = formats[0].pixelformat; s->buffersize = formats[0].buffersize; @@ -1225,7 +1204,7 @@ static int msi2500_probe(struct usb_interface *intf, s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&s->vb_queue); if (ret) { - dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); + dev_err(s->dev, "Could not initialize vb2 queue\n"); goto err_free_mem; } @@ -1239,13 +1218,12 @@ static int msi2500_probe(struct usb_interface *intf, s->v4l2_dev.release = msi2500_video_release; ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); if (ret) { - dev_err(&s->udev->dev, - "Failed to register v4l2-device (%d)\n", ret); + dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret); goto err_free_mem; } /* SPI master adapter */ - master = spi_alloc_master(&s->udev->dev, 0); + master = spi_alloc_master(s->dev, 0); if (master == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; @@ -1266,7 +1244,7 @@ static int msi2500_probe(struct usb_interface *intf, sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info); s->v4l2_subdev = sd; if (sd == NULL) { - dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n"); + dev_err(s->dev, "cannot get v4l2 subdevice\n"); ret = -ENODEV; goto err_unregister_master; } @@ -1275,7 +1253,7 @@ static int msi2500_probe(struct usb_interface *intf, v4l2_ctrl_handler_init(&s->hdl, 0); if (s->hdl.error) { ret = s->hdl.error; - dev_err(&s->udev->dev, "Could not initialize controls\n"); + dev_err(s->dev, "Could not initialize controls\n"); goto err_free_controls; } @@ -1288,16 +1266,13 @@ static int msi2500_probe(struct usb_interface *intf, ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); if (ret) { - dev_err(&s->udev->dev, - "Failed to register as video device (%d)\n", + dev_err(s->dev, "Failed to register as video device (%d)\n", ret); goto err_unregister_v4l2_dev; } - dev_info(&s->udev->dev, "Registered as %s\n", + dev_info(s->dev, "Registered as %s\n", video_device_node_name(&s->vdev)); - dev_notice(&s->udev->dev, - "%s: SDR API is still slightly experimental and functionality changes may follow\n", - KBUILD_MODNAME); + dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n"); return 0; -- cgit v1.2.3 From 5fa51cc36ac14e0a2a6fd4f9037bf4372066e894 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:12:13 -0300 Subject: [media] msi001: logging changes Remove function name from debug logs. Logging system could add it automatically. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/msi001.c | 56 ++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index ee99e372c943..26019e731993 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -67,7 +67,8 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, { int ret; u32 reg; - dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__, + + dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n", lna_gain, mixer_gain, if_gain); reg = 1 << 0; @@ -83,7 +84,7 @@ static int msi001_set_gain(struct msi001 *s, int lna_gain, int mixer_gain, return 0; err: - dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&s->spi->dev, "failed %d\n", ret); return ret; }; @@ -94,6 +95,7 @@ static int msi001_set_tuner(struct msi001 *s) u32 reg; u64 f_vco, tmp64; u8 mode, filter_mode, lo_div; + static const struct { u32 rf; u8 mode; @@ -145,9 +147,7 @@ static int msi001_set_tuner(struct msi001 *s) #define R_REF 4 #define F_OUT_STEP 1 - dev_dbg(&s->spi->dev, - "%s: f_rf=%d f_if=%d\n", - __func__, f_rf, f_if); + dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if); for (i = 0; i < ARRAY_SIZE(band_lut); i++) { if (f_rf <= band_lut[i].rf) { @@ -198,8 +198,7 @@ static int msi001_set_tuner(struct msi001 *s) s->bandwidth->val = bandwidth_lut[i].freq; - dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n", - __func__, bandwidth_lut[i].freq); + dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq); f_vco = (u64) (f_rf + f_if + f_if1) * lo_div; tmp64 = f_vco; @@ -225,9 +224,8 @@ static int msi001_set_tuner(struct msi001 *s) tmp += 1ul * F_REF * R_REF * frac / thresh; tmp /= lo_div; - dev_dbg(&s->spi->dev, - "%s: rf=%u:%u n=%d thresh=%d frac=%d\n", - __func__, f_rf, tmp, n, thresh, frac); + dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n", + f_rf, tmp, n, thresh, frac); ret = msi001_wreg(s, 0x00000e); if (ret) @@ -276,7 +274,7 @@ static int msi001_set_tuner(struct msi001 *s) return 0; err: - dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&s->spi->dev, "failed %d\n", ret); return ret; }; @@ -284,7 +282,8 @@ static int msi001_s_power(struct v4l2_subdev *sd, int on) { struct msi001 *s = sd_to_msi001(sd); int ret; - dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on); + + dev_dbg(&s->spi->dev, "on=%d\n", on); if (on) ret = 0; @@ -301,7 +300,8 @@ static const struct v4l2_subdev_core_ops msi001_core_ops = { static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + + dev_dbg(&s->spi->dev, "index=%d\n", v->index); strlcpy(v->name, "Mirics MSi001", sizeof(v->name)); v->type = V4L2_TUNER_RF; @@ -315,14 +315,16 @@ static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index); + + dev_dbg(&s->spi->dev, "index=%d\n", v->index); return 0; } static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner); + + dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner); f->frequency = s->f_tuner; return 0; } @@ -332,8 +334,9 @@ static int msi001_s_frequency(struct v4l2_subdev *sd, { struct msi001 *s = sd_to_msi001(sd); unsigned int band; - dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); + + dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2)) band = 0; @@ -349,8 +352,9 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd, struct v4l2_frequency_band *band) { struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); + + dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->index >= ARRAY_SIZE(bands)) return -EINVAL; @@ -380,9 +384,10 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl); int ret; + dev_dbg(&s->spi->dev, - "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - __func__, ctrl->id, ctrl->name, ctrl->val, + "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, ctrl->step); switch (ctrl->id) { @@ -403,8 +408,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl) s->mixer_gain->cur.val, s->if_gain->val); break; default: - dev_dbg(&s->spi->dev, "%s: unkown control %d\n", - __func__, ctrl->id); + dev_dbg(&s->spi->dev, "unkown control %d\n", ctrl->id); ret = -EINVAL; } @@ -419,7 +423,8 @@ static int msi001_probe(struct spi_device *spi) { struct msi001 *s; int ret; - dev_dbg(&spi->dev, "%s:\n", __func__); + + dev_dbg(&spi->dev, "\n"); s = kzalloc(sizeof(struct msi001), GFP_KERNEL); if (s == NULL) { @@ -466,7 +471,8 @@ static int msi001_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); struct msi001 *s = sd_to_msi001(sd); - dev_dbg(&spi->dev, "%s:\n", __func__); + + dev_dbg(&spi->dev, "\n"); /* * Registered by v4l2_spi_new_subdev() from master driver, but we must -- cgit v1.2.3 From b63ab6b064f73721568a46080d41422ea223ee6e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:26:23 -0300 Subject: [media] msi2500: remove unneeded spinlock irq flags initialization There is no need to init flags before calling spin_lock_irqsave(). spin_lock_irqsave is macro which stores value to 'flags'. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 647846b5904a..efc761c78f72 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -160,7 +160,7 @@ struct msi2500_state { static struct msi2500_frame_buf *msi2500_get_next_fill_buf( struct msi2500_state *s) { - unsigned long flags = 0; + unsigned long flags; struct msi2500_frame_buf *buf = NULL; spin_lock_irqsave(&s->queued_bufs_lock, flags); @@ -558,7 +558,7 @@ static int msi2500_isoc_init(struct msi2500_state *s) /* Must be called with vb_queue_lock hold */ static void msi2500_cleanup_queued_bufs(struct msi2500_state *s) { - unsigned long flags = 0; + unsigned long flags; dev_dbg(s->dev, "\n"); @@ -634,7 +634,7 @@ static void msi2500_buf_queue(struct vb2_buffer *vb) struct msi2500_state *s = vb2_get_drv_priv(vb->vb2_queue); struct msi2500_frame_buf *buf = container_of(vb, struct msi2500_frame_buf, vb); - unsigned long flags = 0; + unsigned long flags; /* Check the device has not disconnected between prep and queuing */ if (unlikely(!s->udev)) { -- cgit v1.2.3 From 13bd82d18ec29c7c81f2d42816f5a14095977c9e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:35:48 -0300 Subject: [media] e4000: logging changes Remove function name from debug logs. Logging system could add it automatically. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.c | 71 ++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index cd9cf643f602..510239f80c0d 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -26,7 +26,7 @@ static int e4000_init(struct dvb_frontend *fe) struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); /* dummy I2C to ensure I2C wakes up */ ret = regmap_write(s->regmap, 0x02, 0x40); @@ -87,7 +87,7 @@ static int e4000_init(struct dvb_frontend *fe) s->active = true; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -97,7 +97,7 @@ static int e4000_sleep(struct dvb_frontend *fe) struct e4000 *s = fe->tuner_priv; int ret; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; @@ -106,7 +106,7 @@ static int e4000_sleep(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -121,9 +121,8 @@ static int e4000_set_params(struct dvb_frontend *fe) u8 buf[5], i_data[4], q_data[4]; dev_dbg(&s->client->dev, - "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n", - __func__, c->delivery_system, c->frequency, - c->bandwidth_hz); + "delivery_system=%d frequency=%u bandwidth_hz=%u\n", + c->delivery_system, c->frequency, c->bandwidth_hz); /* gain control manual */ ret = regmap_write(s->regmap, 0x1a, 0x00); @@ -150,9 +149,8 @@ static int e4000_set_params(struct dvb_frontend *fe) buf[3] = 0x00; buf[4] = e4000_pll_lut[i].div; - dev_dbg(&s->client->dev, - "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n", - __func__, f_vco, buf[0], sigma_delta); + dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n", + f_vco, buf[0], sigma_delta); ret = regmap_bulk_write(s->regmap, 0x09, buf, 5); if (ret) @@ -253,7 +251,7 @@ static int e4000_set_params(struct dvb_frontend *fe) goto err; err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -262,7 +260,7 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { struct e4000 *s = fe->tuner_priv; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); *frequency = 0; /* Zero-IF */ @@ -276,10 +274,9 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n", - __func__, s->lna_gain_auto->cur.val, - s->lna_gain_auto->val, s->lna_gain->cur.val, - s->lna_gain->val); + dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n", + s->lna_gain_auto->cur.val, s->lna_gain_auto->val, + s->lna_gain->cur.val, s->lna_gain->val); if (s->lna_gain_auto->val && s->if_gain_auto->cur.val) u8tmp = 0x17; @@ -301,7 +298,7 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -312,10 +309,9 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) int ret; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n", - __func__, s->mixer_gain_auto->cur.val, - s->mixer_gain_auto->val, s->mixer_gain->cur.val, - s->mixer_gain->val); + dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n", + s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val, + s->mixer_gain->cur.val, s->mixer_gain->val); if (s->mixer_gain_auto->val) u8tmp = 0x15; @@ -333,7 +329,7 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -345,10 +341,9 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) u8 buf[2]; u8 u8tmp; - dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n", - __func__, s->if_gain_auto->cur.val, - s->if_gain_auto->val, s->if_gain->cur.val, - s->if_gain->val); + dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n", + s->if_gain_auto->cur.val, s->if_gain_auto->val, + s->if_gain->cur.val, s->if_gain->val); if (s->if_gain_auto->val && s->lna_gain_auto->cur.val) u8tmp = 0x17; @@ -372,7 +367,7 @@ static int e4000_set_if_gain(struct dvb_frontend *fe) } err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -390,7 +385,7 @@ static int e4000_pll_lock(struct dvb_frontend *fe) s->pll_lock->val = (utmp & 0x01); err: if (ret) - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -408,8 +403,8 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ret = e4000_pll_lock(s->fe); break; default: - dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", - __func__, ctrl->id, ctrl->name); + dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -445,8 +440,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl) ret = e4000_set_if_gain(s->fe); break; default: - dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n", - __func__, ctrl->id, ctrl->name); + dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); ret = -EINVAL; } @@ -494,7 +489,7 @@ static int e4000_probe(struct i2c_client *client, s = kzalloc(sizeof(struct e4000), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -512,7 +507,7 @@ static int e4000_probe(struct i2c_client *client, if (ret) goto err; - dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp); + dev_dbg(&s->client->dev, "chip id=%02x\n", utmp); if (utmp != 0x40) { ret = -ENODEV; @@ -559,9 +554,7 @@ static int e4000_probe(struct i2c_client *client, s->sd.ctrl_handler = &s->hdl; #endif - dev_info(&s->client->dev, - "%s: Elonics E4000 successfully identified\n", - KBUILD_MODNAME); + dev_info(&s->client->dev, "Elonics E4000 successfully identified\n"); fe->tuner_priv = s; memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops, @@ -573,7 +566,7 @@ static int e4000_probe(struct i2c_client *client, return 0; err: if (ret) { - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(s); } @@ -586,7 +579,7 @@ static int e4000_remove(struct i2c_client *client) struct e4000 *s = container_of(sd, struct e4000, sd); struct dvb_frontend *fe = s->fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); #if IS_ENABLED(CONFIG_VIDEO_V4L2) v4l2_ctrl_handler_free(&s->hdl); -- cgit v1.2.3 From abfc8d66d72ba183eb3b5d344fd1ec17233db8bb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:37:57 -0300 Subject: [media] rtl2832_sdr: remove unneeded spinlock irq flags initialization There is no need to init flags before calling spin_lock_irqsave(). spin_lock_irqsave is macro which stores value to 'flags' Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 5bcf48bb4a71..029189d8be88 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -329,7 +329,7 @@ static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg, static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf( struct rtl2832_sdr_state *s) { - unsigned long flags = 0; + unsigned long flags; struct rtl2832_sdr_frame_buf *buf = NULL; spin_lock_irqsave(&s->queued_bufs_lock, flags); @@ -570,7 +570,7 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) /* Must be called with vb_queue_lock hold */ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s) { - unsigned long flags = 0; + unsigned long flags; dev_dbg(&s->udev->dev, "%s:\n", __func__); @@ -659,7 +659,7 @@ static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb) struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); struct rtl2832_sdr_frame_buf *buf = container_of(vb, struct rtl2832_sdr_frame_buf, vb); - unsigned long flags = 0; + unsigned long flags; /* Check the device has not disconnected between prep and queuing */ if (!s->udev) { -- cgit v1.2.3 From b538a8e85b2b2fbb954da2b9189eaf18cf9098bf Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:44:13 -0300 Subject: [media] rtl2832_sdr: enhance sample rate debug calculation precision Sample rate calculation gives a little bit too large results because in real life there was around one milliseconds (~one usb packet) too much data for given time. Calculate time more accurate in order to provide better results. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 029189d8be88..9211ddeff227 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -365,17 +365,19 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, dst_len = 0; } - /* calculate samping rate and output it in 10 seconds intervals */ + /* calculate sample rate and output it in 10 seconds intervals */ if (unlikely(time_is_before_jiffies(s->jiffies_next))) { -#define MSECS 10000UL + #define MSECS 10000UL + unsigned int msecs = jiffies_to_msecs(jiffies - + s->jiffies_next + msecs_to_jiffies(MSECS)); unsigned int samples = s->sample - s->sample_measured; s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample_measured = s->sample; dev_dbg(&s->udev->dev, - "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", - src_len, samples, MSECS, - samples * 1000UL / MSECS); + "slen=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); } /* total number of I+Q pairs */ -- cgit v1.2.3 From d4d2050006bfb0c4af41288143424d3b0b9b325e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Aug 2014 23:57:54 -0300 Subject: [media] rtl2832_sdr: logging changes Remove function name from debug logs. Logging system could add it automatically. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 98 ++++++++++++++----------------- 1 file changed, 45 insertions(+), 53 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 9211ddeff227..7bf98cf6bbe1 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -396,8 +396,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) struct rtl2832_sdr_frame_buf *fbuf; dev_dbg_ratelimited(&s->udev->dev, - "%s: status=%d length=%d/%d errors=%d\n", - __func__, urb->status, urb->actual_length, + "status=%d length=%d/%d errors=%d\n", + urb->status, urb->actual_length, urb->transfer_buffer_length, urb->error_count); switch (urb->status) { @@ -445,7 +445,7 @@ static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s) int i; for (i = s->urbs_submitted - 1; i >= 0; i--) { - dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "kill urb=%d\n", i); /* stop the URB */ usb_kill_urb(s->urb_list[i]); } @@ -459,7 +459,7 @@ static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s) int i, ret; for (i = 0; i < s->urbs_initialized; i++) { - dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "submit urb=%d\n", i); ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); if (ret) { dev_err(&s->udev->dev, @@ -479,8 +479,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s) if (s->flags & USB_STATE_URB_BUF) { while (s->buf_num) { s->buf_num--; - dev_dbg(&s->udev->dev, "%s: free buf=%d\n", - __func__, s->buf_num); + dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num); usb_free_coherent(s->udev, s->buf_size, s->buf_list[s->buf_num], s->dma_addr[s->buf_num]); @@ -496,24 +495,22 @@ static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s) s->buf_num = 0; s->buf_size = BULK_BUFFER_SIZE; - dev_dbg(&s->udev->dev, - "%s: all in all I will use %u bytes for streaming\n", - __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE); + dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n", + MAX_BULK_BUFS * BULK_BUFFER_SIZE); for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, BULK_BUFFER_SIZE, GFP_ATOMIC, &s->dma_addr[s->buf_num]); if (!s->buf_list[s->buf_num]) { - dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n", - __func__, s->buf_num); + dev_dbg(&s->udev->dev, "alloc buf=%d failed\n", + s->buf_num); rtl2832_sdr_free_stream_bufs(s); return -ENOMEM; } - dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", - __func__, s->buf_num, - s->buf_list[s->buf_num], + dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n", + s->buf_num, s->buf_list[s->buf_num], (long long)s->dma_addr[s->buf_num]); s->flags |= USB_STATE_URB_BUF; } @@ -529,8 +526,7 @@ static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s) for (i = s->urbs_initialized - 1; i >= 0; i--) { if (s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: free urb=%d\n", - __func__, i); + dev_dbg(&s->udev->dev, "free urb=%d\n", i); /* free the URBs */ usb_free_urb(s->urb_list[i]); } @@ -546,10 +542,10 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) /* allocate the URBs */ for (i = 0; i < MAX_BULK_BUFS; i++) { - dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "alloc urb=%d\n", i); s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: failed\n", __func__); + dev_dbg(&s->udev->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(s->urb_list[j]); return -ENOMEM; @@ -574,7 +570,7 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s) { unsigned long flags; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); spin_lock_irqsave(&s->queued_bufs_lock, flags); while (!list_empty(&s->queued_bufs)) { @@ -593,7 +589,7 @@ static void rtl2832_sdr_release_sec(struct dvb_frontend *fe) { struct rtl2832_sdr_state *s = fe->sec_priv; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); mutex_lock(&s->vb_queue_lock); mutex_lock(&s->v4l2_lock); @@ -615,7 +611,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); @@ -633,15 +629,15 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, { struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ if (vq->num_buffers + *nbuffers < 8) *nbuffers = 8 - vq->num_buffers; *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", - __func__, *nbuffers, sizes[0]); + dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n", + *nbuffers, sizes[0]); return 0; } @@ -683,7 +679,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) u64 u64tmp; u32 u32tmp; - dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc); + dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc); if (!test_bit(POWER_ON, &s->flags)) return 0; @@ -717,8 +713,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) u64tmp = -u64tmp; u32tmp = u64tmp & 0x3fffff; - dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n", - __func__, f_if, u32tmp); + dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp); buf[0] = (u32tmp >> 16) & 0xff; buf[1] = (u32tmp >> 8) & 0xff; @@ -905,7 +900,7 @@ static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s) { int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); /* PID filter */ ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1); @@ -966,8 +961,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) c->frequency = s->f_tuner; c->delivery_system = SYS_DVBT; - dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n", - __func__, c->frequency, c->bandwidth_hz); + dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n", + c->frequency, c->bandwidth_hz); if (!test_bit(POWER_ON, &s->flags)) return 0; @@ -982,7 +977,7 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s) { struct dvb_frontend *fe = s->fe; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (fe->ops.tuner_ops.init) fe->ops.tuner_ops.init(fe); @@ -994,7 +989,7 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s) { struct dvb_frontend *fe = s->fe; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); @@ -1007,7 +1002,7 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (!s->udev) return -ENODEV; @@ -1056,7 +1051,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) { struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); mutex_lock(&s->v4l2_lock); @@ -1090,8 +1085,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n", - __func__, v->index, v->type); + dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type); if (v->index == 0) { strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); @@ -1117,7 +1111,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (v->index > 1) return -EINVAL; @@ -1129,8 +1123,8 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); + dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands_adc)) @@ -1155,8 +1149,8 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int ret = 0; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", - __func__, f->tuner, f->type); + dev_dbg(&s->udev->dev, "tuner=%d type=%d\n", + f->tuner, f->type); if (f->tuner == 0) { f->frequency = s->f_adc; @@ -1177,8 +1171,8 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int ret, band; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); + dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); /* ADC band midpoints */ #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) @@ -1196,15 +1190,13 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, bands_adc[band].rangelow, bands_adc[band].rangehigh); - dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", - __func__, s->f_adc); + dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc); ret = rtl2832_sdr_set_adc(s); } else if (f->tuner == 1) { s->f_tuner = clamp_t(unsigned int, f->frequency, bands_fm[0].rangelow, bands_fm[0].rangehigh); - dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", - __func__, f->frequency); + dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency); ret = rtl2832_sdr_set_tuner_freq(s); } else { @@ -1219,7 +1211,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (f->index >= s->num_formats) return -EINVAL; @@ -1235,7 +1227,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); f->fmt.sdr.pixelformat = s->pixelformat; f->fmt.sdr.buffersize = s->buffersize; @@ -1252,7 +1244,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, struct vb2_queue *q = &s->vb_queue; int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); if (vb2_is_busy(q)) @@ -1282,7 +1274,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); @@ -1356,8 +1348,8 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) int ret; dev_dbg(&s->udev->dev, - "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - __func__, ctrl->id, ctrl->name, ctrl->val, + "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, ctrl->step); switch (ctrl->id) { -- cgit v1.2.3 From 0e38233d329e463a64146080c008d8044651bd3f Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 25 Aug 2014 15:07:02 -0300 Subject: [media] si2157: change command for sleep Instead of sending command 13 to the tuner, send command 16 when sleeping. This behaviour is observed when using manufacturer provided binary-only Linux driver for TechnoTrend CT2-4400 (Windows driver does not do power management). The issue with command 13 is that firmware loading is necessary after that. This is not an issue with tuners that do not require firmware, but starting streaming after sleep on an Si2158 takes noticeable time as firmware is loaded on resume. Signed-off-by: Olli Salonen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index efb5cced30a5..c84f7b8ee8d2 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -197,9 +197,10 @@ static int si2157_sleep(struct dvb_frontend *fe) s->active = false; - memcpy(cmd.args, "\x13", 1); - cmd.wlen = 1; - cmd.rlen = 0; + /* standby */ + memcpy(cmd.args, "\x16\x00", 2); + cmd.wlen = 2; + cmd.rlen = 1; ret = si2157_cmd_execute(s, &cmd); if (ret) goto err; -- cgit v1.2.3 From 4cbf6ed910c88d7f6c15304f9a5a3ed86290dc06 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 25 Aug 2014 15:07:03 -0300 Subject: [media] si2157: avoid firmware loading if it has been loaded previously Add a variable into state to keep track if firmware has been loaded or not. Skip firmware loading in case it is already loaded (resume from sleep). Signed-off-by: Olli Salonen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 11 +++++++++-- drivers/media/tuners/si2157_priv.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index c84f7b8ee8d2..5901484011b9 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -89,7 +89,10 @@ static int si2157_init(struct dvb_frontend *fe) dev_dbg(&s->client->dev, "\n"); - /* configure? */ + if (s->fw_loaded) + goto warm; + + /* power up */ memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); cmd.wlen = 15; cmd.rlen = 1; @@ -176,9 +179,12 @@ skip_fw_download: if (ret) goto err; - s->active = true; + s->fw_loaded = true; +warm: + s->active = true; return 0; + err: if (fw) release_firmware(fw); @@ -320,6 +326,7 @@ static int si2157_probe(struct i2c_client *client, s->client = client; s->fe = cfg->fe; s->inversion = cfg->inversion; + s->fw_loaded = false; mutex_init(&s->i2c_mutex); /* check if the tuner is there */ diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 3ddab5e6b500..4080a57962f0 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -26,6 +26,7 @@ struct si2157 { struct i2c_client *client; struct dvb_frontend *fe; bool active; + bool fw_loaded; bool inversion; }; -- cgit v1.2.3 From 8e417224dfb397633601a04214841df12cd470b0 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 25 Aug 2014 15:07:04 -0300 Subject: [media] si2168: avoid firmware loading if it has been loaded previously Add a variable to keep track if firmware is loaded or not and skip parts of the initialization if fw is already loaded. Resume from sleep with a different command compared to initial power up and run command 85 after resume command. This behaviour is observed when using manufacturer provided binary-only si2168 driver for TechnoTrend CT2-4400. Signed-off-by: Olli Salonen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 31 ++++++++++++++++++++++++++++--- drivers/media/dvb-frontends/si2168_priv.h | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 55a4212aea75..a0797fd95129 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -363,6 +363,7 @@ static int si2168_init(struct dvb_frontend *fe) dev_dbg(&s->client->dev, "\n"); + /* initialize */ memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); cmd.wlen = 13; cmd.rlen = 0; @@ -370,6 +371,26 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + if (s->fw_loaded) { + /* resume */ + memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); + cmd.wlen = 8; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + memcpy(cmd.args, "\x85", 1); + cmd.wlen = 1; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + goto warm; + } + + /* power up */ memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); cmd.wlen = 8; cmd.rlen = 1; @@ -466,9 +487,6 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; - dev_info(&s->client->dev, "found a '%s' in warm state\n", - si2168_ops.info.name); - /* set ts mode */ memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); cmd.args[4] |= s->ts_mode; @@ -478,6 +496,12 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + s->fw_loaded = true; + +warm: + dev_info(&s->client->dev, "found a '%s' in warm state\n", + si2168_ops.info.name); + s->active = true; return 0; @@ -645,6 +669,7 @@ static int si2168_probe(struct i2c_client *client, *config->i2c_adapter = s->adapter; *config->fe = &s->fe; s->ts_mode = config->ts_mode; + s->fw_loaded = false; i2c_set_clientdata(client, s); diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 0f832844b831..e13983ed4be1 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -36,6 +36,7 @@ struct si2168 { fe_delivery_system_t delivery_system; fe_status_t fe_status; bool active; + bool fw_loaded; u8 ts_mode; }; -- cgit v1.2.3 From 976bcb2f6f9c9fb11f0aad7b7c87953e9c3f0116 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 31 Jul 2014 16:35:56 -0300 Subject: [media] tda18212: add support for slave chip version There is 2 different versions of that chip available, master and slave. Slave is used only on dual tuner devices with master tuner. Laser printing top of chip is 18212/M or 18212/S according to chip version. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18212.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 05a4ac9edb6b..15b09f8d85c0 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -306,7 +306,8 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, { struct tda18212_priv *priv = NULL; int ret; - u8 val; + u8 chip_id = chip_id; + char *version; priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); if (priv == NULL) @@ -320,26 +321,38 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ /* check if the tuner is there */ - ret = tda18212_rd_reg(priv, 0x00, &val); + ret = tda18212_rd_reg(priv, 0x00, &chip_id); + dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ - if (!ret) - dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val); - if (ret || val != 0xc7) { - kfree(priv); - return NULL; + if (ret) + goto err; + + switch (chip_id) { + case 0xc7: + version = "M"; /* master */ + break; + case 0x47: + version = "S"; /* slave */ + break; + default: + goto err; } dev_info(&priv->i2c->dev, - "%s: NXP TDA18212HN successfully identified\n", - KBUILD_MODNAME); + "%s: NXP TDA18212HN/%s successfully identified\n", + KBUILD_MODNAME, version); memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, sizeof(struct dvb_tuner_ops)); return fe; +err: + dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); + kfree(priv); + return NULL; } EXPORT_SYMBOL(tda18212_attach); -- cgit v1.2.3 From c0aaf696d45e2a72048a56441e81dad78659c698 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 19 Sep 2014 08:32:30 -0300 Subject: [media] coda: coda-bit: Include "" coda-bit uses kmalloc/kfree functions, so the slab header needs to be included in order to fix the following build errors: drivers/media/platform/coda/coda-bit.c: In function 'coda_fill_bitstream': drivers/media/platform/coda/coda-bit.c:231:4: error: implicit declaration of function 'kmalloc' [-Werror=implicit-function-declaration] drivers/media/platform/coda/coda-bit.c: In function 'coda_alloc_framebuffers': drivers/media/platform/coda/coda-bit.c:312:3: error: implicit declaration of function 'kfree' [-Werror=implicit-function-declaration] Signed-off-by: Fabio Estevam Acked-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 07fc91aba1e0..9b8ea8bbeb4e 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 7c5e3e5f017d3fced9211747bed423c6bcda7f7c Mon Sep 17 00:00:00 2001 From: Bimow Chen Date: Fri, 1 Aug 2014 06:19:58 -0300 Subject: [media] get_dvb_firmware: Update firmware of ITEtech IT9135 IT9135 firmware update. Signed-off-by: Bimow Chen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/get_dvb_firmware | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 26c623dd3aa3..91b43d2738c7 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -708,23 +708,25 @@ sub drxk_terratec_htc_stick { } sub it9135 { - my $sourcefile = "dvb-usb-it9135.zip"; - my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile"; - my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9"; - my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); - my $outfile = "dvb-usb-it9135.fw"; + my $url = "http://www.ite.com.tw/uploads/firmware/v3.25.0.0/"; + my $file1 = "dvb-usb-it9135-01.zip"; my $fwfile1 = "dvb-usb-it9135-01.fw"; + my $hash1 = "02fcf11174eda84745dae7e61c5ff9ba"; + my $file2 = "dvb-usb-it9135-02.zip"; my $fwfile2 = "dvb-usb-it9135-02.fw"; + my $hash2 = "d5e1437dc24358578e07999475d4cac9"; checkstandard(); - wgetfile($sourcefile, $url); - unzip($sourcefile, $tmpdir); - verify("$tmpdir/$outfile", $hash); - extract("$tmpdir/$outfile", 64, 8128, "$fwfile1"); - extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2"); + wgetfile($file1, $url . $file1); + unzip($file1, ""); + verify("$fwfile1", $hash1); + + wgetfile($file2, $url . $file2); + unzip($file2, ""); + verify("$fwfile2", $hash2); - "$fwfile1 $fwfile2" + "$file1 $file2" } sub tda10071 { -- cgit v1.2.3 From ca681fe0bc9358516c159a35e54069b1a43f25b2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 8 Aug 2014 23:56:49 -0300 Subject: [media] af9033: provide dyn0_clk clock source AF903x/IT913x demod provides clock source(s). It seems that this clock source is used for integrated RF tuner of IT913x. It is enabled by default, but firmware disables it automatically when suspend is requested (suspend_flag (0x004c) + trigger_ofsm (0x0000)). Automatic disable behavior seems to be similar for both AF903x and IT913x I tested, though there is no likely any real clock user in a case of AF903x. Cc: Bimow Chen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 10 ++-------- drivers/media/dvb-frontends/af9033.h | 5 +++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 5c90ea683a7e..2a4dfd2f9679 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -314,14 +314,8 @@ static int af9033_init(struct dvb_frontend *fe) goto err; } - /* feed clock to RF tuner */ - 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: + /* clock output */ + if (state->cfg.dyn0_clk) { ret = af9033_wr_reg(state, 0x80fba8, 0x00); if (ret < 0) goto err; diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 539f4db678b8..b95a6d438eca 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -75,6 +75,11 @@ struct af9033_config { * input spectrum inversion */ bool spec_inv; + + /* + * + */ + bool dyn0_clk; }; -- cgit v1.2.3 From 15ba8202e6f9417abd1d6831aca4237407e0ff0b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 00:08:57 -0300 Subject: [media] af9035: enable AF9033 demod clock source for IT9135 Integrated RF tuner of IT9135 is connected to demod clock source named dyn0_clk. Enable that clock source in order to provide stable clock early enough. Cc: Bimow Chen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index c82beac0e0cb..8ac0423c70d5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -647,16 +647,19 @@ static int af9035_read_config(struct dvb_usb_device *d) 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) { + /* feed clock for integrated RF tuner */ + state->af9033_config[0].dyn0_clk = true; + state->af9033_config[1].dyn0_clk = true; + 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; + tmp16 = 0x00461d; /* eeprom memory mapped location */ } else { state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38; - tmp16 = 0x00461b; + tmp16 = 0x00461b; /* eeprom memory mapped location */ } /* check if eeprom exists */ -- cgit v1.2.3 From f69429447ac11edfcbedd11cff62917831141e35 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 00:15:05 -0300 Subject: [media] it913x: fix tuner sleep power leak IT913x tuner driver disables own clock, provided by demod core, as very a first operation when tuner is put on *sleep*. That likely causes failure of all the rest commands on sleep sequence, which leads situation where tuner is not actually on sleep, but consuming a lot of power. I measured 102mA current consumption from the USB before change and after change it was only 32mA. Used device was single tuner IT9135 BX. Second reason to remove that register from tuner driver is reason it is simply on wrong driver (demod vs. tuner), breaking the principle of correct driver. Clock is now provided more correctly af9033 demod driver as a config option. Cc: Bimow Chen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner_it913x.c | 1 - drivers/media/tuners/tuner_it913x_priv.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c index 3d83c425bccf..3265d9ab3c67 100644 --- a/drivers/media/tuners/tuner_it913x.c +++ b/drivers/media/tuners/tuner_it913x.c @@ -202,7 +202,6 @@ 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); diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h index ce652108aa5d..8e85a61ea5f9 100644 --- a/drivers/media/tuners/tuner_it913x_priv.h +++ b/drivers/media/tuners/tuner_it913x_priv.h @@ -38,7 +38,6 @@ struct it913xset { u32 pro; /* 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, -- cgit v1.2.3 From 66f6319936344279466bd09f9788e888e03c99a0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 12:35:00 -0300 Subject: [media] it913x: avoid division by zero on error case Error on init leaves some internal divisor zero, which causes oops later. Fix it by populating divisors even it fails. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner_it913x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c index 3265d9ab3c67..cd20c5b0f07e 100644 --- a/drivers/media/tuners/tuner_it913x.c +++ b/drivers/media/tuners/tuner_it913x.c @@ -154,6 +154,9 @@ static int it913x_init(struct dvb_frontend *fe) val = 16; break; case -ENODEV: + /* FIXME: these are just avoid divide by 0 */ + state->tun_xtal = 2000; + state->tun_fdiv = 3; return -ENODEV; case 1: default: -- cgit v1.2.3 From 9e0a976ed60345d53e8d421cb0a39202ce8487fe Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 13:39:16 -0300 Subject: [media] it913x: fix IT9135 AX sleep Old IT9135 AX needs a little bit different register settings for sleep than newer IT9135 BX. This has been broken always, as power management of the whole driver, but it started to be problem as I fixed clock. Earlier clock was disabled very first on sleep and rest of the commands were skipped by the chip as no clock, leaving tuner full power state. When I fixed clocks these PM bugs started raising out as I/O errors. Cc: Bimow Chen Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner_it913x.c | 6 +++++- drivers/media/tuners/tuner_it913x_priv.h | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c index cd20c5b0f07e..281d8c5cc0a9 100644 --- a/drivers/media/tuners/tuner_it913x.c +++ b/drivers/media/tuners/tuner_it913x.c @@ -371,7 +371,11 @@ static int it9137_set_params(struct dvb_frontend *fe) static int it913x_sleep(struct dvb_frontend *fe) { struct it913x_state *state = fe->tuner_priv; - return it913x_script_loader(state, it9137_tuner_off); + + if (state->chip_ver == 0x01) + return it913x_script_loader(state, it9135ax_tuner_off); + else + return it913x_script_loader(state, it9137_tuner_off); } static int it913x_release(struct dvb_frontend *fe) diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h index 8e85a61ea5f9..cc6f4b1e45aa 100644 --- a/drivers/media/tuners/tuner_it913x_priv.h +++ b/drivers/media/tuners/tuner_it913x_priv.h @@ -36,6 +36,17 @@ struct it913xset { u32 pro; u8 count; }; +/* Tuner setting scripts for IT9135 AX */ +static struct it913xset it9135ax_tuner_off[] = { + {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ + {PRO_DMOD, 0xec02, {0x3f}, 0x01}, + {PRO_DMOD, 0xec03, {0x1f}, 0x01}, + {PRO_DMOD, 0xec04, {0x3f}, 0x01}, + {PRO_DMOD, 0xec05, {0x3f}, 0x01}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + /* Tuner setting scripts (still keeping it9137) */ static struct it913xset it9137_tuner_off[] = { {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ -- cgit v1.2.3 From b619ff7ab484ace964b97dacc7e6c78c0e6228aa Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 14:16:29 -0300 Subject: [media] af9035: remove AVerMedia eeprom override Reverts commit 3ab25123373270152a9fae98e3c48ef1b2a878c0 [media] af9035: override tuner for AVerMedia A835B devices Original commit itself is correct, but it was replaced by more general solution (commit 1cbbf90d0406913ad4b44194b07f4f41bde84e54). This old solution was committed by a accident and is not needed anymore. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 8ac0423c70d5..85f2c4bdef98 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -802,25 +802,6 @@ static int af9035_read_config(struct dvb_usb_device *d) addr += 0x10; /* shift for the 2nd tuner params */ } - /* - * These AVerMedia devices has a bad EEPROM content :-( - * Override some wrong values here. - */ - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) { - switch (le16_to_cpu(d->udev->descriptor.idProduct)) { - case USB_PID_AVERMEDIA_A835B_1835: - case USB_PID_AVERMEDIA_A835B_2835: - case USB_PID_AVERMEDIA_A835B_3835: - dev_info(&d->udev->dev, - "%s: overriding tuner from %02x to %02x\n", - KBUILD_MODNAME, state->af9033_config[0].tuner, - AF9033_TUNER_IT9135_60); - - state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60; - break; - } - } - skip_eeprom: /* get demod clock */ ret = af9035_rd_reg(d, 0x00d800, &tmp); -- cgit v1.2.3 From c10989a2a86aa8f6eff9115f67bab55304e2dd0d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 14:49:46 -0300 Subject: [media] af9035: make checkpatch.pl happy Correct issues reported by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 85f2c4bdef98..f37cf7da8c1d 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -536,6 +536,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d, 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__); /* @@ -974,6 +975,7 @@ 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; } @@ -982,6 +984,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) { @@ -1068,6 +1071,7 @@ 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__); /* @@ -1393,6 +1397,7 @@ 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) @@ -1554,7 +1559,8 @@ static const struct usb_device_id af9035_id_table[] = { RC_MAP_IT913X_V1) }, /* 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) }, + &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", + NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05, &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) }, { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900, -- cgit v1.2.3 From 24e419a0f383e626092eb3c13097b691d2923735 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 14:59:53 -0300 Subject: [media] af9033: make checkpatch.pl happy Correct issues reported by checkpatch.pl. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 2a4dfd2f9679..7f22f011f8f5 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -69,8 +69,9 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, if (ret == 1) { ret = 0; } else { - dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%06x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&state->i2c->dev, + "%s: i2c wr failed=%d reg=%06x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -101,8 +102,9 @@ static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) if (ret == 2) { ret = 0; } else { - dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%06x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&state->i2c->dev, + "%s: i2c rd failed=%d reg=%06x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -835,7 +837,7 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) int ret, i, len; u8 buf[3], tmp; u32 snr_val; - const struct val_snr *uninitialized_var(snr_lut); + const struct val_snr *snr_lut; /* read value */ ret = af9033_rd_regs(state, 0x80002c, buf, 3); @@ -928,7 +930,9 @@ static int af9033_update_ch_stat(struct af9033_state *state) abort_cnt = 1000; state->ber = 0xffffffff; } else { - /* 8 byte packets, that have not been rejected already */ + /* + * 8 byte packets, that have not been rejected already + */ bit_cnt -= (u32)abort_cnt; if (bit_cnt == 0) { state->ber = 0xffffffff; @@ -1015,7 +1019,8 @@ err: return ret; } -static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) +static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, + int onoff) { struct af9033_state *state = fe->demodulator_priv; int ret; @@ -1069,8 +1074,8 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, memcpy(&state->cfg, config, sizeof(struct af9033_config)); if (state->cfg.clock != 12000000) { - dev_err(&state->i2c->dev, "%s: af9033: unsupported clock=%d, " \ - "only 12000000 Hz is supported currently\n", + dev_err(&state->i2c->dev, + "%s: af9033: unsupported clock=%d, only 12000000 Hz is supported currently\n", KBUILD_MODNAME, state->cfg.clock); goto err; } @@ -1084,9 +1089,10 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, if (ret < 0) goto err; - dev_info(&state->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d " \ - "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1], - buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + dev_info(&state->i2c->dev, + "%s: firmware version: LINK=%d.%d.%d.%d 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 */ switch (state->cfg.tuner) { -- cgit v1.2.3 From d11132411538761ca79ecded63cd16621b6c40ee Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Aug 2014 15:02:14 -0300 Subject: [media] it913x: make checkpatch.pl happy Correct issues reported by checkpatch.pl Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner_it913x.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c index 281d8c5cc0a9..b92d59979437 100644 --- a/drivers/media/tuners/tuner_it913x.c +++ b/drivers/media/tuners/tuner_it913x.c @@ -46,6 +46,7 @@ static int it913x_rd_regs(struct it913x_state *state, { .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; @@ -61,6 +62,7 @@ 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]; } @@ -75,6 +77,7 @@ static int it913x_wr_regs(struct it913x_state *state, .buf = b, .len = 3 + count } }; int ret; + b[0] = (u8)(reg >> 16) & 0xff; b[1] = (u8)(reg >> 8) & 0xff; b[2] = (u8) reg & 0xff; @@ -122,6 +125,7 @@ static int it913x_script_loader(struct it913x_state *state, struct it913xset *loadscript) { int ret, i; + if (loadscript == NULL) return -EINVAL; -- cgit v1.2.3 From c2ba9726c342d113bdc36cfd8e984e30498037c6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Aug 2014 00:08:16 -0300 Subject: [media] it913x: rename tuner_it913x => it913x Remove tuner_ prefix from module name and file names. Prefix was added due to file name conflict on media out-tree build system. Demodulator having same name does not exists anymore. So lets remove dumb prefix. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Makefile | 2 +- drivers/media/tuners/it913x.c | 463 +++++++++++++++++++++++++++++++ drivers/media/tuners/it913x.h | 45 +++ drivers/media/tuners/it913x_priv.h | 88 ++++++ drivers/media/tuners/tuner_it913x.c | 463 ------------------------------- drivers/media/tuners/tuner_it913x.h | 45 --- drivers/media/tuners/tuner_it913x_priv.h | 88 ------ drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 8 files changed, 598 insertions(+), 598 deletions(-) create mode 100644 drivers/media/tuners/it913x.c create mode 100644 drivers/media/tuners/it913x.h create mode 100644 drivers/media/tuners/it913x_priv.h delete mode 100644 drivers/media/tuners/tuner_it913x.c delete mode 100644 drivers/media/tuners/tuner_it913x.h delete mode 100644 drivers/media/tuners/tuner_it913x_priv.h diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 5591699755ba..7eede5cd9906 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.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) += tuner_it913x.o +obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o ccflags-y += -I$(srctree)/drivers/media/dvb-core diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c new file mode 100644 index 000000000000..4627925ed117 --- /dev/null +++ b/drivers/media/tuners/it913x.c @@ -0,0 +1,463 @@ +/* + * 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: + /* FIXME: these are just avoid divide by 0 */ + state->tun_xtal = 2000; + state->tun_fdiv = 3; + 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, 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; + + if (state->chip_ver == 0x01) + return it913x_script_loader(state, it9135ax_tuner_off); + else + 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; + int ret; + + /* 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; + + /* tuner RF initial */ + ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); + if (ret < 0) + goto error; + + 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 new file mode 100644 index 000000000000..12dd36bd9e79 --- /dev/null +++ b/drivers/media/tuners/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/it913x_priv.h b/drivers/media/tuners/it913x_priv.h new file mode 100644 index 000000000000..781c98ecf5b6 --- /dev/null +++ b/drivers/media/tuners/it913x_priv.h @@ -0,0 +1,88 @@ +/* + * 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 for IT9135 AX */ +static struct it913xset it9135ax_tuner_off[] = { + {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ + {PRO_DMOD, 0xec02, {0x3f}, 0x01}, + {PRO_DMOD, 0xec03, {0x1f}, 0x01}, + {PRO_DMOD, 0xec04, {0x3f}, 0x01}, + {PRO_DMOD, 0xec05, {0x3f}, 0x01}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +/* Tuner setting scripts (still keeping it9137) */ +static struct it913xset it9137_tuner_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 deleted file mode 100644 index b92d59979437..000000000000 --- a/drivers/media/tuners/tuner_it913x.c +++ /dev/null @@ -1,463 +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 "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: - /* FIXME: these are just avoid divide by 0 */ - state->tun_xtal = 2000; - state->tun_fdiv = 3; - 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, 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; - - if (state->chip_ver == 0x01) - return it913x_script_loader(state, it9135ax_tuner_off); - else - 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; - int ret; - - /* 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; - - /* tuner RF initial */ - ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); - if (ret < 0) - goto error; - - 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 deleted file mode 100644 index 12dd36bd9e79..000000000000 --- a/drivers/media/tuners/tuner_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/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h deleted file mode 100644 index cc6f4b1e45aa..000000000000 --- a/drivers/media/tuners/tuner_it913x_priv.h +++ /dev/null @@ -1,88 +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 "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 for IT9135 AX */ -static struct it913xset it9135ax_tuner_off[] = { - {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ - {PRO_DMOD, 0xec02, {0x3f}, 0x01}, - {PRO_DMOD, 0xec03, {0x1f}, 0x01}, - {PRO_DMOD, 0xec04, {0x3f}, 0x01}, - {PRO_DMOD, 0xec05, {0x3f}, 0x01}, - {PRO_DMOD, 0xec3f, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -/* Tuner setting scripts (still keeping it9137) */ -static struct it913xset it9137_tuner_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 c21902fdd4c4..70ec9c9aeb54 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 "tuner_it913x.h" +#include "it913x.h" struct reg_val { u32 reg; -- cgit v1.2.3 From 3b2a5e8c080da37be6135f44d236fe6b796666d9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Aug 2014 17:14:16 -0300 Subject: [media] it913x: convert to I2C driver Change the it913x driver to use the I2C high lever tuner binding model. As af9035 depends on it, add a code there to do the binding. [mchehab@osg.samsung.com: Merge 3 patches into one, because we don't want to break bisect due to the conversion] Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 133 +++++++++++++++++++--------------- drivers/media/tuners/it913x.h | 33 +++++---- drivers/media/tuners/it913x_priv.h | 1 - drivers/media/usb/dvb-usb-v2/af9035.c | 132 ++++++++++++++++++++++++++++++++- drivers/media/usb/dvb-usb-v2/af9035.h | 3 +- 5 files changed, 221 insertions(+), 81 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 4627925ed117..72fefb753af1 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -23,10 +23,9 @@ #include "it913x_priv.h" struct it913x_state { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; + struct i2c_client *client; + struct dvb_frontend *fe; u8 chip_ver; - u8 tuner_type; u8 firmware_ver; u16 tun_xtal; u8 tun_fdiv; @@ -41,9 +40,9 @@ static int it913x_rd_regs(struct it913x_state *state, int ret; u8 b[3]; struct i2c_msg msg[2] = { - { .addr = state->i2c_addr, .flags = 0, + { .addr = state->client->addr, .flags = 0, .buf = b, .len = sizeof(b) }, - { .addr = state->i2c_addr, .flags = I2C_M_RD, + { .addr = state->client->addr, .flags = I2C_M_RD, .buf = data, .len = count } }; @@ -52,7 +51,7 @@ static int it913x_rd_regs(struct it913x_state *state, b[2] = (u8) reg & 0xff; b[0] |= 0x80; /* All reads from demodulator */ - ret = i2c_transfer(state->i2c_adap, msg, 2); + ret = i2c_transfer(state->client->adapter, msg, 2); return ret; } @@ -73,7 +72,7 @@ static int it913x_wr_regs(struct it913x_state *state, { u8 b[256]; struct i2c_msg msg[1] = { - { .addr = state->i2c_addr, .flags = 0, + { .addr = state->client->addr, .flags = 0, .buf = b, .len = 3 + count } }; int ret; @@ -86,7 +85,7 @@ static int it913x_wr_regs(struct it913x_state *state, if (pro == PRO_DMOD) b[0] |= 0x80; - ret = i2c_transfer(state->i2c_adap, msg, 1); + ret = i2c_transfer(state->client->adapter, msg, 1); if (ret < 0) return -EIO; @@ -191,8 +190,7 @@ 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); - dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, - state->tun_fn_min); + dev_dbg(&state->client->dev, "Tuner fn_min %d\n", state->tun_fn_min); if (state->chip_ver > 1) msleep(50); @@ -237,8 +235,8 @@ static int it9137_set_params(struct dvb_frontend *fe) else set_tuner = set_it9137_template; - dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", - __func__, frequency, bandwidth); + dev_dbg(&state->client->dev, "Tuner Frequency %d Bandwidth %d\n", + frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { l_band = 0; @@ -353,15 +351,13 @@ 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; - dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", - __func__, temp_f); + dev_dbg(&state->client->dev, "High Frequency = %04x\n", 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); + dev_dbg(&state->client->dev, "low Frequency = %04x\n", freq); ret = it913x_script_loader(state, set_tuner); @@ -382,12 +378,6 @@ static int it913x_sleep(struct dvb_frontend *fe) 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", @@ -395,68 +385,91 @@ static const struct dvb_tuner_ops it913x_tuner_ops = { .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) +static int it913x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct it913x_state *state = NULL; + struct it913x_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct it913x_state *state; int ret; + char *chip_ver_str; - /* 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; + if (state == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; } - state->tuner_type = config; + state->client = client; + state->fe = cfg->fe; + state->chip_ver = cfg->chip_ver; state->firmware_ver = 1; /* tuner RF initial */ ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); if (ret < 0) - goto error; + goto err; fe->tuner_priv = state; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, state); + + if (state->chip_ver == 1) + chip_ver_str = "AX"; + else if (state->chip_ver == 2) + chip_ver_str = "BX"; + else + chip_ver_str = "??"; + + dev_info(&state->client->dev, "ITE IT913X %s successfully attached\n", + chip_ver_str); + dev_dbg(&state->client->dev, "chip_ver=%02x\n", state->chip_ver); + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + kfree(state); - 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 ret; +} - return fe; -error: +static int it913x_remove(struct i2c_client *client) +{ + struct it913x_state *state = i2c_get_clientdata(client); + struct dvb_frontend *fe = state->fe; + + dev_dbg(&client->dev, "\n"); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; kfree(state); - return NULL; + + return 0; } -EXPORT_SYMBOL(it913x_attach); + +static const struct i2c_device_id it913x_id_table[] = { + {"it913x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, it913x_id_table); + +static struct i2c_driver it913x_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "it913x", + }, + .probe = it913x_probe, + .remove = it913x_remove, + .id_table = it913x_id_table, +}; + +module_i2c_driver(it913x_driver); MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h index 12dd36bd9e79..9789c4d2a6ea 100644 --- a/drivers/media/tuners/it913x.h +++ b/drivers/media/tuners/it913x.h @@ -25,21 +25,22 @@ #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 +/* + * I2C address + * 0x38, 0x3a, 0x3c, 0x3e + */ +struct it913x_config { + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; + + /* + * chip version + * 1 = IT9135 AX + * 2 = IT9135 BX + */ + u8 chip_ver:2; +}; #endif diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 781c98ecf5b6..d624efde80aa 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -24,7 +24,6 @@ #define IT913X_PRIV_H #include "it913x.h" -#include "af9033.h" #define PRO_LINK 0x0 #define PRO_DMOD 0x1 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f37cf7da8c1d..1a5b600dc349 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -193,6 +193,93 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, return af9035_wr_regs(d, reg, &val, 1); } +static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr, + void *platform_data) +{ + int ret, num; + struct state *state = d_to_priv(d); + struct i2c_client *client; + struct i2c_adapter *adapter = &d->i2c_adap; + struct i2c_board_info board_info = { + .addr = addr, + .platform_data = platform_data, + }; + + strlcpy(board_info.type, type, I2C_NAME_SIZE); + + /* find first free client */ + for (num = 0; num < AF9035_I2C_CLIENT_MAX; num++) { + if (state->i2c_client[num] == NULL) + break; + } + + dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); + + if (num == AF9035_I2C_CLIENT_MAX) { + dev_err(&d->udev->dev, "%s: I2C client out of index\n", + KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + request_module(board_info.type); + + /* register I2C device */ + client = i2c_new_device(adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) { + ret = -ENODEV; + goto err; + } + + /* increase I2C driver usage count */ + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + ret = -ENODEV; + goto err; + } + + state->i2c_client[num] = client; + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static void af9035_del_i2c_dev(struct dvb_usb_device *d) +{ + int num; + struct state *state = d_to_priv(d); + struct i2c_client *client; + + /* find last used client */ + num = AF9035_I2C_CLIENT_MAX; + while (num--) { + if (state->i2c_client[num] != NULL) + break; + } + + dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); + + if (num == -1) { + dev_err(&d->udev->dev, "%s: I2C client out of index\n", + KBUILD_MODNAME); + goto err; + } + + client = state->i2c_client[num]; + + /* decrease I2C driver usage count */ + module_put(client->dev.driver->owner); + + /* unregister I2C device */ + i2c_unregister_device(client); + + state->i2c_client[num] = NULL; + return; +err: + dev_dbg(&d->udev->dev, "%s: failed\n", __func__); +} + static int af9035_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -1231,14 +1318,39 @@ 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: + { + struct it913x_config it913x_config = { + .fe = adap->fe[0], + .chip_ver = 1, + }; + + ret = af9035_add_i2c_dev(d, "it913x", + state->af9033_config[adap->id].i2c_addr, + &it913x_config); + if (ret) + goto err; + + fe = adap->fe[0]; + break; + } case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - /* attach tuner */ - fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap, + { + struct it913x_config it913x_config = { + .fe = adap->fe[0], + .chip_ver = 2, + }; + + ret = af9035_add_i2c_dev(d, "it913x", state->af9033_config[adap->id].i2c_addr, - state->af9033_config[0].tuner); + &it913x_config); + if (ret) + goto err; + + fe = adap->fe[0]; break; + } default: fe = NULL; } @@ -1303,6 +1415,19 @@ err: return ret; } +static void af9035_exit(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + if (state->i2c_client[1]) + af9035_del_i2c_dev(d); + + if (state->i2c_client[0]) + af9035_del_i2c_dev(d); +} + #if IS_ENABLED(CONFIG_RC_CORE) static int af9035_rc_query(struct dvb_usb_device *d) { @@ -1479,6 +1604,7 @@ static const struct dvb_usb_device_properties af9035_props = { .init = af9035_init, .get_rc_config = af9035_get_rc_config, .get_stream_config = af9035_get_stream_config, + .exit = af9035_exit, .get_adapter_count = af9035_get_adapter_count, .adapter = { diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 70ec9c9aeb54..0911c4fc860c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -62,8 +62,9 @@ struct state { u8 dual_mode:1; u16 eeprom_addr; struct af9033_config af9033_config[2]; - struct af9033_ops ops; + #define AF9035_I2C_CLIENT_MAX 2 + struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX]; }; static const u32 clock_lut_af9035[] = { -- cgit v1.2.3 From 8da55c94dd85474a9925bd07a73959ae77a5aa6d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Aug 2014 18:56:46 -0300 Subject: [media] it913x: change reg read/write routines more common Change register write and read routines to similar which are typically used. We have to add processor core as a part of register address in order to simplify register access. Chip has two cores, called link and ofdm. As for now, use address bit 24 to address used core. Bits 15:0 are register address in given core. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 58 +++++++++++++++----------------- drivers/media/tuners/it913x_priv.h | 69 ++++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 67 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 72fefb753af1..7664878c9454 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -49,7 +49,6 @@ static int it913x_rd_regs(struct it913x_state *state, 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->client->adapter, msg, 2); @@ -57,18 +56,21 @@ static int it913x_rd_regs(struct it913x_state *state, } /* read single register */ -static int it913x_rd_reg(struct it913x_state *state, u32 reg) +static int it913x_rd_reg(struct it913x_state *state, u32 reg, u8 *val) { int ret; u8 b[1]; ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); - return (ret < 0) ? -ENODEV : b[0]; + if (ret < 0) + return -ENODEV; + *val = b[0]; + return 0; } /* write multiple registers */ static int it913x_wr_regs(struct it913x_state *state, - u8 pro, u32 reg, u8 buf[], u8 count) + u32 reg, u8 buf[], u8 count) { u8 b[256]; struct i2c_msg msg[1] = { @@ -82,9 +84,6 @@ static int it913x_wr_regs(struct it913x_state *state, b[2] = (u8) reg & 0xff; memcpy(&b[3], buf, count); - if (pro == PRO_DMOD) - b[0] |= 0x80; - ret = i2c_transfer(state->client->adapter, msg, 1); if (ret < 0) @@ -95,7 +94,7 @@ static int it913x_wr_regs(struct it913x_state *state, /* write single register */ static int it913x_wr_reg(struct it913x_state *state, - u8 pro, u32 reg, u32 data) + u32 reg, u32 data) { int ret; u8 b[4]; @@ -115,7 +114,7 @@ static int it913x_wr_reg(struct it913x_state *state, else s = 0; - ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); + ret = it913x_wr_regs(state, reg, &b[s], sizeof(b) - s); return ret; } @@ -129,9 +128,9 @@ static int it913x_script_loader(struct it913x_state *state, return -EINVAL; for (i = 0; i < 1000; ++i) { - if (loadscript[i].pro == 0xff) + if (loadscript[i].address == 0x000000) break; - ret = it913x_wr_regs(state, loadscript[i].pro, + ret = it913x_wr_regs(state, loadscript[i].address, loadscript[i].reg, loadscript[i].count); if (ret < 0) @@ -143,12 +142,13 @@ static int it913x_script_loader(struct it913x_state *state, static int it913x_init(struct dvb_frontend *fe) { struct it913x_state *state = fe->tuner_priv; - int ret, i, reg; + int ret, i; + u8 reg = 0; u8 val, nv_val; u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - reg = it913x_rd_reg(state, 0xec86); + ret = it913x_rd_reg(state, 0x80ec86, ®); switch (reg) { case 0: state->tun_clk_mode = reg; @@ -156,13 +156,8 @@ static int it913x_init(struct dvb_frontend *fe) state->tun_fdiv = 3; val = 16; break; - case -ENODEV: - /* FIXME: these are just avoid divide by 0 */ - state->tun_xtal = 2000; - state->tun_fdiv = 3; - return -ENODEV; case 1: - default: + default: /* I/O error too */ state->tun_clk_mode = reg; state->tun_xtal = 640; state->tun_fdiv = 1; @@ -170,7 +165,7 @@ static int it913x_init(struct dvb_frontend *fe) break; } - reg = it913x_rd_reg(state, 0xed03); + ret = it913x_rd_reg(state, 0x80ed03, ®); if (reg < 0) return -ENODEV; @@ -180,7 +175,7 @@ static int it913x_init(struct dvb_frontend *fe) nv_val = 2; for (i = 0; i < 50; i++) { - ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); + ret = it913x_rd_regs(state, 0x80ed23, &b[0], sizeof(b)); reg = (b[1] << 8) + b[0]; if (reg > 0) break; @@ -196,21 +191,21 @@ static int it913x_init(struct dvb_frontend *fe) msleep(50); else { for (i = 0; i < 50; i++) { - reg = it913x_rd_reg(state, 0xec82); + ret = it913x_rd_reg(state, 0x80ec82, ®); + if (ret < 0) + return -ENODEV; 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, 0xec57, 0x0); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); + ret = it913x_wr_reg(state, 0x80ec40, 0x1); + ret |= it913x_wr_reg(state, 0x80ec57, 0x0); + ret |= it913x_wr_reg(state, 0x80ec58, 0x0); - return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); + return it913x_wr_reg(state, 0x80ed81, val); } static int it9137_set_params(struct dvb_frontend *fe) @@ -220,7 +215,8 @@ static int it9137_set_params(struct dvb_frontend *fe) struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 bandwidth = p->bandwidth_hz; u32 frequency_m = p->frequency; - int ret, reg; + int ret; + u8 reg = 0; u32 frequency = frequency_m / 1000; u32 freq, temp_f, tmp; u16 iqik_m_cal; @@ -321,7 +317,7 @@ static int it9137_set_params(struct dvb_frontend *fe) } else return -EINVAL; - reg = it913x_rd_reg(state, 0xed81); + ret = it913x_rd_reg(state, 0x80ed81, ®); iqik_m_cal = (u16)reg * n_div; if (reg < 0x20) { @@ -412,7 +408,7 @@ static int it913x_probe(struct i2c_client *client, state->firmware_ver = 1; /* tuner RF initial */ - ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68); + ret = it913x_wr_reg(state, 0x80ec4c, 0x68); if (ret < 0) goto err; diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index d624efde80aa..32af24c69cbb 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -25,63 +25,60 @@ #include "it913x.h" -#define PRO_LINK 0x0 -#define PRO_DMOD 0x1 #define TRIGGER_OFSM 0x0000 -struct it913xset { u32 pro; - u32 address; +struct it913xset { u32 address; u8 reg[15]; u8 count; }; /* Tuner setting scripts for IT9135 AX */ static struct it913xset it9135ax_tuner_off[] = { - {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ - {PRO_DMOD, 0xec02, {0x3f}, 0x01}, - {PRO_DMOD, 0xec03, {0x1f}, 0x01}, - {PRO_DMOD, 0xec04, {0x3f}, 0x01}, - {PRO_DMOD, 0xec05, {0x3f}, 0x01}, - {PRO_DMOD, 0xec3f, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ + {0x80ec40, {0x00}, 0x01}, /* Power Down Tuner */ + {0x80ec02, {0x3f}, 0x01}, + {0x80ec03, {0x1f}, 0x01}, + {0x80ec04, {0x3f}, 0x01}, + {0x80ec05, {0x3f}, 0x01}, + {0x80ec3f, {0x01}, 0x01}, + {0x000000, {0x00}, 0x00}, /* Terminating Entry */ }; /* Tuner setting scripts (still keeping it9137) */ static struct it913xset it9137_tuner_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, + {0x80ec40, {0x00}, 0x01}, /* Power Down Tuner */ + {0x80ec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {0x80ec06, {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, + {0x80ec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, + {0x80ec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x09}, - {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + {0x80ec22, {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 */ + {0x80ec20, {0x00}, 0x01}, + {0x80ec3f, {0x01}, 0x01}, + {0x000000, {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 */ + {0x80ee06, {0x00}, 0x01}, + {0x80ec56, {0x00}, 0x01}, + {0x80ec4c, {0x00}, 0x01}, + {0x80ec4d, {0x00}, 0x01}, + {0x80ec4e, {0x00}, 0x01}, + {0x80011e, {0x00}, 0x01}, /* Older Devices */ + {0x80011f, {0x00}, 0x01}, + {0x000000, {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 */ + {0x80ee06, {0x00}, 0x01}, + {0x80ec56, {0x00}, 0x01}, + {0x80ec4c, {0x00}, 0x01}, + {0x80ec4d, {0x00}, 0x01}, + {0x80ec4e, {0x00}, 0x01}, + {0x80ec4f, {0x00}, 0x01}, + {0x80ec50, {0x00}, 0x01}, + {0x000000, {0x00}, 0x00}, /* Terminating Entry */ }; #endif -- cgit v1.2.3 From a71b65e8c545f5a72c1c227eae8a6df1d68f3f24 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Aug 2014 20:11:08 -0300 Subject: [media] it913x: rename 'state' to 'dev' foo_dev seems to be most correct term for the structure holding data of each device instance. It is most used term in Kernel and also examples from book Linux Device Drivers, Third Edition, uses it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 150 +++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 7664878c9454..cc959c111a62 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -22,7 +22,7 @@ #include "it913x_priv.h" -struct it913x_state { +struct it913x_dev { struct i2c_client *client; struct dvb_frontend *fe; u8 chip_ver; @@ -34,15 +34,15 @@ struct it913x_state { }; /* read multiple registers */ -static int it913x_rd_regs(struct it913x_state *state, +static int it913x_rd_regs(struct it913x_dev *dev, u32 reg, u8 *data, u8 count) { int ret; u8 b[3]; struct i2c_msg msg[2] = { - { .addr = state->client->addr, .flags = 0, + { .addr = dev->client->addr, .flags = 0, .buf = b, .len = sizeof(b) }, - { .addr = state->client->addr, .flags = I2C_M_RD, + { .addr = dev->client->addr, .flags = I2C_M_RD, .buf = data, .len = count } }; @@ -50,18 +50,18 @@ static int it913x_rd_regs(struct it913x_state *state, b[1] = (u8)(reg >> 8) & 0xff; b[2] = (u8) reg & 0xff; - ret = i2c_transfer(state->client->adapter, msg, 2); + ret = i2c_transfer(dev->client->adapter, msg, 2); return ret; } /* read single register */ -static int it913x_rd_reg(struct it913x_state *state, u32 reg, u8 *val) +static int it913x_rd_reg(struct it913x_dev *dev, u32 reg, u8 *val) { int ret; u8 b[1]; - ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); + ret = it913x_rd_regs(dev, reg, &b[0], sizeof(b)); if (ret < 0) return -ENODEV; *val = b[0]; @@ -69,12 +69,12 @@ static int it913x_rd_reg(struct it913x_state *state, u32 reg, u8 *val) } /* write multiple registers */ -static int it913x_wr_regs(struct it913x_state *state, +static int it913x_wr_regs(struct it913x_dev *dev, u32 reg, u8 buf[], u8 count) { u8 b[256]; struct i2c_msg msg[1] = { - { .addr = state->client->addr, .flags = 0, + { .addr = dev->client->addr, .flags = 0, .buf = b, .len = 3 + count } }; int ret; @@ -84,7 +84,7 @@ static int it913x_wr_regs(struct it913x_state *state, b[2] = (u8) reg & 0xff; memcpy(&b[3], buf, count); - ret = i2c_transfer(state->client->adapter, msg, 1); + ret = i2c_transfer(dev->client->adapter, msg, 1); if (ret < 0) return -EIO; @@ -93,12 +93,12 @@ static int it913x_wr_regs(struct it913x_state *state, } /* write single register */ -static int it913x_wr_reg(struct it913x_state *state, +static int it913x_wr_reg(struct it913x_dev *dev, u32 reg, u32 data) { int ret; u8 b[4]; - u8 s; + u8 len; b[0] = data >> 24; b[1] = (data >> 16) & 0xff; @@ -106,20 +106,20 @@ static int it913x_wr_reg(struct it913x_state *state, b[3] = data & 0xff; /* expand write as needed */ if (data < 0x100) - s = 3; + len = 3; else if (data < 0x1000) - s = 2; + len = 2; else if (data < 0x100000) - s = 1; + len = 1; else - s = 0; + len = 0; - ret = it913x_wr_regs(state, reg, &b[s], sizeof(b) - s); + ret = it913x_wr_regs(dev, reg, &b[len], sizeof(b) - len); return ret; } -static int it913x_script_loader(struct it913x_state *state, +static int it913x_script_loader(struct it913x_dev *dev, struct it913xset *loadscript) { int ret, i; @@ -130,7 +130,7 @@ static int it913x_script_loader(struct it913x_state *state, for (i = 0; i < 1000; ++i) { if (loadscript[i].address == 0x000000) break; - ret = it913x_wr_regs(state, + ret = it913x_wr_regs(dev, loadscript[i].address, loadscript[i].reg, loadscript[i].count); if (ret < 0) @@ -141,31 +141,31 @@ static int it913x_script_loader(struct it913x_state *state, static int it913x_init(struct dvb_frontend *fe) { - struct it913x_state *state = fe->tuner_priv; + struct it913x_dev *dev = fe->tuner_priv; int ret, i; u8 reg = 0; u8 val, nv_val; u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - ret = it913x_rd_reg(state, 0x80ec86, ®); + ret = it913x_rd_reg(dev, 0x80ec86, ®); switch (reg) { case 0: - state->tun_clk_mode = reg; - state->tun_xtal = 2000; - state->tun_fdiv = 3; + dev->tun_clk_mode = reg; + dev->tun_xtal = 2000; + dev->tun_fdiv = 3; val = 16; break; case 1: default: /* I/O error too */ - state->tun_clk_mode = reg; - state->tun_xtal = 640; - state->tun_fdiv = 1; + dev->tun_clk_mode = reg; + dev->tun_xtal = 640; + dev->tun_fdiv = 1; val = 6; break; } - ret = it913x_rd_reg(state, 0x80ed03, ®); + ret = it913x_rd_reg(dev, 0x80ed03, ®); if (reg < 0) return -ENODEV; @@ -175,7 +175,7 @@ static int it913x_init(struct dvb_frontend *fe) nv_val = 2; for (i = 0; i < 50; i++) { - ret = it913x_rd_regs(state, 0x80ed23, &b[0], sizeof(b)); + ret = it913x_rd_regs(dev, 0x80ed23, &b[0], sizeof(b)); reg = (b[1] << 8) + b[0]; if (reg > 0) break; @@ -183,15 +183,15 @@ static int it913x_init(struct dvb_frontend *fe) return -ENODEV; udelay(2000); } - state->tun_fn_min = state->tun_xtal * reg; - state->tun_fn_min /= (state->tun_fdiv * nv_val); - dev_dbg(&state->client->dev, "Tuner fn_min %d\n", state->tun_fn_min); + dev->tun_fn_min = dev->tun_xtal * reg; + dev->tun_fn_min /= (dev->tun_fdiv * nv_val); + dev_dbg(&dev->client->dev, "Tuner fn_min %d\n", dev->tun_fn_min); - if (state->chip_ver > 1) + if (dev->chip_ver > 1) msleep(50); else { for (i = 0; i < 50; i++) { - ret = it913x_rd_reg(state, 0x80ec82, ®); + ret = it913x_rd_reg(dev, 0x80ec82, ®); if (ret < 0) return -ENODEV; if (reg > 0) @@ -201,16 +201,16 @@ static int it913x_init(struct dvb_frontend *fe) } /* Power Up Tuner - common all versions */ - ret = it913x_wr_reg(state, 0x80ec40, 0x1); - ret |= it913x_wr_reg(state, 0x80ec57, 0x0); - ret |= it913x_wr_reg(state, 0x80ec58, 0x0); + ret = it913x_wr_reg(dev, 0x80ec40, 0x1); + ret |= it913x_wr_reg(dev, 0x80ec57, 0x0); + ret |= it913x_wr_reg(dev, 0x80ec58, 0x0); - return it913x_wr_reg(state, 0x80ed81, val); + return it913x_wr_reg(dev, 0x80ed81, val); } static int it9137_set_params(struct dvb_frontend *fe) { - struct it913x_state *state = fe->tuner_priv; + struct it913x_dev *dev = fe->tuner_priv; struct it913xset *set_tuner = set_it9137_template; struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 bandwidth = p->bandwidth_hz; @@ -226,12 +226,12 @@ static int it9137_set_params(struct dvb_frontend *fe) u8 lna_band; u8 bw; - if (state->firmware_ver == 1) + if (dev->firmware_ver == 1) set_tuner = set_it9135_template; else set_tuner = set_it9137_template; - dev_dbg(&state->client->dev, "Tuner Frequency %d Bandwidth %d\n", + dev_dbg(&dev->client->dev, "Tuner Frequency %d Bandwidth %d\n", frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { @@ -305,10 +305,10 @@ static int it9137_set_params(struct dvb_frontend *fe) } else if (frequency > 296000 && frequency <= 445000) { n_div = 8; n = 5; - } else if (frequency > 445000 && frequency <= state->tun_fn_min) { + } else if (frequency > 445000 && frequency <= dev->tun_fn_min) { n_div = 6; n = 6; - } else if (frequency > state->tun_fn_min && frequency <= 950000) { + } else if (frequency > dev->tun_fn_min && frequency <= 950000) { n_div = 4; n = 7; } else if (frequency > 1450000 && frequency <= 1680000) { @@ -317,27 +317,27 @@ static int it9137_set_params(struct dvb_frontend *fe) } else return -EINVAL; - ret = it913x_rd_reg(state, 0x80ed81, ®); + ret = it913x_rd_reg(dev, 0x80ed81, ®); iqik_m_cal = (u16)reg * n_div; if (reg < 0x20) { - if (state->tun_clk_mode == 0) + if (dev->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) + if (dev->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; + temp_f = frequency * (u32)n_div * (u32)dev->tun_fdiv; + freq = temp_f / dev->tun_xtal; + tmp = freq * dev->tun_xtal; - if ((temp_f - tmp) >= (state->tun_xtal >> 1)) + if ((temp_f - tmp) >= (dev->tun_xtal >> 1)) freq++; freq += (u32) n << 13; @@ -347,15 +347,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; - dev_dbg(&state->client->dev, "High Frequency = %04x\n", temp_f); + dev_dbg(&dev->client->dev, "High Frequency = %04x\n", temp_f); /* Lower frequency */ set_tuner[5].reg[0] = freq & 0xff; set_tuner[6].reg[0] = (freq >> 8) & 0xff; - dev_dbg(&state->client->dev, "low Frequency = %04x\n", freq); + dev_dbg(&dev->client->dev, "low Frequency = %04x\n", freq); - ret = it913x_script_loader(state, set_tuner); + ret = it913x_script_loader(dev, set_tuner); return (ret < 0) ? -ENODEV : 0; } @@ -366,12 +366,12 @@ static int it9137_set_params(struct dvb_frontend *fe) static int it913x_sleep(struct dvb_frontend *fe) { - struct it913x_state *state = fe->tuner_priv; + struct it913x_dev *dev = fe->tuner_priv; - if (state->chip_ver == 0x01) - return it913x_script_loader(state, it9135ax_tuner_off); + if (dev->chip_ver == 0x01) + return it913x_script_loader(dev, it9135ax_tuner_off); else - return it913x_script_loader(state, it9137_tuner_off); + return it913x_script_loader(dev, it9137_tuner_off); } static const struct dvb_tuner_ops it913x_tuner_ops = { @@ -391,60 +391,60 @@ static int it913x_probe(struct i2c_client *client, { struct it913x_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct it913x_state *state; + struct it913x_dev *dev; int ret; char *chip_ver_str; - state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); - if (state == NULL) { + dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL); + if (dev == NULL) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - state->client = client; - state->fe = cfg->fe; - state->chip_ver = cfg->chip_ver; - state->firmware_ver = 1; + dev->client = client; + dev->fe = cfg->fe; + dev->chip_ver = cfg->chip_ver; + dev->firmware_ver = 1; /* tuner RF initial */ - ret = it913x_wr_reg(state, 0x80ec4c, 0x68); + ret = it913x_wr_reg(dev, 0x80ec4c, 0x68); if (ret < 0) goto err; - fe->tuner_priv = state; + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); - i2c_set_clientdata(client, state); + i2c_set_clientdata(client, dev); - if (state->chip_ver == 1) + if (dev->chip_ver == 1) chip_ver_str = "AX"; - else if (state->chip_ver == 2) + else if (dev->chip_ver == 2) chip_ver_str = "BX"; else chip_ver_str = "??"; - dev_info(&state->client->dev, "ITE IT913X %s successfully attached\n", + dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n", chip_ver_str); - dev_dbg(&state->client->dev, "chip_ver=%02x\n", state->chip_ver); + dev_dbg(&dev->client->dev, "chip_ver=%02x\n", dev->chip_ver); return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); - kfree(state); + kfree(dev); return ret; } static int it913x_remove(struct i2c_client *client) { - struct it913x_state *state = i2c_get_clientdata(client); - struct dvb_frontend *fe = state->fe; + struct it913x_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->fe; dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(state); + kfree(dev); return 0; } -- cgit v1.2.3 From d2dbc00cea35081b9f998a0985d151f60ce37835 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Aug 2014 21:45:33 -0300 Subject: [media] it913x: convert to RegMap API Use RegMap API to cover I2C register access routines. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 1 + drivers/media/tuners/it913x.c | 137 +++++++++---------------------------- drivers/media/tuners/it913x_priv.h | 1 + 3 files changed, 34 insertions(+), 105 deletions(-) diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 83199964b54e..48bff2e23d93 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -248,6 +248,7 @@ config MEDIA_TUNER_SI2157 config MEDIA_TUNER_IT913X tristate "ITE Tech IT913x silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help ITE Tech IT913x silicon tuner driver. diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index cc959c111a62..f3e212c127c8 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -24,6 +24,7 @@ struct it913x_dev { struct i2c_client *client; + struct regmap *regmap; struct dvb_frontend *fe; u8 chip_ver; u8 firmware_ver; @@ -33,92 +34,6 @@ struct it913x_dev { u32 tun_fn_min; }; -/* read multiple registers */ -static int it913x_rd_regs(struct it913x_dev *dev, - u32 reg, u8 *data, u8 count) -{ - int ret; - u8 b[3]; - struct i2c_msg msg[2] = { - { .addr = dev->client->addr, .flags = 0, - .buf = b, .len = sizeof(b) }, - { .addr = dev->client->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; - - ret = i2c_transfer(dev->client->adapter, msg, 2); - - return ret; -} - -/* read single register */ -static int it913x_rd_reg(struct it913x_dev *dev, u32 reg, u8 *val) -{ - int ret; - u8 b[1]; - - ret = it913x_rd_regs(dev, reg, &b[0], sizeof(b)); - if (ret < 0) - return -ENODEV; - *val = b[0]; - return 0; -} - -/* write multiple registers */ -static int it913x_wr_regs(struct it913x_dev *dev, - u32 reg, u8 buf[], u8 count) -{ - u8 b[256]; - struct i2c_msg msg[1] = { - { .addr = dev->client->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); - - ret = i2c_transfer(dev->client->adapter, msg, 1); - - if (ret < 0) - return -EIO; - - return 0; -} - -/* write single register */ -static int it913x_wr_reg(struct it913x_dev *dev, - u32 reg, u32 data) -{ - int ret; - u8 b[4]; - u8 len; - - 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) - len = 3; - else if (data < 0x1000) - len = 2; - else if (data < 0x100000) - len = 1; - else - len = 0; - - ret = it913x_wr_regs(dev, reg, &b[len], sizeof(b) - len); - - return ret; -} - static int it913x_script_loader(struct it913x_dev *dev, struct it913xset *loadscript) { @@ -130,8 +45,7 @@ static int it913x_script_loader(struct it913x_dev *dev, for (i = 0; i < 1000; ++i) { if (loadscript[i].address == 0x000000) break; - ret = it913x_wr_regs(dev, - loadscript[i].address, + ret = regmap_bulk_write(dev->regmap, loadscript[i].address, loadscript[i].reg, loadscript[i].count); if (ret < 0) return -ENODEV; @@ -143,12 +57,12 @@ static int it913x_init(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; int ret, i; - u8 reg = 0; + unsigned int reg; u8 val, nv_val; u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - ret = it913x_rd_reg(dev, 0x80ec86, ®); + ret = regmap_read(dev->regmap, 0x80ec86, ®); switch (reg) { case 0: dev->tun_clk_mode = reg; @@ -165,7 +79,7 @@ static int it913x_init(struct dvb_frontend *fe) break; } - ret = it913x_rd_reg(dev, 0x80ed03, ®); + ret = regmap_read(dev->regmap, 0x80ed03, ®); if (reg < 0) return -ENODEV; @@ -175,11 +89,11 @@ static int it913x_init(struct dvb_frontend *fe) nv_val = 2; for (i = 0; i < 50; i++) { - ret = it913x_rd_regs(dev, 0x80ed23, &b[0], sizeof(b)); + ret = regmap_bulk_read(dev->regmap, 0x80ed23, &b[0], sizeof(b)); reg = (b[1] << 8) + b[0]; if (reg > 0) break; - if (ret < 0) + if (ret) return -ENODEV; udelay(2000); } @@ -191,7 +105,7 @@ static int it913x_init(struct dvb_frontend *fe) msleep(50); else { for (i = 0; i < 50; i++) { - ret = it913x_rd_reg(dev, 0x80ec82, ®); + ret = regmap_read(dev->regmap, 0x80ec82, ®); if (ret < 0) return -ENODEV; if (reg > 0) @@ -201,11 +115,11 @@ static int it913x_init(struct dvb_frontend *fe) } /* Power Up Tuner - common all versions */ - ret = it913x_wr_reg(dev, 0x80ec40, 0x1); - ret |= it913x_wr_reg(dev, 0x80ec57, 0x0); - ret |= it913x_wr_reg(dev, 0x80ec58, 0x0); + ret = regmap_write(dev->regmap, 0x80ec40, 0x1); + ret |= regmap_write(dev->regmap, 0x80ec57, 0x0); + ret |= regmap_write(dev->regmap, 0x80ec58, 0x0); - return it913x_wr_reg(dev, 0x80ed81, val); + return regmap_write(dev->regmap, 0x80ed81, val); } static int it9137_set_params(struct dvb_frontend *fe) @@ -216,7 +130,7 @@ static int it9137_set_params(struct dvb_frontend *fe) u32 bandwidth = p->bandwidth_hz; u32 frequency_m = p->frequency; int ret; - u8 reg = 0; + unsigned int reg; u32 frequency = frequency_m / 1000; u32 freq, temp_f, tmp; u16 iqik_m_cal; @@ -317,7 +231,7 @@ static int it9137_set_params(struct dvb_frontend *fe) } else return -EINVAL; - ret = it913x_rd_reg(dev, 0x80ed81, ®); + ret = regmap_read(dev->regmap, 0x80ed81, ®); iqik_m_cal = (u16)reg * n_div; if (reg < 0x20) { @@ -394,6 +308,10 @@ static int it913x_probe(struct i2c_client *client, struct it913x_dev *dev; int ret; char *chip_ver_str; + static const struct regmap_config regmap_config = { + .reg_bits = 24, + .val_bits = 8, + }; dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL); if (dev == NULL) { @@ -406,11 +324,16 @@ static int it913x_probe(struct i2c_client *client, dev->fe = cfg->fe; dev->chip_ver = cfg->chip_ver; dev->firmware_ver = 1; + dev->regmap = regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } /* tuner RF initial */ - ret = it913x_wr_reg(dev, 0x80ec4c, 0x68); - if (ret < 0) - goto err; + ret = regmap_write(dev->regmap, 0x80ec4c, 0x68); + if (ret) + goto err_regmap_exit; fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, @@ -428,10 +351,13 @@ static int it913x_probe(struct i2c_client *client, chip_ver_str); dev_dbg(&dev->client->dev, "chip_ver=%02x\n", dev->chip_ver); return 0; + +err_regmap_exit: + regmap_exit(dev->regmap); +err_kfree: + kfree(dev); err: dev_dbg(&client->dev, "failed %d\n", ret); - kfree(dev); - return ret; } @@ -444,6 +370,7 @@ static int it913x_remove(struct i2c_client *client) memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; + regmap_exit(dev->regmap); kfree(dev); return 0; diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 32af24c69cbb..3ed2d3c0fe55 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -24,6 +24,7 @@ #define IT913X_PRIV_H #include "it913x.h" +#include #define TRIGGER_OFSM 0x0000 -- cgit v1.2.3 From 676c350f97366f648dbe7f7f8202a695d946f764 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 27 Aug 2014 03:59:27 -0300 Subject: [media] it913x: re-implement sleep Re-implement sleep. Based USB sniffs taken from the latest Hauppauge windows driver version 07/10/2014, 14.6.23.32191. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 76 +++++++++++++++++++++++++++-------- drivers/media/tuners/it913x.h | 10 ++++- drivers/media/tuners/it913x_priv.h | 27 ------------- drivers/media/usb/dvb-usb-v2/af9035.c | 14 +++++++ 4 files changed, 83 insertions(+), 44 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index f3e212c127c8..11d391a5d5c6 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -26,7 +26,8 @@ struct it913x_dev { struct i2c_client *client; struct regmap *regmap; struct dvb_frontend *fe; - u8 chip_ver; + u8 chip_ver:2; + u8 role:2; u8 firmware_ver; u16 tun_xtal; u8 tun_fdiv; @@ -122,6 +123,62 @@ static int it913x_init(struct dvb_frontend *fe) return regmap_write(dev->regmap, 0x80ed81, val); } +static int it913x_sleep(struct dvb_frontend *fe) +{ + struct it913x_dev *dev = fe->tuner_priv; + int ret, len; + + dev_dbg(&dev->client->dev, "role=%u\n", dev->role); + + ret = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1); + if (ret) + goto err; + + /* + * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner + * communication lost. Due to that, we cannot put master full sleep. + */ + if (dev->role == IT913X_ROLE_DUAL_MASTER) + len = 4; + else + len = 15; + + dev_dbg(&dev->client->dev, "role=%u len=%d\n", dev->role, len); + + ret = regmap_bulk_write(dev->regmap, 0x80ec02, + "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + len); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec17, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec22, + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1); + if (ret) + goto err; + + ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; +} + static int it9137_set_params(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; @@ -274,20 +331,6 @@ static int it9137_set_params(struct dvb_frontend *fe) 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_dev *dev = fe->tuner_priv; - - if (dev->chip_ver == 0x01) - return it913x_script_loader(dev, it9135ax_tuner_off); - else - return it913x_script_loader(dev, it9137_tuner_off); -} - static const struct dvb_tuner_ops it913x_tuner_ops = { .info = { .name = "ITE Tech IT913X", @@ -323,6 +366,7 @@ static int it913x_probe(struct i2c_client *client, dev->client = client; dev->fe = cfg->fe; dev->chip_ver = cfg->chip_ver; + dev->role = cfg->role; dev->firmware_ver = 1; dev->regmap = regmap_init_i2c(client, ®map_config); if (IS_ERR(dev->regmap)) { @@ -349,7 +393,7 @@ static int it913x_probe(struct i2c_client *client, dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n", chip_ver_str); - dev_dbg(&dev->client->dev, "chip_ver=%02x\n", dev->chip_ver); + dev_dbg(&dev->client->dev, "chip_ver=%u role=%u\n", dev->chip_ver, dev->role); return 0; err_regmap_exit: diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h index 9789c4d2a6ea..33de53d4a566 100644 --- a/drivers/media/tuners/it913x.h +++ b/drivers/media/tuners/it913x.h @@ -40,7 +40,15 @@ struct it913x_config { * 1 = IT9135 AX * 2 = IT9135 BX */ - u8 chip_ver:2; + unsigned int chip_ver:2; + + /* + * tuner role + */ +#define IT913X_ROLE_SINGLE 0 +#define IT913X_ROLE_DUAL_MASTER 1 +#define IT913X_ROLE_DUAL_SLAVE 2 + unsigned int role:2; }; #endif diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 3ed2d3c0fe55..41f9b2a43e39 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -33,33 +33,6 @@ struct it913xset { u32 address; u8 count; }; -/* Tuner setting scripts for IT9135 AX */ -static struct it913xset it9135ax_tuner_off[] = { - {0x80ec40, {0x00}, 0x01}, /* Power Down Tuner */ - {0x80ec02, {0x3f}, 0x01}, - {0x80ec03, {0x1f}, 0x01}, - {0x80ec04, {0x3f}, 0x01}, - {0x80ec05, {0x3f}, 0x01}, - {0x80ec3f, {0x01}, 0x01}, - {0x000000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -/* Tuner setting scripts (still keeping it9137) */ -static struct it913xset it9137_tuner_off[] = { - {0x80ec40, {0x00}, 0x01}, /* Power Down Tuner */ - {0x80ec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, - {0x80ec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}, 0x0c}, - {0x80ec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, - {0x80ec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}, 0x09}, - {0x80ec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}, 0x0a}, - {0x80ec20, {0x00}, 0x01}, - {0x80ec3f, {0x01}, 0x01}, - {0x000000, {0x00}, 0x00}, /* Terminating Entry */ -}; - static struct it913xset set_it9135_template[] = { {0x80ee06, {0x00}, 0x01}, {0x80ec56, {0x00}, 0x01}, diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1a5b600dc349..533c96e4fbb6 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1324,6 +1324,13 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) .chip_ver = 1, }; + if (state->dual_mode) { + if (adap->id == 0) + it913x_config.role = IT913X_ROLE_DUAL_MASTER; + else + it913x_config.role = IT913X_ROLE_DUAL_SLAVE; + } + ret = af9035_add_i2c_dev(d, "it913x", state->af9033_config[adap->id].i2c_addr, &it913x_config); @@ -1342,6 +1349,13 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) .chip_ver = 2, }; + if (state->dual_mode) { + if (adap->id == 0) + it913x_config.role = IT913X_ROLE_DUAL_MASTER; + else + it913x_config.role = IT913X_ROLE_DUAL_SLAVE; + } + ret = af9035_add_i2c_dev(d, "it913x", state->af9033_config[adap->id].i2c_addr, &it913x_config); -- cgit v1.2.3 From b7413c800fa7566696f1209207a90d014f548dac Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Aug 2014 01:45:52 -0300 Subject: [media] it913x: remove dead code Remove unused tuner set template. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 9 +-------- drivers/media/tuners/it913x_priv.h | 11 ----------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 11d391a5d5c6..ab386bf01daf 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -28,7 +28,6 @@ struct it913x_dev { struct dvb_frontend *fe; u8 chip_ver:2; u8 role:2; - u8 firmware_ver; u16 tun_xtal; u8 tun_fdiv; u8 tun_clk_mode; @@ -182,7 +181,7 @@ err: static int it9137_set_params(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; - struct it913xset *set_tuner = set_it9137_template; + struct it913xset *set_tuner = set_it9135_template; struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 bandwidth = p->bandwidth_hz; u32 frequency_m = p->frequency; @@ -197,11 +196,6 @@ static int it9137_set_params(struct dvb_frontend *fe) u8 lna_band; u8 bw; - if (dev->firmware_ver == 1) - set_tuner = set_it9135_template; - else - set_tuner = set_it9137_template; - dev_dbg(&dev->client->dev, "Tuner Frequency %d Bandwidth %d\n", frequency, bandwidth); @@ -367,7 +361,6 @@ static int it913x_probe(struct i2c_client *client, dev->fe = cfg->fe; dev->chip_ver = cfg->chip_ver; dev->role = cfg->role; - dev->firmware_ver = 1; dev->regmap = regmap_init_i2c(client, ®map_config); if (IS_ERR(dev->regmap)) { ret = PTR_ERR(dev->regmap); diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 41f9b2a43e39..a6ddd02c2179 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -44,15 +44,4 @@ static struct it913xset set_it9135_template[] = { {0x000000, {0x00}, 0x00}, /* Terminating Entry */ }; -static struct it913xset set_it9137_template[] = { - {0x80ee06, {0x00}, 0x01}, - {0x80ec56, {0x00}, 0x01}, - {0x80ec4c, {0x00}, 0x01}, - {0x80ec4d, {0x00}, 0x01}, - {0x80ec4e, {0x00}, 0x01}, - {0x80ec4f, {0x00}, 0x01}, - {0x80ec50, {0x00}, 0x01}, - {0x000000, {0x00}, 0x00}, /* Terminating Entry */ -}; - #endif -- cgit v1.2.3 From 3d2f18d34692a413fcd75f5e83fc1dcb7afac13c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Aug 2014 02:07:08 -0300 Subject: [media] it913x: get rid of script loader and and private header file Used script loader is quite useless and hides register numbers making code hard to understand. Get rid of it and use standard RegMap register write functions directly. it913x_priv.h file leaves empty after that change and is also removed. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 63 +++++++++++++++++++------------------- drivers/media/tuners/it913x_priv.h | 47 ---------------------------- 2 files changed, 31 insertions(+), 79 deletions(-) delete mode 100644 drivers/media/tuners/it913x_priv.h diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index ab386bf01daf..924f18d95ba4 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -20,7 +20,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= */ -#include "it913x_priv.h" +#include "it913x.h" +#include struct it913x_dev { struct i2c_client *client; @@ -34,25 +35,6 @@ struct it913x_dev { u32 tun_fn_min; }; -static int it913x_script_loader(struct it913x_dev *dev, - struct it913xset *loadscript) -{ - int ret, i; - - if (loadscript == NULL) - return -EINVAL; - - for (i = 0; i < 1000; ++i) { - if (loadscript[i].address == 0x000000) - break; - ret = regmap_bulk_write(dev->regmap, 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_dev *dev = fe->tuner_priv; @@ -181,7 +163,6 @@ err: static int it9137_set_params(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; - struct it913xset *set_tuner = set_it9135_template; struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 bandwidth = p->bandwidth_hz; u32 frequency_m = p->frequency; @@ -231,7 +212,10 @@ static int it9137_set_params(struct dvb_frontend *fe) lna_band = 1; } else return -EINVAL; - set_tuner[0].reg[0] = lna_band; + + ret = regmap_write(dev->regmap, 0x80ee06, lna_band); + if (ret) + goto err; switch (bandwidth) { case 5000000: @@ -249,8 +233,13 @@ static int it9137_set_params(struct dvb_frontend *fe) break; } - set_tuner[1].reg[0] = bw; - set_tuner[2].reg[0] = 0xa0 | (l_band << 3); + ret = regmap_write(dev->regmap, 0x80ec56, bw); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3)); + if (ret) + goto err; if (frequency > 53000 && frequency <= 74000) { n_div = 48; @@ -309,20 +298,30 @@ static int it9137_set_params(struct dvb_frontend *fe) /* 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; + ret = regmap_write(dev->regmap, 0x80ec4d, temp_f & 0xff); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec4e, (temp_f >> 8) & 0xff); + if (ret) + goto err; dev_dbg(&dev->client->dev, "High Frequency = %04x\n", temp_f); /* Lower frequency */ - set_tuner[5].reg[0] = freq & 0xff; - set_tuner[6].reg[0] = (freq >> 8) & 0xff; - - dev_dbg(&dev->client->dev, "low Frequency = %04x\n", freq); + ret = regmap_write(dev->regmap, 0x80011e, freq & 0xff); + if (ret) + goto err; - ret = it913x_script_loader(dev, set_tuner); + ret = regmap_write(dev->regmap, 0x80011f, (freq >> 8) & 0xff); + if (ret) + goto err; - return (ret < 0) ? -ENODEV : 0; + dev_dbg(&dev->client->dev, "low Frequency = %04x\n", freq); + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; } static const struct dvb_tuner_ops it913x_tuner_ops = { diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h deleted file mode 100644 index a6ddd02c2179..000000000000 --- a/drivers/media/tuners/it913x_priv.h +++ /dev/null @@ -1,47 +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 - -#define TRIGGER_OFSM 0x0000 - -struct it913xset { u32 address; - u8 reg[15]; - u8 count; -}; - -static struct it913xset set_it9135_template[] = { - {0x80ee06, {0x00}, 0x01}, - {0x80ec56, {0x00}, 0x01}, - {0x80ec4c, {0x00}, 0x01}, - {0x80ec4d, {0x00}, 0x01}, - {0x80ec4e, {0x00}, 0x01}, - {0x80011e, {0x00}, 0x01}, /* Older Devices */ - {0x80011f, {0x00}, 0x01}, - {0x000000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -#endif -- cgit v1.2.3 From 17027b9620e6a2ea1d7f3cd0761803c44c65e2ed Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 30 Aug 2014 23:52:48 -0300 Subject: [media] it913x: refactor code largely Refactor code largely. Try to keep order of register read/write same as windows driver does as it makes comparing sniffs easier. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 356 +++++++++++++++++++++++------------------- 1 file changed, 194 insertions(+), 162 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 924f18d95ba4..098e9d542708 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -1,5 +1,5 @@ /* - * ITE Tech IT9137 silicon tuner driver + * ITE IT913X silicon tuner driver * * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) * IT9137 Copyright (C) ITE Tech Inc. @@ -29,79 +29,120 @@ struct it913x_dev { struct dvb_frontend *fe; u8 chip_ver:2; u8 role:2; - u16 tun_xtal; - u8 tun_fdiv; - u8 tun_clk_mode; - u32 tun_fn_min; + u16 xtal; + u8 fdiv; + u8 clk_mode; + u32 fn_min; + bool active; }; static int it913x_init(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; int ret, i; - unsigned int reg; - u8 val, nv_val; - u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; - u8 b[2]; + unsigned int utmp; + u8 iqik_m_cal, nv_val, buf[2]; + static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; - ret = regmap_read(dev->regmap, 0x80ec86, ®); - switch (reg) { + dev_dbg(&dev->client->dev, "role %u\n", dev->role); + + ret = regmap_write(dev->regmap, 0x80ec4c, 0x68); + if (ret) + goto err; + + usleep_range(10000, 100000); + + ret = regmap_read(dev->regmap, 0x80ec86, &utmp); + if (ret) + goto err; + + switch (utmp) { case 0: - dev->tun_clk_mode = reg; - dev->tun_xtal = 2000; - dev->tun_fdiv = 3; - val = 16; + /* 12.000 MHz */ + dev->clk_mode = utmp; + dev->xtal = 2000; + dev->fdiv = 3; + iqik_m_cal = 16; break; case 1: - default: /* I/O error too */ - dev->tun_clk_mode = reg; - dev->tun_xtal = 640; - dev->tun_fdiv = 1; - val = 6; + /* 20.480 MHz */ + dev->clk_mode = utmp; + dev->xtal = 640; + dev->fdiv = 1; + iqik_m_cal = 6; break; + default: + dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp); + goto err; } - ret = regmap_read(dev->regmap, 0x80ed03, ®); + ret = regmap_read(dev->regmap, 0x80ed03, &utmp); + if (ret) + goto err; - if (reg < 0) - return -ENODEV; - else if (reg < ARRAY_SIZE(nv)) - nv_val = nv[reg]; + else if (utmp < ARRAY_SIZE(nv)) + nv_val = nv[utmp]; else nv_val = 2; for (i = 0; i < 50; i++) { - ret = regmap_bulk_read(dev->regmap, 0x80ed23, &b[0], sizeof(b)); - reg = (b[1] << 8) + b[0]; - if (reg > 0) - break; + ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2); if (ret) - return -ENODEV; + goto err; + + utmp = (buf[1] << 8) | (buf[0] << 0); + if (utmp) + break; + udelay(2000); } - dev->tun_fn_min = dev->tun_xtal * reg; - dev->tun_fn_min /= (dev->tun_fdiv * nv_val); - dev_dbg(&dev->client->dev, "Tuner fn_min %d\n", dev->tun_fn_min); - if (dev->chip_ver > 1) - msleep(50); - else { + dev_dbg(&dev->client->dev, "loop count %d, utmp %d\n", i, utmp); + + dev->fn_min = dev->xtal * utmp; + dev->fn_min /= (dev->fdiv * nv_val); + dev->fn_min *= 1000; + dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min); + + if (dev->chip_ver == 1) { for (i = 0; i < 50; i++) { - ret = regmap_read(dev->regmap, 0x80ec82, ®); - if (ret < 0) - return -ENODEV; - if (reg > 0) + ret = regmap_read(dev->regmap, 0x80ec82, &utmp); + if (ret) + goto err; + + if (utmp) break; + udelay(2000); } + + dev_dbg(&dev->client->dev, "loop count %d\n", i); + } else { + msleep(50); } - /* Power Up Tuner - common all versions */ - ret = regmap_write(dev->regmap, 0x80ec40, 0x1); - ret |= regmap_write(dev->regmap, 0x80ec57, 0x0); - ret |= regmap_write(dev->regmap, 0x80ec58, 0x0); + ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec57, 0x00); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec58, 0x00); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80ec40, 0x01); + if (ret) + goto err; + + dev->active = true; - return regmap_write(dev->regmap, 0x80ed81, val); + return 0; +err: + dev_dbg(&dev->client->dev, "failed %d\n", ret); + return ret; } static int it913x_sleep(struct dvb_frontend *fe) @@ -109,7 +150,9 @@ static int it913x_sleep(struct dvb_frontend *fe) struct it913x_dev *dev = fe->tuner_priv; int ret, len; - dev_dbg(&dev->client->dev, "role=%u\n", dev->role); + dev_dbg(&dev->client->dev, "role %u\n", dev->role); + + dev->active = false; ret = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1); if (ret) @@ -124,7 +167,7 @@ static int it913x_sleep(struct dvb_frontend *fe) else len = 15; - dev_dbg(&dev->client->dev, "role=%u len=%d\n", dev->role, len); + dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len); ret = regmap_bulk_write(dev->regmap, 0x80ec02, "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", @@ -160,164 +203,159 @@ err: return ret; } -static int it9137_set_params(struct dvb_frontend *fe) +static int it913x_set_params(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 bandwidth = p->bandwidth_hz; - u32 frequency_m = p->frequency; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int 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; - - dev_dbg(&dev->client->dev, "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; + unsigned int utmp; + u32 pre_lo_freq, t_cal_freq; + u16 iqik_m_cal, n_div; + u8 u8tmp, n, l_band, lna_band; - ret = regmap_write(dev->regmap, 0x80ee06, lna_band); - if (ret) - goto err; - - switch (bandwidth) { - case 5000000: - bw = 0; - break; - case 6000000: - bw = 2; - break; - case 7000000: - bw = 4; - break; - default: - case 8000000: - bw = 6; - break; - } - - ret = regmap_write(dev->regmap, 0x80ec56, bw); - if (ret) - goto err; + dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n", + dev->role, c->frequency, c->bandwidth_hz); - ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3)); - if (ret) + if (!dev->active) { + ret = -EINVAL; goto err; + } - if (frequency > 53000 && frequency <= 74000) { + if (c->frequency <= 74000000) { n_div = 48; n = 0; - } else if (frequency > 74000 && frequency <= 111000) { + } else if (c->frequency <= 111000000) { n_div = 32; n = 1; - } else if (frequency > 111000 && frequency <= 148000) { + } else if (c->frequency <= 148000000) { n_div = 24; n = 2; - } else if (frequency > 148000 && frequency <= 222000) { + } else if (c->frequency <= 222000000) { n_div = 16; n = 3; - } else if (frequency > 222000 && frequency <= 296000) { + } else if (c->frequency <= 296000000) { n_div = 12; n = 4; - } else if (frequency > 296000 && frequency <= 445000) { + } else if (c->frequency <= 445000000) { n_div = 8; n = 5; - } else if (frequency > 445000 && frequency <= dev->tun_fn_min) { + } else if (c->frequency <= dev->fn_min) { n_div = 6; n = 6; - } else if (frequency > dev->tun_fn_min && frequency <= 950000) { + } else if (c->frequency <= 950000000) { n_div = 4; n = 7; - } else if (frequency > 1450000 && frequency <= 1680000) { + } else { n_div = 2; n = 0; - } else - return -EINVAL; + } + + ret = regmap_read(dev->regmap, 0x80ed81, &utmp); + if (ret) + goto err; - ret = regmap_read(dev->regmap, 0x80ed81, ®); - iqik_m_cal = (u16)reg * n_div; + iqik_m_cal = utmp * n_div; - if (reg < 0x20) { - if (dev->tun_clk_mode == 0) + if (utmp < 0x20) { + if (dev->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 (dev->tun_clk_mode == 0) + if (dev->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)dev->tun_fdiv; - freq = temp_f / dev->tun_xtal; - tmp = freq * dev->tun_xtal; + t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv; + pre_lo_freq = t_cal_freq / dev->xtal; + utmp = pre_lo_freq * dev->xtal; - if ((temp_f - tmp) >= (dev->tun_xtal >> 1)) - freq++; + if ((t_cal_freq - utmp) >= (dev->xtal >> 1)) + pre_lo_freq++; - freq += (u32) n << 13; + pre_lo_freq += (u32) n << 13; /* Frequency OMEGA_IQIK_M_CAL_MID*/ - temp_f = freq + (u32)iqik_m_cal; + t_cal_freq = pre_lo_freq + (u32)iqik_m_cal; + dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n", + t_cal_freq, pre_lo_freq); - ret = regmap_write(dev->regmap, 0x80ec4d, temp_f & 0xff); + if (c->frequency <= 440000000) { + l_band = 0; + lna_band = 0; + } else if (c->frequency <= 484000000) { + l_band = 1; + lna_band = 1; + } else if (c->frequency <= 533000000) { + l_band = 1; + lna_band = 2; + } else if (c->frequency <= 587000000) { + l_band = 1; + lna_band = 3; + } else if (c->frequency <= 645000000) { + l_band = 1; + lna_band = 4; + } else if (c->frequency <= 710000000) { + l_band = 1; + lna_band = 5; + } else if (c->frequency <= 782000000) { + l_band = 1; + lna_band = 6; + } else if (c->frequency <= 860000000) { + l_band = 1; + lna_band = 7; + } else if (c->frequency <= 1492000000) { + l_band = 1; + lna_band = 0; + } else if (c->frequency <= 1685000000) { + l_band = 1; + lna_band = 1; + } else { + ret = -EINVAL; + goto err; + } + + /* XXX: latest windows driver does not set that at all */ + ret = regmap_write(dev->regmap, 0x80ee06, lna_band); if (ret) goto err; - ret = regmap_write(dev->regmap, 0x80ec4e, (temp_f >> 8) & 0xff); + if (c->bandwidth_hz <= 5000000) + u8tmp = 0; + else if (c->bandwidth_hz <= 6000000) + u8tmp = 2; + else if (c->bandwidth_hz <= 7000000) + u8tmp = 4; + else + u8tmp = 6; /* 8000000 */ + + ret = regmap_write(dev->regmap, 0x80ec56, u8tmp); + if (ret) + goto err; + + /* XXX: latest windows driver sets different value (a8 != 68) */ + ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3)); if (ret) goto err; - dev_dbg(&dev->client->dev, "High Frequency = %04x\n", temp_f); + ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff); + if (ret) + goto err; - /* Lower frequency */ - ret = regmap_write(dev->regmap, 0x80011e, freq & 0xff); + ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff); if (ret) goto err; - ret = regmap_write(dev->regmap, 0x80011f, (freq >> 8) & 0xff); + ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff); + if (ret) + goto err; + + ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff); if (ret) goto err; - dev_dbg(&dev->client->dev, "low Frequency = %04x\n", freq); return 0; err: dev_dbg(&dev->client->dev, "failed %d\n", ret); @@ -326,14 +364,14 @@ err: static const struct dvb_tuner_ops it913x_tuner_ops = { .info = { - .name = "ITE Tech IT913X", + .name = "ITE IT913X", .frequency_min = 174000000, .frequency_max = 862000000, }, .init = it913x_init, .sleep = it913x_sleep, - .set_params = it9137_set_params, + .set_params = it913x_set_params, }; static int it913x_probe(struct i2c_client *client, @@ -366,11 +404,6 @@ static int it913x_probe(struct i2c_client *client, goto err_kfree; } - /* tuner RF initial */ - ret = regmap_write(dev->regmap, 0x80ec4c, 0x68); - if (ret) - goto err_regmap_exit; - fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -385,11 +418,10 @@ static int it913x_probe(struct i2c_client *client, dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n", chip_ver_str); - dev_dbg(&dev->client->dev, "chip_ver=%u role=%u\n", dev->chip_ver, dev->role); + dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n", + dev->chip_ver, dev->role); return 0; -err_regmap_exit: - regmap_exit(dev->regmap); err_kfree: kfree(dev); err: @@ -430,6 +462,6 @@ static struct i2c_driver it913x_driver = { module_i2c_driver(it913x_driver); -MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); +MODULE_DESCRIPTION("ITE IT913X silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5190ff3e3e6ec55ecda805e68c4746aec8c1203c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 00:29:33 -0300 Subject: [media] it913x: replace udelay polling with jiffies udelay based I/O polling loop is a bad idea, especially system performance point of view. Kernel jiffies are preferred solution for such situations. Use it instead. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 098e9d542708..a076c87eda7a 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -39,10 +39,11 @@ struct it913x_dev { static int it913x_init(struct dvb_frontend *fe) { struct it913x_dev *dev = fe->tuner_priv; - int ret, i; + int ret; unsigned int utmp; u8 iqik_m_cal, nv_val, buf[2]; static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; + unsigned long timeout; dev_dbg(&dev->client->dev, "role %u\n", dev->role); @@ -85,7 +86,9 @@ static int it913x_init(struct dvb_frontend *fe) else nv_val = 2; - for (i = 0; i < 50; i++) { + #define TIMEOUT 50 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2); if (ret) goto err; @@ -93,30 +96,38 @@ static int it913x_init(struct dvb_frontend *fe) utmp = (buf[1] << 8) | (buf[0] << 0); if (utmp) break; - - udelay(2000); } - dev_dbg(&dev->client->dev, "loop count %d, utmp %d\n", i, utmp); + dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - TIMEOUT), utmp); dev->fn_min = dev->xtal * utmp; dev->fn_min /= (dev->fdiv * nv_val); dev->fn_min *= 1000; dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min); + /* + * Chip version BX never sets that flag so we just wait 50ms in that + * case. It is possible poll BX similarly than AX and then timeout in + * order to get 50ms delay, but that causes about 120 extra I2C + * messages. As for now, we just wait and reduce IO. + */ if (dev->chip_ver == 1) { - for (i = 0; i < 50; i++) { + #define TIMEOUT 50 + timeout = jiffies + msecs_to_jiffies(TIMEOUT); + while (!time_after(jiffies, timeout)) { ret = regmap_read(dev->regmap, 0x80ec82, &utmp); if (ret) goto err; if (utmp) break; - - udelay(2000); } - dev_dbg(&dev->client->dev, "loop count %d\n", i); + dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n", + jiffies_to_msecs(jiffies) - + (jiffies_to_msecs(timeout) - TIMEOUT), utmp); } else { msleep(50); } -- cgit v1.2.3 From ef5211fd59ac28e9728bcf5c02207207fb8a74b5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 02:03:05 -0300 Subject: [media] af9033: fix firmware version logging AF9030 and IT9130 series has different memory location for firmware version. Choose correct location according to chip type. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 7f22f011f8f5..7d637b92ff25 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -1061,6 +1061,7 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, int ret; struct af9033_state *state; u8 buf[8]; + u32 reg; dev_dbg(&i2c->dev, "%s:\n", __func__); @@ -1081,7 +1082,21 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, } /* firmware version */ - ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); + 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: + reg = 0x004bfc; + break; + default: + reg = 0x0083e9; + break; + } + + ret = af9033_rd_regs(state, reg, &buf[0], 4); if (ret < 0) goto err; -- cgit v1.2.3 From 09611caad158f868993261c7d9277a9a331f8ea3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 02:18:34 -0300 Subject: [media] af9033: rename 'state' to 'dev' foo_dev seems to be most correct term for the structure holding data of each device instance. It is most used term in Kernel codebase and also examples from book Linux Device Drivers, Third Edition, uses it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 328 +++++++++++++++++------------------ 1 file changed, 164 insertions(+), 164 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 7d637b92ff25..43b7335f27e4 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -24,7 +24,7 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 -struct af9033_state { +struct af9033_dev { struct i2c_adapter *i2c; struct dvb_frontend fe; struct af9033_config cfg; @@ -39,14 +39,14 @@ struct af9033_state { }; /* write multiple registers */ -static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, +static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, int len) { int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = state->cfg.i2c_addr, + .addr = dev->cfg.i2c_addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -54,7 +54,7 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, }; if (3 + len > sizeof(buf)) { - dev_warn(&state->i2c->dev, + dev_warn(&dev->i2c->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -65,11 +65,11 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, buf[2] = (reg >> 0) & 0xff; memcpy(&buf[3], val, len); - ret = i2c_transfer(state->i2c, msg, 1); + ret = i2c_transfer(dev->i2c, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&state->i2c->dev, + dev_warn(&dev->i2c->dev, "%s: i2c wr failed=%d reg=%06x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -79,30 +79,30 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, } /* read multiple registers */ -static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) +static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len) { int ret; u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, (reg >> 0) & 0xff }; struct i2c_msg msg[2] = { { - .addr = state->cfg.i2c_addr, + .addr = dev->cfg.i2c_addr, .flags = 0, .len = sizeof(buf), .buf = buf }, { - .addr = state->cfg.i2c_addr, + .addr = dev->cfg.i2c_addr, .flags = I2C_M_RD, .len = len, .buf = val } }; - ret = i2c_transfer(state->i2c, msg, 2); + ret = i2c_transfer(dev->i2c, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&state->i2c->dev, + dev_warn(&dev->i2c->dev, "%s: i2c rd failed=%d reg=%06x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -113,19 +113,19 @@ static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) /* write single register */ -static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) +static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val) { - return af9033_wr_regs(state, reg, &val, 1); + return af9033_wr_regs(dev, reg, &val, 1); } /* read single register */ -static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) +static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val) { - return af9033_rd_regs(state, reg, val, 1); + return af9033_rd_regs(dev, reg, val, 1); } /* write single register with mask */ -static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, +static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val, u8 mask) { int ret; @@ -133,7 +133,7 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, /* no need for read if whole reg is written */ if (mask != 0xff) { - ret = af9033_rd_regs(state, reg, &tmp, 1); + ret = af9033_rd_regs(dev, reg, &tmp, 1); if (ret) return ret; @@ -142,17 +142,17 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, val |= tmp; } - return af9033_wr_regs(state, reg, &val, 1); + return af9033_wr_regs(dev, reg, &val, 1); } /* read single register with mask */ -static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, +static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; - ret = af9033_rd_regs(state, reg, &tmp, 1); + ret = af9033_rd_regs(dev, reg, &tmp, 1); if (ret) return ret; @@ -169,17 +169,17 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, } /* write reg val table using reg addr auto increment */ -static int af9033_wr_reg_val_tab(struct af9033_state *state, +static int af9033_wr_reg_val_tab(struct af9033_dev *dev, const struct reg_val *tab, int tab_len) { #define MAX_TAB_LEN 212 int ret, i, j; u8 buf[1 + MAX_TAB_LEN]; - dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + dev_dbg(&dev->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); if (tab_len > sizeof(buf)) { - dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n", + dev_warn(&dev->i2c->dev, "%s: tab len %d is too big\n", KBUILD_MODNAME, tab_len); return -EINVAL; } @@ -188,7 +188,7 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state, 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); + ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1); if (ret < 0) goto err; @@ -201,16 +201,16 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state, return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } -static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) +static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&dev->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); if (a > b) { c = a / b; @@ -227,7 +227,7 @@ static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", + dev_dbg(&dev->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); return r; @@ -235,14 +235,14 @@ static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) static void af9033_release(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; - kfree(state); + kfree(dev); } static int af9033_init(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret, i, len; const struct reg_val *init; u8 buf[4]; @@ -250,7 +250,7 @@ static int af9033_init(struct dvb_frontend *fe) struct reg_val_mask tab[] = { { 0x80fb24, 0x00, 0x08 }, { 0x80004c, 0x00, 0xff }, - { 0x00f641, state->cfg.tuner, 0xff }, + { 0x00f641, dev->cfg.tuner, 0xff }, { 0x80f5ca, 0x01, 0x01 }, { 0x80f715, 0x01, 0x01 }, { 0x00f41f, 0x04, 0x04 }, @@ -269,82 +269,82 @@ static int af9033_init(struct dvb_frontend *fe) { 0x00d830, 0x01, 0xff }, { 0x00d831, 0x00, 0xff }, { 0x00d832, 0x00, 0xff }, - { 0x80f985, state->ts_mode_serial, 0x01 }, - { 0x80f986, state->ts_mode_parallel, 0x01 }, + { 0x80f985, dev->ts_mode_serial, 0x01 }, + { 0x80f986, dev->ts_mode_parallel, 0x01 }, { 0x00d827, 0x00, 0xff }, { 0x00d829, 0x00, 0xff }, - { 0x800045, state->cfg.adc_multiplier, 0xff }, + { 0x800045, dev->cfg.adc_multiplier, 0xff }, }; /* program clock control */ - clock_cw = af9033_div(state, state->cfg.clock, 1000000ul, 19ul); + clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul); buf[0] = (clock_cw >> 0) & 0xff; buf[1] = (clock_cw >> 8) & 0xff; buf[2] = (clock_cw >> 16) & 0xff; buf[3] = (clock_cw >> 24) & 0xff; - dev_dbg(&state->i2c->dev, "%s: clock=%d clock_cw=%08x\n", - __func__, state->cfg.clock, clock_cw); + dev_dbg(&dev->i2c->dev, "%s: clock=%d clock_cw=%08x\n", + __func__, dev->cfg.clock, clock_cw); - ret = af9033_wr_regs(state, 0x800025, buf, 4); + ret = af9033_wr_regs(dev, 0x800025, buf, 4); if (ret < 0) goto err; /* program ADC control */ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { - if (clock_adc_lut[i].clock == state->cfg.clock) + if (clock_adc_lut[i].clock == dev->cfg.clock) break; } - adc_cw = af9033_div(state, clock_adc_lut[i].adc, 1000000ul, 19ul); + adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul); buf[0] = (adc_cw >> 0) & 0xff; buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - dev_dbg(&state->i2c->dev, "%s: adc=%d adc_cw=%06x\n", + dev_dbg(&dev->i2c->dev, "%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, adc_cw); - ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); + ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3); if (ret < 0) goto err; /* program register table */ for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, + ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val, tab[i].mask); if (ret < 0) goto err; } /* clock output */ - if (state->cfg.dyn0_clk) { - ret = af9033_wr_reg(state, 0x80fba8, 0x00); + if (dev->cfg.dyn0_clk) { + ret = af9033_wr_reg(dev, 0x80fba8, 0x00); if (ret < 0) goto err; } /* settings for TS interface */ - if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { - ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); + if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) { + ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01); if (ret < 0) goto err; } else { - ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01); if (ret < 0) goto err; } /* load OFSM settings */ - dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__); - switch (state->cfg.tuner) { + dev_dbg(&dev->i2c->dev, "%s: load ofsm settings\n", __func__); + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: @@ -363,14 +363,14 @@ static int af9033_init(struct dvb_frontend *fe) break; } - ret = af9033_wr_reg_val_tab(state, init, len); + ret = af9033_wr_reg_val_tab(dev, init, len); if (ret < 0) goto err; /* load tuner specific settings */ - dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n", + dev_dbg(&dev->i2c->dev, "%s: load tuner specific settings\n", __func__); - switch (state->cfg.tuner) { + switch (dev->cfg.tuner) { case AF9033_TUNER_TUA9001: len = ARRAY_SIZE(tuner_init_tua9001); init = tuner_init_tua9001; @@ -420,90 +420,90 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_62; break; default: - dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n", - __func__, state->cfg.tuner); + dev_dbg(&dev->i2c->dev, "%s: unsupported tuner ID=%d\n", + __func__, dev->cfg.tuner); ret = -ENODEV; goto err; } - ret = af9033_wr_reg_val_tab(state, init, len); + ret = af9033_wr_reg_val_tab(dev, 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); + if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01); if (ret < 0) goto err; } - switch (state->cfg.tuner) { + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - ret = af9033_wr_reg(state, 0x800000, 0x01); + ret = af9033_wr_reg(dev, 0x800000, 0x01); if (ret < 0) goto err; } - state->bandwidth_hz = 0; /* force to program all parameters */ + dev->bandwidth_hz = 0; /* force to program all parameters */ return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_sleep(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret, i; u8 tmp; - ret = af9033_wr_reg(state, 0x80004c, 1); + ret = af9033_wr_reg(dev, 0x80004c, 1); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800000, 0); + ret = af9033_wr_reg(dev, 0x800000, 0); if (ret < 0) goto err; for (i = 100, tmp = 1; i && tmp; i--) { - ret = af9033_rd_reg(state, 0x80004c, &tmp); + ret = af9033_rd_reg(dev, 0x80004c, &tmp); if (ret < 0) goto err; usleep_range(200, 10000); } - dev_dbg(&state->i2c->dev, "%s: loop=%d\n", __func__, i); + dev_dbg(&dev->i2c->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; goto err; } - ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); + ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08); if (ret < 0) goto err; /* prevent current leak (?) */ - if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { /* enable parallel TS */ - ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01); if (ret < 0) goto err; } @@ -511,7 +511,7 @@ static int af9033_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -529,13 +529,13 @@ static int af9033_get_tune_settings(struct dvb_frontend *fe, static int af9033_set_frontend(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, spec_inv, sampling_freq; u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; - dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", + dev_dbg(&dev->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, c->bandwidth_hz); /* check bandwidth */ @@ -550,7 +550,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) bandwidth_reg_val = 0x02; break; default: - dev_dbg(&state->i2c->dev, "%s: invalid bandwidth_hz\n", + dev_dbg(&dev->i2c->dev, "%s: invalid bandwidth_hz\n", __func__); ret = -EINVAL; goto err; @@ -561,23 +561,23 @@ static int af9033_set_frontend(struct dvb_frontend *fe) fe->ops.tuner_ops.set_params(fe); /* program CFOE coefficients */ - if (c->bandwidth_hz != state->bandwidth_hz) { + if (c->bandwidth_hz != dev->bandwidth_hz) { for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { - if (coeff_lut[i].clock == state->cfg.clock && + if (coeff_lut[i].clock == dev->cfg.clock && coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } } - ret = af9033_wr_regs(state, 0x800001, + ret = af9033_wr_regs(dev, 0x800001, coeff_lut[i].val, sizeof(coeff_lut[i].val)); } /* program frequency control */ - if (c->bandwidth_hz != state->bandwidth_hz) { - spec_inv = state->cfg.spec_inv ? -1 : 1; + if (c->bandwidth_hz != dev->bandwidth_hz) { + spec_inv = dev->cfg.spec_inv ? -1 : 1; for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { - if (clock_adc_lut[i].clock == state->cfg.clock) + if (clock_adc_lut[i].clock == dev->cfg.clock) break; } adc_freq = clock_adc_lut[i].adc; @@ -598,12 +598,12 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else sampling_freq *= -1; - freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul); + freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul); if (spec_inv == -1) freq_cw = 0x800000 - freq_cw; - if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X) + if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X) freq_cw /= 2; buf[0] = (freq_cw >> 0) & 0xff; @@ -614,26 +614,26 @@ static int af9033_set_frontend(struct dvb_frontend *fe) if (if_frequency == 0) buf[2] = 0; - ret = af9033_wr_regs(state, 0x800029, buf, 3); + ret = af9033_wr_regs(dev, 0x800029, buf, 3); if (ret < 0) goto err; - state->bandwidth_hz = c->bandwidth_hz; + dev->bandwidth_hz = c->bandwidth_hz; } - ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); + ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800040, 0x00); + ret = af9033_wr_reg(dev, 0x800040, 0x00); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800047, 0x00); + ret = af9033_wr_reg(dev, 0x800047, 0x00); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01); if (ret < 0) goto err; @@ -642,33 +642,33 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else tmp = 0x01; /* UHF */ - ret = af9033_wr_reg(state, 0x80004b, tmp); + ret = af9033_wr_reg(dev, 0x80004b, tmp); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800000, 0x00); + ret = af9033_wr_reg(dev, 0x800000, 0x00); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_get_frontend(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[8]; - dev_dbg(&state->i2c->dev, "%s:\n", __func__); + dev_dbg(&dev->i2c->dev, "%s:\n", __func__); /* read all needed registers */ - ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); + ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf)); if (ret < 0) goto err; @@ -780,21 +780,21 @@ static int af9033_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 tmp; *status = 0; /* radio channel status, 0=no result, 1=has signal, 2=no signal */ - ret = af9033_rd_reg(state, 0x800047, &tmp); + ret = af9033_rd_reg(dev, 0x800047, &tmp); if (ret < 0) goto err; @@ -804,7 +804,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) if (tmp != 0x02) { /* TPS lock */ - ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); + ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01); if (ret < 0) goto err; @@ -813,7 +813,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) FE_HAS_VITERBI; /* full lock */ - ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); + ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01); if (ret < 0) goto err; @@ -826,28 +826,28 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret, i, len; u8 buf[3], tmp; u32 snr_val; const struct val_snr *snr_lut; /* read value */ - ret = af9033_rd_regs(state, 0x80002c, buf, 3); + ret = af9033_rd_regs(dev, 0x80002c, buf, 3); if (ret < 0) goto err; snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; /* read current modulation */ - ret = af9033_rd_reg(state, 0x80f903, &tmp); + ret = af9033_rd_reg(dev, 0x80f903, &tmp); if (ret < 0) goto err; @@ -880,19 +880,19 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 strength2; /* read signal strength of 0-100 scale */ - ret = af9033_rd_reg(state, 0x800048, &strength2); + ret = af9033_rd_reg(dev, 0x800048, &strength2); if (ret < 0) goto err; @@ -902,12 +902,12 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } -static int af9033_update_ch_stat(struct af9033_state *state) +static int af9033_update_ch_stat(struct af9033_dev *dev) { int ret = 0; u32 err_cnt, bit_cnt; @@ -915,8 +915,8 @@ static int af9033_update_ch_stat(struct af9033_state *state) u8 buf[7]; /* only update data every half second */ - if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) { - ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf)); + if (time_after(jiffies, dev->last_stat_check + msecs_to_jiffies(500))) { + ret = af9033_rd_regs(dev, 0x800032, buf, sizeof(buf)); if (ret < 0) goto err; /* in 8 byte packets? */ @@ -928,93 +928,93 @@ static int af9033_update_ch_stat(struct af9033_state *state) if (bit_cnt < abort_cnt) { abort_cnt = 1000; - state->ber = 0xffffffff; + dev->ber = 0xffffffff; } else { /* * 8 byte packets, that have not been rejected already */ bit_cnt -= (u32)abort_cnt; if (bit_cnt == 0) { - state->ber = 0xffffffff; + dev->ber = 0xffffffff; } else { err_cnt -= (u32)abort_cnt * 8 * 8; bit_cnt *= 8 * 8; - state->ber = err_cnt * (0xffffffff / bit_cnt); + dev->ber = err_cnt * (0xffffffff / bit_cnt); } } - state->ucb += abort_cnt; - state->last_stat_check = jiffies; + dev->ucb += abort_cnt; + dev->last_stat_check = jiffies; } return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - ret = af9033_update_ch_stat(state); + ret = af9033_update_ch_stat(dev); if (ret < 0) return ret; - *ber = state->ber; + *ber = dev->ber; return 0; } static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - ret = af9033_update_ch_stat(state); + ret = af9033_update_ch_stat(dev); if (ret < 0) return ret; - *ucblocks = state->ucb; + *ucblocks = dev->ucb; return 0; } static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&state->i2c->dev, "%s: enable=%d\n", __func__, enable); + dev_dbg(&dev->i2c->dev, "%s: enable=%d\n", __func__, enable); - ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&dev->i2c->dev, "%s: onoff=%d\n", __func__, onoff); - ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1022,32 +1022,32 @@ err: static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", + dev_dbg(&dev->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", __func__, index, pid, onoff); if (pid > 0x1fff) return 0; - ret = af9033_wr_regs(state, 0x80f996, wbuf, 2); + ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x80f994, onoff); + ret = af9033_wr_reg(dev, 0x80f994, onoff); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x80f995, index); + ret = af9033_wr_reg(dev, 0x80f995, index); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1059,30 +1059,30 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, struct af9033_ops *ops) { int ret; - struct af9033_state *state; + struct af9033_dev *dev; u8 buf[8]; u32 reg; dev_dbg(&i2c->dev, "%s:\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); - if (state == NULL) + dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL); + if (dev == NULL) goto err; /* setup the state */ - state->i2c = i2c; - memcpy(&state->cfg, config, sizeof(struct af9033_config)); + dev->i2c = i2c; + memcpy(&dev->cfg, config, sizeof(struct af9033_config)); - if (state->cfg.clock != 12000000) { - dev_err(&state->i2c->dev, + if (dev->cfg.clock != 12000000) { + dev_err(&dev->i2c->dev, "%s: af9033: unsupported clock=%d, only 12000000 Hz is supported currently\n", - KBUILD_MODNAME, state->cfg.clock); + KBUILD_MODNAME, dev->cfg.clock); goto err; } /* firmware version */ - switch (state->cfg.tuner) { + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: @@ -1096,21 +1096,21 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, break; } - ret = af9033_rd_regs(state, reg, &buf[0], 4); + ret = af9033_rd_regs(dev, reg, &buf[0], 4); if (ret < 0) goto err; - ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); + ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4); if (ret < 0) goto err; - dev_info(&state->i2c->dev, + dev_info(&dev->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d 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 */ - switch (state->cfg.tuner) { + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: @@ -1120,22 +1120,22 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, /* IT9135 did not like to sleep at that early */ break; default: - ret = af9033_wr_reg(state, 0x80004c, 1); + ret = af9033_wr_reg(dev, 0x80004c, 1); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800000, 0); + ret = af9033_wr_reg(dev, 0x800000, 0); if (ret < 0) goto err; } /* configure internal TS mode */ - switch (state->cfg.ts_mode) { + switch (dev->cfg.ts_mode) { case AF9033_TS_MODE_PARALLEL: - state->ts_mode_parallel = true; + dev->ts_mode_parallel = true; break; case AF9033_TS_MODE_SERIAL: - state->ts_mode_serial = true; + dev->ts_mode_serial = true; break; case AF9033_TS_MODE_USB: /* usb mode for AF9035 */ @@ -1144,18 +1144,18 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, } /* create dvb_frontend */ - memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); - state->fe.demodulator_priv = state; + memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.demodulator_priv = dev; if (ops) { ops->pid_filter = af9033_pid_filter; ops->pid_filter_ctrl = af9033_pid_filter_ctrl; } - return &state->fe; + return &dev->fe; err: - kfree(state); + kfree(dev); return NULL; } EXPORT_SYMBOL(af9033_attach); -- cgit v1.2.3 From f5b00a767006e47f9c32099f0797068a7a3e4c5c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 20:57:05 -0300 Subject: [media] af9033: convert to I2C client Convert driver to kernel I2C model. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 236 +++++++++++++++++++--------------- drivers/media/dvb-frontends/af9033.h | 44 ++----- drivers/media/usb/dvb-usb-v2/af9035.c | 50 +++++-- drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 4 files changed, 183 insertions(+), 149 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 43b7335f27e4..c40ae49effb5 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -25,7 +25,7 @@ #define MAX_XFER_SIZE 64 struct af9033_dev { - struct i2c_adapter *i2c; + struct i2c_client *client; struct dvb_frontend fe; struct af9033_config cfg; @@ -46,7 +46,7 @@ static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = dev->cfg.i2c_addr, + .addr = dev->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -54,7 +54,7 @@ static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, }; if (3 + len > sizeof(buf)) { - dev_warn(&dev->i2c->dev, + dev_warn(&dev->client->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -65,11 +65,11 @@ static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, buf[2] = (reg >> 0) & 0xff; memcpy(&buf[3], val, len); - ret = i2c_transfer(dev->i2c, msg, 1); + ret = i2c_transfer(dev->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&dev->i2c->dev, + dev_warn(&dev->client->dev, "%s: i2c wr failed=%d reg=%06x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -86,23 +86,23 @@ static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len) (reg >> 0) & 0xff }; struct i2c_msg msg[2] = { { - .addr = dev->cfg.i2c_addr, + .addr = dev->client->addr, .flags = 0, .len = sizeof(buf), .buf = buf }, { - .addr = dev->cfg.i2c_addr, + .addr = dev->client->addr, .flags = I2C_M_RD, .len = len, .buf = val } }; - ret = i2c_transfer(dev->i2c, msg, 2); + ret = i2c_transfer(dev->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&dev->i2c->dev, + dev_warn(&dev->client->dev, "%s: i2c rd failed=%d reg=%06x len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; @@ -176,10 +176,10 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev, int ret, i, j; u8 buf[1 + MAX_TAB_LEN]; - dev_dbg(&dev->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + dev_dbg(&dev->client->dev, "%s: tab_len=%d\n", __func__, tab_len); if (tab_len > sizeof(buf)) { - dev_warn(&dev->i2c->dev, "%s: tab len %d is too big\n", + dev_warn(&dev->client->dev, "%s: tab len %d is too big\n", KBUILD_MODNAME, tab_len); return -EINVAL; } @@ -201,7 +201,7 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev, return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -210,7 +210,7 @@ static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&dev->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&dev->client->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); if (a > b) { c = a / b; @@ -227,19 +227,12 @@ static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - dev_dbg(&dev->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", + dev_dbg(&dev->client->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r); return r; } -static void af9033_release(struct dvb_frontend *fe) -{ - struct af9033_dev *dev = fe->demodulator_priv; - - kfree(dev); -} - static int af9033_init(struct dvb_frontend *fe) { struct af9033_dev *dev = fe->demodulator_priv; @@ -283,7 +276,7 @@ static int af9033_init(struct dvb_frontend *fe) buf[2] = (clock_cw >> 16) & 0xff; buf[3] = (clock_cw >> 24) & 0xff; - dev_dbg(&dev->i2c->dev, "%s: clock=%d clock_cw=%08x\n", + dev_dbg(&dev->client->dev, "%s: clock=%d clock_cw=%08x\n", __func__, dev->cfg.clock, clock_cw); ret = af9033_wr_regs(dev, 0x800025, buf, 4); @@ -301,7 +294,7 @@ static int af9033_init(struct dvb_frontend *fe) buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - dev_dbg(&dev->i2c->dev, "%s: adc=%d adc_cw=%06x\n", + dev_dbg(&dev->client->dev, "%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc, adc_cw); ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3); @@ -343,7 +336,7 @@ static int af9033_init(struct dvb_frontend *fe) } /* load OFSM settings */ - dev_dbg(&dev->i2c->dev, "%s: load ofsm settings\n", __func__); + dev_dbg(&dev->client->dev, "%s: load ofsm settings\n", __func__); switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: @@ -368,7 +361,7 @@ static int af9033_init(struct dvb_frontend *fe) goto err; /* load tuner specific settings */ - dev_dbg(&dev->i2c->dev, "%s: load tuner specific settings\n", + dev_dbg(&dev->client->dev, "%s: load tuner specific settings\n", __func__); switch (dev->cfg.tuner) { case AF9033_TUNER_TUA9001: @@ -420,7 +413,7 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_62; break; default: - dev_dbg(&dev->i2c->dev, "%s: unsupported tuner ID=%d\n", + dev_dbg(&dev->client->dev, "%s: unsupported tuner ID=%d\n", __func__, dev->cfg.tuner); ret = -ENODEV; goto err; @@ -458,7 +451,7 @@ static int af9033_init(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -485,7 +478,7 @@ static int af9033_sleep(struct dvb_frontend *fe) usleep_range(200, 10000); } - dev_dbg(&dev->i2c->dev, "%s: loop=%d\n", __func__, i); + dev_dbg(&dev->client->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; @@ -511,7 +504,7 @@ static int af9033_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -535,7 +528,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; - dev_dbg(&dev->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", + dev_dbg(&dev->client->dev, "%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency, c->bandwidth_hz); /* check bandwidth */ @@ -550,7 +543,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) bandwidth_reg_val = 0x02; break; default: - dev_dbg(&dev->i2c->dev, "%s: invalid bandwidth_hz\n", + dev_dbg(&dev->client->dev, "%s: invalid bandwidth_hz\n", __func__); ret = -EINVAL; goto err; @@ -653,7 +646,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -665,7 +658,7 @@ static int af9033_get_frontend(struct dvb_frontend *fe) int ret; u8 buf[8]; - dev_dbg(&dev->i2c->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "%s:\n", __func__); /* read all needed registers */ ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf)); @@ -780,7 +773,7 @@ static int af9033_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -826,7 +819,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -880,7 +873,7 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -902,7 +895,7 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -948,7 +941,7 @@ static int af9033_update_ch_stat(struct af9033_dev *dev) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -986,7 +979,7 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&dev->i2c->dev, "%s: enable=%d\n", __func__, enable); + dev_dbg(&dev->client->dev, "%s: enable=%d\n", __func__, enable); ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01); if (ret < 0) @@ -995,7 +988,7 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1005,7 +998,7 @@ static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&dev->i2c->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&dev->client->dev, "%s: onoff=%d\n", __func__, onoff); ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01); if (ret < 0) @@ -1014,7 +1007,7 @@ static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1026,7 +1019,7 @@ static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int ret; u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - dev_dbg(&dev->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", + dev_dbg(&dev->client->dev, "%s: index=%d pid=%04x onoff=%d\n", __func__, index, pid, onoff); if (pid > 0x1fff) @@ -1047,38 +1040,79 @@ static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, return 0; err: - dev_dbg(&dev->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } -static struct dvb_frontend_ops af9033_ops; +static struct dvb_frontend_ops af9033_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Afatech AF9033 (DVB-T)", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 250000, + .frequency_tolerance = 0, + .caps = 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_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .init = af9033_init, + .sleep = af9033_sleep, + + .get_tune_settings = af9033_get_tune_settings, + .set_frontend = af9033_set_frontend, + .get_frontend = af9033_get_frontend, + + .read_status = af9033_read_status, + .read_snr = af9033_read_snr, + .read_signal_strength = af9033_read_signal_strength, + .read_ber = af9033_read_ber, + .read_ucblocks = af9033_read_ucblocks, + + .i2c_gate_ctrl = af9033_i2c_gate_ctrl, +}; -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops) +static int af9033_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int ret; + struct af9033_config *cfg = client->dev.platform_data; struct af9033_dev *dev; + int ret; u8 buf[8]; u32 reg; - dev_dbg(&i2c->dev, "%s:\n", __func__); - /* allocate memory for the internal state */ dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL); - if (dev == NULL) + if (dev == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "Could not allocate memory for state\n"); goto err; + } /* setup the state */ - dev->i2c = i2c; - memcpy(&dev->cfg, config, sizeof(struct af9033_config)); + dev->client = client; + memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); if (dev->cfg.clock != 12000000) { - dev_err(&dev->i2c->dev, + ret = -ENODEV; + dev_err(&dev->client->dev, "%s: af9033: unsupported clock=%d, only 12000000 Hz is supported currently\n", KBUILD_MODNAME, dev->cfg.clock); - goto err; + goto err_kfree; } /* firmware version */ @@ -1098,13 +1132,13 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, ret = af9033_rd_regs(dev, reg, &buf[0], 4); if (ret < 0) - goto err; + goto err_kfree; ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4); if (ret < 0) - goto err; + goto err_kfree; - dev_info(&dev->i2c->dev, + dev_info(&dev->client->dev, "%s: firmware version: LINK=%d.%d.%d.%d OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); @@ -1122,11 +1156,11 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, default: ret = af9033_wr_reg(dev, 0x80004c, 1); if (ret < 0) - goto err; + goto err_kfree; ret = af9033_wr_reg(dev, 0x800000, 0); if (ret < 0) - goto err; + goto err_kfree; } /* configure internal TS mode */ @@ -1146,63 +1180,53 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, /* create dvb_frontend */ memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); dev->fe.demodulator_priv = dev; - - if (ops) { - ops->pid_filter = af9033_pid_filter; - ops->pid_filter_ctrl = af9033_pid_filter_ctrl; + *cfg->fe = &dev->fe; + if (cfg->ops) { + cfg->ops->pid_filter = af9033_pid_filter; + cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl; } + i2c_set_clientdata(client, dev); - return &dev->fe; - -err: + dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n"); + return 0; +err_kfree: kfree(dev); - return NULL; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; } -EXPORT_SYMBOL(af9033_attach); -static struct dvb_frontend_ops af9033_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Afatech AF9033 (DVB-T)", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 250000, - .frequency_tolerance = 0, - .caps = 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_HIERARCHY_AUTO | - FE_CAN_RECOVER | - FE_CAN_MUTE_TS - }, +static int af9033_remove(struct i2c_client *client) +{ + struct af9033_dev *dev = i2c_get_clientdata(client); - .release = af9033_release, + dev_dbg(&client->dev, "%s\n", __func__); - .init = af9033_init, - .sleep = af9033_sleep, + dev->fe.ops.release = NULL; + dev->fe.demodulator_priv = NULL; + kfree(dev); - .get_tune_settings = af9033_get_tune_settings, - .set_frontend = af9033_set_frontend, - .get_frontend = af9033_get_frontend, + return 0; +} - .read_status = af9033_read_status, - .read_snr = af9033_read_snr, - .read_signal_strength = af9033_read_signal_strength, - .read_ber = af9033_read_ber, - .read_ucblocks = af9033_read_ucblocks, +static const struct i2c_device_id af9033_id_table[] = { + {"af9033", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, af9033_id_table); - .i2c_gate_ctrl = af9033_i2c_gate_ctrl, +static struct i2c_driver af9033_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "af9033", + }, + .probe = af9033_probe, + .remove = af9033_remove, + .id_table = af9033_id_table, }; +module_i2c_driver(af9033_driver); + MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index b95a6d438eca..1b968d0fcb17 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -80,8 +80,18 @@ struct af9033_config { * */ bool dyn0_clk; -}; + /* + * PID filter ops + */ + struct af9033_ops *ops; + + /* + * frontend + * returned by that driver + */ + struct dvb_frontend **fe; +}; struct af9033_ops { int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff); @@ -89,36 +99,4 @@ struct af9033_ops { int onoff); }; - -#if IS_ENABLED(CONFIG_DVB_AF9033) -extern -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops); - -#else -static inline -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, - int onoff) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -#endif - #endif /* AF9033_H */ diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 533c96e4fbb6..6534e44b42b6 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -305,6 +305,19 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, * NOTE: As a firmware knows tuner type there is very small possibility * there could be some tuner I2C hacks done by firmware and this may * lead problems if firmware expects those bytes are used. + * + * TODO: Here is few hacks. AF9035 chip integrates AF9033 demodulator. + * IT9135 chip integrates AF9033 demodulator and RF tuner. For dual + * tuner devices, there is also external AF9033 demodulator connected + * via external I2C bus. All AF9033 demod I2C traffic, both single and + * dual tuner configuration, is covered by firmware - actual USB IO + * looks just like a memory access. + * In case of IT913x chip, there is own tuner driver. It is implemented + * currently as a I2C driver, even tuner IP block is likely build + * directly into the demodulator memory space and there is no own I2C + * bus. I2C subsystem does not allow register multiple devices to same + * bus, having same slave address. Due to that we reuse demod address, + * shifted by one bit, on that case. */ if (num == 2 && !(msg[0].flags & I2C_M_RD) && (msg[1].flags & I2C_M_RD)) { @@ -312,12 +325,14 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) || - (msg[0].addr == state->af9033_config[1].i2c_addr)) { + (msg[0].addr == state->af9033_config[1].i2c_addr) || + (state->chip_type == 0x9135)) { /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; - if (msg[0].addr == state->af9033_config[1].i2c_addr) + if (msg[0].addr == state->af9033_config[1].i2c_addr || + msg[0].addr == (state->af9033_config[1].i2c_addr >> 1)) reg |= 0x100000; ret = af9035_rd_regs(d, reg, &msg[1].buf[0], @@ -349,12 +364,14 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) || - (msg[0].addr == state->af9033_config[1].i2c_addr)) { + (msg[0].addr == state->af9033_config[1].i2c_addr) || + (state->chip_type == 0x9135)) { /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; - if (msg[0].addr == state->af9033_config[1].i2c_addr) + if (msg[0].addr == state->af9033_config[1].i2c_addr || + msg[0].addr == (state->af9033_config[1].i2c_addr >> 1)) reg |= 0x100000; ret = af9035_wr_regs(d, reg, &msg[0].buf[3], @@ -1066,6 +1083,8 @@ static int af9035_get_adapter_count(struct dvb_usb_device *d) return state->dual_mode + 1; } +static void af9035_exit(struct dvb_usb_device *d); + static int af9035_frontend_attach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1080,9 +1099,14 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) goto err; } - /* attach demodulator */ - adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id], - &d->i2c_adap, &state->ops); + state->af9033_config[adap->id].fe = &adap->fe[0]; + state->af9033_config[adap->id].ops = &state->ops; + ret = af9035_add_i2c_dev(d, "af9033", + state->af9033_config[adap->id].i2c_addr, + &state->af9033_config[adap->id]); + if (ret) + goto err; + if (adap->fe[0] == NULL) { ret = -ENODEV; goto err; @@ -1095,6 +1119,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) return 0; err: + af9035_exit(d); /* remove I2C clients */ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; @@ -1332,7 +1357,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) } ret = af9035_add_i2c_dev(d, "it913x", - state->af9033_config[adap->id].i2c_addr, + state->af9033_config[adap->id].i2c_addr >> 1, &it913x_config); if (ret) goto err; @@ -1357,7 +1382,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) } ret = af9035_add_i2c_dev(d, "it913x", - state->af9033_config[adap->id].i2c_addr, + state->af9033_config[adap->id].i2c_addr >> 1, &it913x_config); if (ret) goto err; @@ -1377,6 +1402,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) return 0; err: + af9035_exit(d); /* remove I2C clients */ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; @@ -1435,6 +1461,12 @@ static void af9035_exit(struct dvb_usb_device *d) dev_dbg(&d->udev->dev, "%s:\n", __func__); + if (state->i2c_client[3]) + af9035_del_i2c_dev(d); + + if (state->i2c_client[2]) + af9035_del_i2c_dev(d); + if (state->i2c_client[1]) af9035_del_i2c_dev(d); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 0911c4fc860c..21960773df05 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 { u16 eeprom_addr; struct af9033_config af9033_config[2]; struct af9033_ops ops; - #define AF9035_I2C_CLIENT_MAX 2 + #define AF9035_I2C_CLIENT_MAX 4 struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX]; }; -- cgit v1.2.3 From 6a087f1f6bb731719ff7b8e20a3ec6a8613fff12 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 21:08:09 -0300 Subject: [media] af9033: clean up logging It uses I2C client so logging system prints module name automatically. Function name is also added automatically, if it is requested from dynamic debug by setting proper format. Because of that, we could simplify logging in our driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 98 +++++++++++++++++------------------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index c40ae49effb5..1bd5a9af7db5 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -55,8 +55,8 @@ static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, if (3 + len > sizeof(buf)) { dev_warn(&dev->client->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); + "i2c wr reg=%04x: len=%d is too big!\n", + reg, len); return -EINVAL; } @@ -69,9 +69,8 @@ static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, if (ret == 1) { ret = 0; } else { - dev_warn(&dev->client->dev, - "%s: i2c wr failed=%d reg=%06x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -102,9 +101,8 @@ static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len) if (ret == 2) { ret = 0; } else { - dev_warn(&dev->client->dev, - "%s: i2c rd failed=%d reg=%06x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -176,11 +174,10 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev, int ret, i, j; u8 buf[1 + MAX_TAB_LEN]; - dev_dbg(&dev->client->dev, "%s: tab_len=%d\n", __func__, tab_len); + dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len); if (tab_len > sizeof(buf)) { - dev_warn(&dev->client->dev, "%s: tab len %d is too big\n", - KBUILD_MODNAME, tab_len); + dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len); return -EINVAL; } @@ -201,7 +198,7 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev, return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -210,7 +207,7 @@ static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&dev->client->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x); if (a > b) { c = a / b; @@ -227,8 +224,7 @@ static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - dev_dbg(&dev->client->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", - __func__, a, b, x, r, r); + dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r); return r; } @@ -276,8 +272,8 @@ static int af9033_init(struct dvb_frontend *fe) buf[2] = (clock_cw >> 16) & 0xff; buf[3] = (clock_cw >> 24) & 0xff; - dev_dbg(&dev->client->dev, "%s: clock=%d clock_cw=%08x\n", - __func__, dev->cfg.clock, clock_cw); + dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n", + dev->cfg.clock, clock_cw); ret = af9033_wr_regs(dev, 0x800025, buf, 4); if (ret < 0) @@ -294,8 +290,8 @@ static int af9033_init(struct dvb_frontend *fe) buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - dev_dbg(&dev->client->dev, "%s: adc=%d adc_cw=%06x\n", - __func__, clock_adc_lut[i].adc, adc_cw); + dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n", + clock_adc_lut[i].adc, adc_cw); ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3); if (ret < 0) @@ -336,7 +332,7 @@ static int af9033_init(struct dvb_frontend *fe) } /* load OFSM settings */ - dev_dbg(&dev->client->dev, "%s: load ofsm settings\n", __func__); + dev_dbg(&dev->client->dev, "load ofsm settings\n"); switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: @@ -361,8 +357,7 @@ static int af9033_init(struct dvb_frontend *fe) goto err; /* load tuner specific settings */ - dev_dbg(&dev->client->dev, "%s: load tuner specific settings\n", - __func__); + dev_dbg(&dev->client->dev, "load tuner specific settings\n"); switch (dev->cfg.tuner) { case AF9033_TUNER_TUA9001: len = ARRAY_SIZE(tuner_init_tua9001); @@ -413,8 +408,8 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_62; break; default: - dev_dbg(&dev->client->dev, "%s: unsupported tuner ID=%d\n", - __func__, dev->cfg.tuner); + dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n", + dev->cfg.tuner); ret = -ENODEV; goto err; } @@ -451,7 +446,7 @@ static int af9033_init(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -478,7 +473,7 @@ static int af9033_sleep(struct dvb_frontend *fe) usleep_range(200, 10000); } - dev_dbg(&dev->client->dev, "%s: loop=%d\n", __func__, i); + dev_dbg(&dev->client->dev, "loop=%d\n", i); if (i == 0) { ret = -ETIMEDOUT; @@ -504,7 +499,7 @@ static int af9033_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -528,8 +523,8 @@ static int af9033_set_frontend(struct dvb_frontend *fe) u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; - dev_dbg(&dev->client->dev, "%s: frequency=%d bandwidth_hz=%d\n", - __func__, c->frequency, c->bandwidth_hz); + dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n", + c->frequency, c->bandwidth_hz); /* check bandwidth */ switch (c->bandwidth_hz) { @@ -543,8 +538,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) bandwidth_reg_val = 0x02; break; default: - dev_dbg(&dev->client->dev, "%s: invalid bandwidth_hz\n", - __func__); + dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n"); ret = -EINVAL; goto err; } @@ -646,7 +640,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -658,7 +652,7 @@ static int af9033_get_frontend(struct dvb_frontend *fe) int ret; u8 buf[8]; - dev_dbg(&dev->client->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); /* read all needed registers */ ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf)); @@ -773,7 +767,7 @@ static int af9033_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -819,7 +813,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -873,7 +867,7 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -895,7 +889,7 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -941,7 +935,7 @@ static int af9033_update_ch_stat(struct af9033_dev *dev) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -979,7 +973,7 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&dev->client->dev, "%s: enable=%d\n", __func__, enable); + dev_dbg(&dev->client->dev, "enable=%d\n", enable); ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01); if (ret < 0) @@ -988,7 +982,7 @@ static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -998,7 +992,7 @@ static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&dev->client->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&dev->client->dev, "onoff=%d\n", onoff); ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01); if (ret < 0) @@ -1007,7 +1001,7 @@ static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -1019,8 +1013,8 @@ static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int ret; u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - dev_dbg(&dev->client->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); + dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n", + index, pid, onoff); if (pid > 0x1fff) return 0; @@ -1040,7 +1034,7 @@ static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, return 0; err: - dev_dbg(&dev->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -1110,8 +1104,8 @@ static int af9033_probe(struct i2c_client *client, if (dev->cfg.clock != 12000000) { ret = -ENODEV; dev_err(&dev->client->dev, - "%s: af9033: unsupported clock=%d, only 12000000 Hz is supported currently\n", - KBUILD_MODNAME, dev->cfg.clock); + "unsupported clock %d Hz, only 12000000 Hz is supported currently\n", + dev->cfg.clock); goto err_kfree; } @@ -1139,9 +1133,9 @@ static int af9033_probe(struct i2c_client *client, goto err_kfree; dev_info(&dev->client->dev, - "%s: firmware version: LINK=%d.%d.%d.%d OFDM=%d.%d.%d.%d\n", - KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3], buf[4], - buf[5], buf[6], buf[7]); + "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], + buf[7]); /* sleep */ switch (dev->cfg.tuner) { @@ -1192,7 +1186,7 @@ static int af9033_probe(struct i2c_client *client, err_kfree: kfree(dev); err: - dev_dbg(&client->dev, "failed %d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -1200,7 +1194,7 @@ static int af9033_remove(struct i2c_client *client) { struct af9033_dev *dev = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&dev->client->dev, "\n"); dev->fe.ops.release = NULL; dev->fe.demodulator_priv = NULL; -- cgit v1.2.3 From ee36381ee8cec66ff976ad2c91e85dbee4a02859 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 22:17:12 -0300 Subject: [media] af9035: few small I2C master xfer changes Biggest problem of that function is complexity. Try reduce complexity: * define macros to detect all 3 supported xfers * remove duplicate message maximum size checks Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 37 +++++++++++++---------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 6534e44b42b6..ec621338a6ef 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -319,8 +319,14 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, * bus, having same slave address. Due to that we reuse demod address, * shifted by one bit, on that case. */ - if (num == 2 && !(msg[0].flags & I2C_M_RD) && - (msg[1].flags & I2C_M_RD)) { +#define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \ + (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD)) +#define AF9035_IS_I2C_XFER_WRITE(_msg, _num) \ + (_num == 1 && !(_msg[0].flags & I2C_M_RD)) +#define AF9035_IS_I2C_XFER_READ(_msg, _num) \ + (_num == 1 && (_msg[0].flags & I2C_M_RD)) + + if (AF9035_IS_I2C_XFER_WRITE_READ(msg, num)) { if (msg[0].len > 40 || msg[1].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; @@ -338,18 +344,11 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = af9035_rd_regs(d, reg, &msg[1].buf[0], msg[1].len); } else { - /* I2C */ + /* I2C write + read */ u8 buf[MAX_XFER_SIZE]; struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len, buf, msg[1].len, msg[1].buf }; - if (5 + msg[0].len > sizeof(buf)) { - dev_warn(&d->udev->dev, - "%s: i2c xfer: len=%d is too big!\n", - KBUILD_MODNAME, msg[0].len); - ret = -EOPNOTSUPP; - goto unlock; - } req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[1].len; buf[1] = msg[0].addr << 1; @@ -359,7 +358,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, memcpy(&buf[5], msg[0].buf, msg[0].len); ret = af9035_ctrl_msg(d, &req); } - } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + } else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) { if (msg[0].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; @@ -377,18 +376,11 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = af9035_wr_regs(d, reg, &msg[0].buf[3], msg[0].len - 3); } else { - /* I2C */ + /* I2C write */ u8 buf[MAX_XFER_SIZE]; struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len, buf, 0, NULL }; - if (5 + msg[0].len > sizeof(buf)) { - dev_warn(&d->udev->dev, - "%s: i2c xfer: len=%d is too big!\n", - KBUILD_MODNAME, msg[0].len); - ret = -EOPNOTSUPP; - goto unlock; - } req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; @@ -398,12 +390,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, memcpy(&buf[5], msg[0].buf, msg[0].len); ret = af9035_ctrl_msg(d, &req); } - } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { + } else if (AF9035_IS_I2C_XFER_READ(msg, num)) { if (msg[0].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; } else { - /* I2C */ + /* I2C read */ u8 buf[5]; struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), buf, msg[0].len, msg[0].buf }; @@ -418,14 +410,13 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, } else { /* * We support only three kind of I2C transactions: - * 1) 1 x read + 1 x write (repeated start) + * 1) 1 x write + 1 x read (repeated start) * 2) 1 x write * 3) 1 x read */ ret = -EOPNOTSUPP; } -unlock: mutex_unlock(&d->i2c_mutex); if (ret < 0) -- cgit v1.2.3 From a781edd16c9da9c3cd9ceea36c780895b87417d2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 31 Aug 2014 22:57:26 -0300 Subject: [media] af9033: remove I2C addr from config I2C driver address is passed as a i2c_new_device() parameter when device is created. Thus no need to keep it in config struct. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.h | 9 ++++----- drivers/media/usb/dvb-usb-v2/af9035.c | 29 ++++++++++++++--------------- drivers/media/usb/dvb-usb-v2/af9035.h | 1 + 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 1b968d0fcb17..6ad22b69a636 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -24,12 +24,11 @@ #include +/* + * I2C address (TODO: are these in 8-bit format?) + * 0x38, 0x3a, 0x3c, 0x3e + */ struct af9033_config { - /* - * I2C address - */ - u8 i2c_addr; - /* * clock Hz * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ec621338a6ef..b49170754a7c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -330,15 +330,15 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, if (msg[0].len > 40 || msg[1].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; - } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) || - (msg[0].addr == state->af9033_config[1].i2c_addr) || + } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || + (msg[0].addr == state->af9033_i2c_addr[1]) || (state->chip_type == 0x9135)) { /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; - if (msg[0].addr == state->af9033_config[1].i2c_addr || - msg[0].addr == (state->af9033_config[1].i2c_addr >> 1)) + if (msg[0].addr == state->af9033_i2c_addr[1] || + msg[0].addr == (state->af9033_i2c_addr[1] >> 1)) reg |= 0x100000; ret = af9035_rd_regs(d, reg, &msg[1].buf[0], @@ -362,15 +362,15 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, if (msg[0].len > 40) { /* TODO: correct limits > 40 */ ret = -EOPNOTSUPP; - } else if ((msg[0].addr == state->af9033_config[0].i2c_addr) || - (msg[0].addr == state->af9033_config[1].i2c_addr) || + } else if ((msg[0].addr == state->af9033_i2c_addr[0]) || + (msg[0].addr == state->af9033_i2c_addr[1]) || (state->chip_type == 0x9135)) { /* demod access via firmware interface */ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 | msg[0].buf[2]; - if (msg[0].addr == state->af9033_config[1].i2c_addr || - msg[0].addr == (state->af9033_config[1].i2c_addr >> 1)) + if (msg[0].addr == state->af9033_i2c_addr[1] || + msg[0].addr == (state->af9033_i2c_addr[1] >> 1)) reg |= 0x100000; ret = af9035_wr_regs(d, reg, &msg[0].buf[3], @@ -736,8 +736,8 @@ static int af9035_read_config(struct dvb_usb_device *d) u16 tmp16, addr; /* demod I2C "address" */ - state->af9033_config[0].i2c_addr = 0x38; - state->af9033_config[1].i2c_addr = 0x3a; + state->af9033_i2c_addr[0] = 0x38; + state->af9033_i2c_addr[1] = 0x3a; 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; @@ -789,7 +789,7 @@ static int af9035_read_config(struct dvb_usb_device *d) goto err; if (tmp) - state->af9033_config[1].i2c_addr = tmp; + state->af9033_i2c_addr[1] = tmp; dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n", __func__, tmp); @@ -1092,8 +1092,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) state->af9033_config[adap->id].fe = &adap->fe[0]; state->af9033_config[adap->id].ops = &state->ops; - ret = af9035_add_i2c_dev(d, "af9033", - state->af9033_config[adap->id].i2c_addr, + ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id], &state->af9033_config[adap->id]); if (ret) goto err; @@ -1348,7 +1347,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) } ret = af9035_add_i2c_dev(d, "it913x", - state->af9033_config[adap->id].i2c_addr >> 1, + state->af9033_i2c_addr[adap->id] >> 1, &it913x_config); if (ret) goto err; @@ -1373,7 +1372,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) } ret = af9035_add_i2c_dev(d, "it913x", - state->af9033_config[adap->id].i2c_addr >> 1, + state->af9033_i2c_addr[adap->id] >> 1, &it913x_config); if (ret) goto err; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 21960773df05..edb3871c50ea 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -61,6 +61,7 @@ struct state { u16 chip_type; u8 dual_mode:1; u16 eeprom_addr; + u8 af9033_i2c_addr[2]; struct af9033_config af9033_config[2]; struct af9033_ops ops; #define AF9035_I2C_CLIENT_MAX 4 -- cgit v1.2.3 From 5c114a4f88e0998aac77e7b22f992bcd4104334c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Sep 2014 00:38:01 -0300 Subject: [media] af9035: replace PCTV device model numbers with name Use device names for recent PCTV Systems devices: PCTV AndroiDTV (78e) PCTV microStick (79e) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index b49170754a7c..94563b2f1d48 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1728,9 +1728,9 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900, &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) }, { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_78E, - &af9035_props, "PCTV 78e", RC_MAP_IT913X_V1) }, + &af9035_props, "PCTV AndroiDTV (78e)", RC_MAP_IT913X_V1) }, { DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_79E, - &af9035_props, "PCTV 79e", RC_MAP_IT913X_V2) }, + &af9035_props, "PCTV microStick (79e)", RC_MAP_IT913X_V2) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); -- cgit v1.2.3 From 249c697e5e2c8e1347d79be0a9c93a985f2ad12e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 1 Sep 2014 19:44:59 -0300 Subject: [media] MAINTAINERS: IT913X driver filenames I removed tuner_ prefix from the driver file names. Update maintainers entry according to that. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fbc1af4fc870..6eb60a4e7339 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5066,7 +5066,7 @@ 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/tuner_it913x* +F: drivers/media/tuners/it913x* IVTV VIDEO4LINUX DRIVER M: Andy Walls -- cgit v1.2.3 From 83f1161911c5f32dc4cfa817a73ae028d32c43b7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Sep 2014 03:55:21 -0300 Subject: [media] af9033: implement DVBv5 statistics for signal strength Let the demod firmware estimate RF signal strength and return it to the app as a dBm. To handle that, use thread which reads signal strengths from firmware in 2 sec intervals when device is active. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 1bd5a9af7db5..b9a0b009aeda 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -28,13 +28,17 @@ struct af9033_dev { struct i2c_client *client; struct dvb_frontend fe; struct af9033_config cfg; + bool is_af9035; + bool is_it9135; u32 bandwidth_hz; bool ts_mode_parallel; bool ts_mode_serial; + fe_status_t fe_status; u32 ber; u32 ucb; + struct delayed_work stat_work; unsigned long last_stat_check; }; @@ -442,6 +446,8 @@ static int af9033_init(struct dvb_frontend *fe) } dev->bandwidth_hz = 0; /* force to program all parameters */ + /* start statistics polling */ + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); return 0; @@ -457,6 +463,9 @@ static int af9033_sleep(struct dvb_frontend *fe) int ret, i; u8 tmp; + /* stop statistics polling */ + cancel_delayed_work_sync(&dev->stat_work); + ret = af9033_wr_reg(dev, 0x80004c, 1); if (ret < 0) goto err; @@ -810,6 +819,8 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) FE_HAS_LOCK; } + dev->fe_status = *status; + return 0; err: @@ -1039,6 +1050,40 @@ err: return ret; } +static void af9033_stat_work(struct work_struct *work) +{ + struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work); + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret, tmp; + u8 u8tmp; + + dev_dbg(&dev->client->dev, "\n"); + + if (dev->fe_status & FE_HAS_SIGNAL) { + if (dev->is_af9035) { + ret = af9033_rd_reg(dev, 0x80004a, &u8tmp); + tmp = -u8tmp * 1000; + } else { + ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp); + tmp = (u8tmp - 100) * 1000; + } + if (ret) + goto err; + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = tmp; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + return; +err: + dev_dbg(&dev->client->dev, "failed=%d\n", ret); +} + static struct dvb_frontend_ops af9033_ops = { .delsys = { SYS_DVBT }, .info = { @@ -1099,6 +1144,7 @@ static int af9033_probe(struct i2c_client *client, /* setup the state */ dev->client = client; + INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work); memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); if (dev->cfg.clock != 12000000) { @@ -1117,9 +1163,11 @@ static int af9033_probe(struct i2c_client *client, case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: + dev->is_it9135 = true; reg = 0x004bfc; break; default: + dev->is_af9035 = true; reg = 0x0083e9; break; } -- cgit v1.2.3 From 3e41313aeadfc5e3b3f827519f3840bca1b98f6d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Sep 2014 04:24:41 -0300 Subject: [media] af9033: implement DVBv5 statistics for CNR Return CNR via DVBv5 statistics API. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 54 ++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index b9a0b009aeda..576e9b5f4bbf 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -1054,11 +1054,12 @@ static void af9033_stat_work(struct work_struct *work) { struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work); struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; - int ret, tmp; - u8 u8tmp; + int ret, tmp, i, len; + u8 u8tmp, buf[3]; dev_dbg(&dev->client->dev, "\n"); + /* signal strength */ if (dev->fe_status & FE_HAS_SIGNAL) { if (dev->is_af9035) { ret = af9033_rd_reg(dev, 0x80004a, &u8tmp); @@ -1078,6 +1079,55 @@ static void af9033_stat_work(struct work_struct *work) c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } + /* CNR */ + if (dev->fe_status & FE_HAS_VITERBI) { + u32 snr_val; + const struct val_snr *snr_lut; + + /* read value */ + ret = af9033_rd_regs(dev, 0x80002c, buf, 3); + if (ret) + goto err; + + snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); + + /* read current modulation */ + ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); + if (ret) + goto err; + + switch ((u8tmp >> 0) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; + break; + default: + goto err_schedule_delayed_work; + } + + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr * 1000; + if (snr_val < snr_lut[i].val) + break; + } + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = tmp; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + +err_schedule_delayed_work: schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); return; err: -- cgit v1.2.3 From 6b45778609dbe4e7d03abe9482a1a5621e2a3e64 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Sep 2014 05:03:21 -0300 Subject: [media] af9033: wrap DVBv3 read SNR to DVBv5 CNR Remove 'duplicate' DVBv3 read SNR implementation and return value, calculated already by DVBv5 CNR, from the cache. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 52 ++++--------------------------- drivers/media/dvb-frontends/af9033_priv.h | 1 + 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 576e9b5f4bbf..4c2061676bbe 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -832,55 +832,15 @@ err: static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9033_dev *dev = fe->demodulator_priv; - int ret, i, len; - u8 buf[3], tmp; - u32 snr_val; - const struct val_snr *snr_lut; - - /* read value */ - ret = af9033_rd_regs(dev, 0x80002c, buf, 3); - if (ret < 0) - goto err; - - snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - - /* read current modulation */ - ret = af9033_rd_reg(dev, 0x80f903, &tmp); - if (ret < 0) - goto err; - - switch ((tmp >> 0) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_lut); - snr_lut = qpsk_snr_lut; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_lut); - snr_lut = qam16_snr_lut; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_lut); - snr_lut = qam64_snr_lut; - break; - default: - goto err; - } - - for (i = 0; i < len; i++) { - tmp = snr_lut[i].snr; - - if (snr_val < snr_lut[i].val) - break; - } + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; - *snr = tmp * 10; /* dB/10 */ + /* use DVBv5 CNR */ + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */ + else + *snr = 0; return 0; - -err: - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - - return ret; } static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index ded7b67d7526..c12c92cb5855 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -24,6 +24,7 @@ #include "dvb_frontend.h" #include "af9033.h" +#include struct reg_val { u32 reg; -- cgit v1.2.3 From 204f4319289fcd45ae2d059a4cfc200c7754b050 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Sep 2014 08:01:10 -0300 Subject: [media] af9033: implement DVBv5 stat block counters Implement following API commands: DTV_STAT_ERROR_BLOCK_COUNT DTV_STAT_TOTAL_BLOCK_COUNT These returns total and uncorrected error packets from outer FEC. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 4c2061676bbe..7b853469bb3b 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -38,6 +38,8 @@ struct af9033_dev { fe_status_t fe_status; u32 ber; u32 ucb; + u64 error_block_count; + u64 total_block_count; struct delayed_work stat_work; unsigned long last_stat_check; }; @@ -1015,7 +1017,7 @@ static void af9033_stat_work(struct work_struct *work) struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work); struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; int ret, tmp, i, len; - u8 u8tmp, buf[3]; + u8 u8tmp, buf[7]; dev_dbg(&dev->client->dev, "\n"); @@ -1087,6 +1089,35 @@ static void af9033_stat_work(struct work_struct *work) c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } + /* UCB/PER/BER */ + if (dev->fe_status & FE_HAS_LOCK) { + /* outer FEC, 204 byte packets */ + u16 abort_packet_count, rsd_packet_count; + + /* + * Packet count used for measurement is 10000 + * (rsd_packet_count). Maybe it should be increased? + */ + + ret = af9033_rd_regs(dev, 0x800032, buf, 7); + if (ret) + goto err; + + abort_packet_count = (buf[1] << 8) | (buf[0] << 0); + rsd_packet_count = (buf[6] << 8) | (buf[5] << 0); + + dev->error_block_count += abort_packet_count; + dev->total_block_count += rsd_packet_count; + + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue = dev->total_block_count; + + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue = dev->error_block_count; + } + err_schedule_delayed_work: schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); return; -- cgit v1.2.3 From 6bb096c92671cad4a8cfcb8bf2a5309a9033faee Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 2 Sep 2014 08:29:46 -0300 Subject: [media] af9033: implement DVBv5 post-Viterbi BER Implement following DTV API commands: DTV_STAT_POST_ERROR_BIT_COUNT DTV_STAT_POST_TOTAL_BIT_COUNT These will provide post-Viterbi bit error rate reporting. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 7b853469bb3b..b6b90e61ed83 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -38,6 +38,8 @@ struct af9033_dev { fe_status_t fe_status; u32 ber; u32 ucb; + u64 post_bit_error; + u64 post_bit_count; u64 error_block_count; u64 total_block_count; struct delayed_work stat_work; @@ -1093,6 +1095,8 @@ static void af9033_stat_work(struct work_struct *work) if (dev->fe_status & FE_HAS_LOCK) { /* outer FEC, 204 byte packets */ u16 abort_packet_count, rsd_packet_count; + /* inner FEC, bits */ + u32 rsd_bit_err_count; /* * Packet count used for measurement is 10000 @@ -1104,10 +1108,13 @@ static void af9033_stat_work(struct work_struct *work) goto err; abort_packet_count = (buf[1] << 8) | (buf[0] << 0); + rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2]; rsd_packet_count = (buf[6] << 8) | (buf[5] << 0); dev->error_block_count += abort_packet_count; dev->total_block_count += rsd_packet_count; + dev->post_bit_error += rsd_bit_err_count; + dev->post_bit_count += rsd_packet_count * 204 * 8; c->block_count.len = 1; c->block_count.stat[0].scale = FE_SCALE_COUNTER; @@ -1116,6 +1123,14 @@ static void af9033_stat_work(struct work_struct *work) c->block_error.len = 1; c->block_error.stat[0].scale = FE_SCALE_COUNTER; c->block_error.stat[0].uvalue = dev->error_block_count; + + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; + + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; } err_schedule_delayed_work: -- cgit v1.2.3 From 1d0ceae4a19d318b443277ea6ac891a2e6e8fdc3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 3 Sep 2014 23:07:39 -0300 Subject: [media] af9033: wrap DVBv3 UCB to DVBv5 UCB stats Remove 'duplicate' DVBv3 read UCB implementation and return value, calculated already for DVBv5 statistics. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index b6b90e61ed83..673d60ef9654 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -932,14 +932,8 @@ static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct af9033_dev *dev = fe->demodulator_priv; - int ret; - - ret = af9033_update_ch_stat(dev); - if (ret < 0) - return ret; - - *ucblocks = dev->ucb; + *ucblocks = dev->error_block_count; return 0; } -- cgit v1.2.3 From e53c47445bb585f864dd861393691b1346f6ec80 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 3 Sep 2014 23:22:53 -0300 Subject: [media] af9033: wrap DVBv3 BER to DVBv5 BER DVBv5 BER is calculated anyway, so just return it for legacy read_ber() API too. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 673d60ef9654..f5267fdad75e 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -38,6 +38,7 @@ struct af9033_dev { fe_status_t fe_status; u32 ber; u32 ucb; + u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */ u64 post_bit_error; u64 post_bit_count; u64 error_block_count; @@ -918,13 +919,9 @@ err: static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9033_dev *dev = fe->demodulator_priv; - int ret; - - ret = af9033_update_ch_stat(dev); - if (ret < 0) - return ret; - *ber = dev->ber; + *ber = (dev->post_bit_error - dev->post_bit_error_prev); + dev->post_bit_error_prev = dev->post_bit_error; return 0; } -- cgit v1.2.3 From ef2fb46b6d7ed9df5906a3c76c9c4673355cd339 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 3 Sep 2014 23:30:44 -0300 Subject: [media] af9033: remove all DVBv3 stat calculation logic Statistics are now calculated for DVBv5 and those DVBv5 values are returned for legacy DVBv3 calls also. So we could remove all old statistics calculation logic. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 49 ------------------------------------ 1 file changed, 49 deletions(-) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index f5267fdad75e..be5002af70f7 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -36,15 +36,12 @@ struct af9033_dev { bool ts_mode_serial; fe_status_t fe_status; - u32 ber; - u32 ucb; u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */ u64 post_bit_error; u64 post_bit_count; u64 error_block_count; u64 total_block_count; struct delayed_work stat_work; - unsigned long last_stat_check; }; /* write multiple registers */ @@ -870,52 +867,6 @@ err: return ret; } -static int af9033_update_ch_stat(struct af9033_dev *dev) -{ - int ret = 0; - u32 err_cnt, bit_cnt; - u16 abort_cnt; - u8 buf[7]; - - /* only update data every half second */ - if (time_after(jiffies, dev->last_stat_check + msecs_to_jiffies(500))) { - ret = af9033_rd_regs(dev, 0x800032, buf, sizeof(buf)); - if (ret < 0) - goto err; - /* in 8 byte packets? */ - abort_cnt = (buf[1] << 8) + buf[0]; - /* in bits */ - err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2]; - /* in 8 byte packets? always(?) 0x2710 = 10000 */ - bit_cnt = (buf[6] << 8) + buf[5]; - - if (bit_cnt < abort_cnt) { - abort_cnt = 1000; - dev->ber = 0xffffffff; - } else { - /* - * 8 byte packets, that have not been rejected already - */ - bit_cnt -= (u32)abort_cnt; - if (bit_cnt == 0) { - dev->ber = 0xffffffff; - } else { - err_cnt -= (u32)abort_cnt * 8 * 8; - bit_cnt *= 8 * 8; - dev->ber = err_cnt * (0xffffffff / bit_cnt); - } - } - dev->ucb += abort_cnt; - dev->last_stat_check = jiffies; - } - - return 0; -err: - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - - return ret; -} - static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9033_dev *dev = fe->demodulator_priv; -- cgit v1.2.3 From ca42129f867fbc427d709408b3ae35988cc08ed4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 4 Sep 2014 17:04:44 -0300 Subject: [media] dvb-usb-v2: add frontend_detach callback Add frontend_detach callback in order to allow custom detach. It is needed when demod driver is implemented I2C client or some other kernel bus, but not proprietary dvb_attach / dvb_detach. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 2 ++ drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 124b4baa7e97..7e36ee02f957 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -214,6 +214,7 @@ struct dvb_usb_adapter_properties { * @read_config: called to resolve device configuration * @read_mac_address: called to resolve adapter mac-address * @frontend_attach: called to attach the possible frontends + * @frontend_detach: called to detach the possible frontends * @tuner_attach: called to attach the possible tuners * @frontend_ctrl: called to power on/off active frontend * @streaming_ctrl: called to start/stop the usb streaming of adapter @@ -254,6 +255,7 @@ struct dvb_usb_device_properties { int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); int (*frontend_attach) (struct dvb_usb_adapter *); + int (*frontend_detach)(struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_frontend *, int); 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 adca05f27fba..02c43b52c906 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -664,9 +664,10 @@ err: static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - int i; - dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, - adap->id); + int ret, i; + struct dvb_usb_device *d = adap_to_d(adap); + + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { if (adap->fe[i]) { @@ -675,6 +676,15 @@ static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) } } + if (d->props->frontend_detach) { + ret = d->props->frontend_detach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, + "%s: frontend_detach() failed=%d\n", + __func__, ret); + } + } + return 0; } -- cgit v1.2.3 From 1066d77f682e84efb56fbd4e5c8bb236532eccc7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 4 Sep 2014 18:31:40 -0300 Subject: [media] dvb-usb-v2: add tuner_detach callback Add tuner_detach callback in order to allow custom detach. It is needed when tuner driver is implemented I2C client or some other kernel bus, but not proprietary dvb_attach / dvb_detach. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 1 + drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 7e36ee02f957..14e111e13e54 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -257,6 +257,7 @@ struct dvb_usb_device_properties { int (*frontend_attach) (struct dvb_usb_adapter *); int (*frontend_detach)(struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); + int (*tuner_detach)(struct dvb_usb_adapter *); int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_frontend *, int); int (*init) (struct dvb_usb_device *); 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 02c43b52c906..1950f37df835 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -676,6 +676,14 @@ static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) } } + if (d->props->tuner_detach) { + ret = d->props->tuner_detach(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: tuner_detach() failed=%d\n", + __func__, ret); + } + } + if (d->props->frontend_detach) { ret = d->props->frontend_detach(adap); if (ret < 0) { -- cgit v1.2.3 From d4d6a34d36b1e72d0c5cf470a41fc7bc79acd73f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 4 Sep 2014 18:35:59 -0300 Subject: [media] af9035: remove I2C client differently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It crash kernel when device was removed while it was streaming. That is because we removed driver and frontend thread was still running. Use new callback which allows I2C driver removal just after frontend is unregistered. V2: fixed by reported by Daniel Reported-by: Daniel Glöckner Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 93 +++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 26 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 94563b2f1d48..440ecb459b9c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1074,15 +1074,13 @@ static int af9035_get_adapter_count(struct dvb_usb_device *d) return state->dual_mode + 1; } -static void af9035_exit(struct dvb_usb_device *d); - 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__); + dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); if (!state->af9033_config[adap->id].tuner) { /* unsupported tuner */ @@ -1109,12 +1107,48 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) return 0; err: - af9035_exit(d); /* remove I2C clients */ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } +static int af9035_frontend_detach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int demod2; + + dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); + + /* + * For dual tuner devices we have to resolve 2nd demod client, as there + * is two different kind of tuner drivers; one is using I2C binding + * and the other is using DVB attach/detach binding. + */ + switch (state->af9033_config[adap->id].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: + demod2 = 2; + break; + default: + demod2 = 1; + } + + if (adap->id == 1) { + if (state->i2c_client[demod2]) + af9035_del_i2c_dev(d); + } else if (adap->id == 0) { + if (state->i2c_client[0]) + af9035_del_i2c_dev(d); + } + + return 0; +} + static struct tua9001_config af9035_tua9001_config = { .i2c_addr = 0x60, }; @@ -1174,7 +1208,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_msg msg[1]; u8 tuner_addr; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); /* * XXX: Hack used in that function: we abuse unused I2C address bit [7] @@ -1392,12 +1426,37 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) return 0; err: - af9035_exit(d); /* remove I2C clients */ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } +static int af9035_tuner_detach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + + dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); + + switch (state->af9033_config[adap->id].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: + if (adap->id == 1) { + if (state->i2c_client[3]) + af9035_del_i2c_dev(d); + } else if (adap->id == 0) { + if (state->i2c_client[1]) + af9035_del_i2c_dev(d); + } + } + + return 0; +} + static int af9035_init(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); @@ -1445,25 +1504,6 @@ err: return ret; } -static void af9035_exit(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - if (state->i2c_client[3]) - af9035_del_i2c_dev(d); - - if (state->i2c_client[2]) - af9035_del_i2c_dev(d); - - if (state->i2c_client[1]) - af9035_del_i2c_dev(d); - - if (state->i2c_client[0]) - af9035_del_i2c_dev(d); -} - #if IS_ENABLED(CONFIG_RC_CORE) static int af9035_rc_query(struct dvb_usb_device *d) { @@ -1636,11 +1676,12 @@ static const struct dvb_usb_device_properties af9035_props = { .i2c_algo = &af9035_i2c_algo, .read_config = af9035_read_config, .frontend_attach = af9035_frontend_attach, + .frontend_detach = af9035_frontend_detach, .tuner_attach = af9035_tuner_attach, + .tuner_detach = af9035_tuner_detach, .init = af9035_init, .get_rc_config = af9035_get_rc_config, .get_stream_config = af9035_get_stream_config, - .exit = af9035_exit, .get_adapter_count = af9035_get_adapter_count, .adapter = { -- cgit v1.2.3 From 2db4d179e16d0fcc1ece25798a8e140fa4f9c18a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 6 Sep 2014 11:24:14 -0300 Subject: [media] af9033: init DVBv5 statistics We need to init supported stats here in order signal app which stats are supported. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index be5002af70f7..63a89c1c59ff 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -238,6 +238,7 @@ static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) static int af9033_init(struct dvb_frontend *fe) { struct af9033_dev *dev = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; const struct reg_val *init; u8 buf[4]; @@ -448,6 +449,19 @@ static int af9033_init(struct dvb_frontend *fe) } dev->bandwidth_hz = 0; /* force to program all parameters */ + /* init stats here in order signal app which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; /* start statistics polling */ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); -- cgit v1.2.3 From 3ab779c0399276c82a6a64610e7c9c4d5bb267f2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 22:43:26 -0300 Subject: [media] tda18212: prepare for I2C client conversion We need carry pointer to frontend via config struct (I2C platform_data ptr) when I2C model is used. Add that pointer first in order to keep build unbreakable during conversion. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18212.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h index c36b49e4b274..265559a4306d 100644 --- a/drivers/media/tuners/tda18212.h +++ b/drivers/media/tuners/tda18212.h @@ -37,6 +37,11 @@ struct tda18212_config { u16 if_dvbc; u16 if_atsc_vsb; u16 if_atsc_qam; + + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; }; #if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212) -- cgit v1.2.3 From f80f2ae2135966dcd21020dcdca066d3fe5f06df Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 21:47:10 -0300 Subject: [media] anysee: convert tda18212 tuner to I2C client Used tda18212 tuner is implemented as I2C driver. Implement I2C client to anysee and use it for tda18212. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/anysee.c | 185 +++++++++++++++++++++++++++------- drivers/media/usb/dvb-usb-v2/anysee.h | 3 + 2 files changed, 152 insertions(+), 36 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index e4a2382196f0..d3c5f230e97a 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -332,7 +332,6 @@ static struct tda10023_config anysee_tda10023_tda18212_config = { }; static struct tda18212_config anysee_tda18212_config = { - .i2c_address = (0xc0 >> 1), .if_dvbt_6 = 4150, .if_dvbt_7 = 4150, .if_dvbt_8 = 4150, @@ -340,7 +339,6 @@ static struct tda18212_config anysee_tda18212_config = { }; static struct tda18212_config anysee_tda18212_config2 = { - .i2c_address = 0x60 /* (0xc0 >> 1) */, .if_dvbt_6 = 3550, .if_dvbt_7 = 3700, .if_dvbt_8 = 4150, @@ -632,6 +630,92 @@ error: return ret; } +static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr, + void *platform_data) +{ + int ret, num; + struct anysee_state *state = d_to_priv(d); + struct i2c_client *client; + struct i2c_adapter *adapter = &d->i2c_adap; + struct i2c_board_info board_info = { + .addr = addr, + .platform_data = platform_data, + }; + + strlcpy(board_info.type, type, I2C_NAME_SIZE); + + /* find first free client */ + for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) { + if (state->i2c_client[num] == NULL) + break; + } + + dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); + + if (num == ANYSEE_I2C_CLIENT_MAX) { + dev_err(&d->udev->dev, "%s: I2C client out of index\n", + KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + request_module(board_info.type); + + /* register I2C device */ + client = i2c_new_device(adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) { + ret = -ENODEV; + goto err; + } + + /* increase I2C driver usage count */ + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + ret = -ENODEV; + goto err; + } + + state->i2c_client[num] = client; + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + +static void anysee_del_i2c_dev(struct dvb_usb_device *d) +{ + int num; + struct anysee_state *state = d_to_priv(d); + struct i2c_client *client; + + /* find last used client */ + num = ANYSEE_I2C_CLIENT_MAX; + while (num--) { + if (state->i2c_client[num] != NULL) + break; + } + + dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); + + if (num == -1) { + dev_err(&d->udev->dev, "%s: I2C client out of index\n", + KBUILD_MODNAME); + goto err; + } + + client = state->i2c_client[num]; + + /* decrease I2C driver usage count */ + module_put(client->dev.driver->owner); + + /* unregister I2C device */ + i2c_unregister_device(client); + + state->i2c_client[num] = NULL; +err: + dev_dbg(&d->udev->dev, "%s: failed\n", __func__); +} + static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { struct anysee_state *state = adap_to_priv(adap); @@ -640,12 +724,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) u8 tmp; struct i2c_msg msg[2] = { { - .addr = anysee_tda18212_config.i2c_address, + .addr = 0x60, .flags = 0, .len = 1, .buf = "\x00", }, { - .addr = anysee_tda18212_config.i2c_address, + .addr = 0x60, .flags = I2C_M_RD, .len = 1, .buf = &tmp, @@ -723,9 +807,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* probe TDA18212 */ tmp = 0; ret = i2c_transfer(&d->i2c_adap, msg, 2); - if (ret == 2 && tmp == 0xc7) + if (ret == 2 && tmp == 0xc7) { dev_dbg(&d->udev->dev, "%s: TDA18212 found\n", __func__); + state->has_tda18212 = true; + } else tmp = 0; @@ -939,46 +1025,63 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) * fails attach old simple PLL. */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); + if (state->has_tda18212) { + struct tda18212_config tda18212_config = + anysee_tda18212_config; - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); - break; - } else if (fe) { - break; - } - - /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + tda18212_config.fe = adap->fe[0]; + ret = anysee_add_i2c_dev(d, "tda18212", 0x60, + &tda18212_config); + if (ret) + goto err; + + /* copy tuner ops for 2nd FE as tuner is shared */ + if (adap->fe[1]) { + adap->fe[1]->tuner_priv = + adap->fe[0]->tuner_priv; + memcpy(&adap->fe[1]->ops.tuner_ops, + &adap->fe[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } - if (fe && adap->fe[1]) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(dvb_pll_attach, adap->fe[1], + return 0; + } else { + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(dvb_pll_attach, adap->fe[1], + (0xc0 >> 1), &d->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); + } } break; case ANYSEE_HW_508TC: /* 18 */ case ANYSEE_HW_508PTC: /* 21 */ + { /* E7 TC */ /* E7 PTC */ + struct tda18212_config tda18212_config = anysee_tda18212_config; - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config); - - if (fe) { - /* attach tuner for 2nd FE */ - fe = dvb_attach(tda18212_attach, adap->fe[1], - &d->i2c_adap, &anysee_tda18212_config); + tda18212_config.fe = adap->fe[0]; + ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config); + if (ret) + goto err; + + /* copy tuner ops for 2nd FE as tuner is shared */ + if (adap->fe[1]) { + adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv; + memcpy(&adap->fe[1]->ops.tuner_ops, + &adap->fe[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); } - break; + return 0; + } case ANYSEE_HW_508S2: /* 19 */ case ANYSEE_HW_508PS2: /* 22 */ /* E7 S2 */ @@ -997,13 +1100,18 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) break; case ANYSEE_HW_508T2C: /* 20 */ + { /* E7 T2C */ + struct tda18212_config tda18212_config = + anysee_tda18212_config2; - /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, - &anysee_tda18212_config2); + tda18212_config.fe = adap->fe[0]; + ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config); + if (ret) + goto err; - break; + return 0; + } default: fe = NULL; } @@ -1012,7 +1120,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) ret = 0; else ret = -ENODEV; - +err: return ret; } @@ -1270,6 +1378,11 @@ static int anysee_init(struct dvb_usb_device *d) static void anysee_exit(struct dvb_usb_device *d) { + struct anysee_state *state = d_to_priv(d); + + if (state->i2c_client[0]) + anysee_del_i2c_dev(d); + return anysee_ci_release(d); } diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h index 8f426d9fc6e1..3ca2bca4ebaf 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.h +++ b/drivers/media/usb/dvb-usb-v2/anysee.h @@ -55,8 +55,11 @@ struct anysee_state { u8 buf[64]; u8 seq; u8 hw; /* PCB ID */ + #define ANYSEE_I2C_CLIENT_MAX 1 + struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX]; u8 fe_id:1; /* frondend ID */ u8 has_ci:1; + u8 has_tda18212:1; u8 ci_attached:1; struct dvb_ca_en50221 ci; unsigned long ci_cam_ready; /* jiffies */ -- cgit v1.2.3 From ac7a24fb7560217381d996aae68eda57bbce462a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 22:35:03 -0300 Subject: [media] em28xx: convert tda18212 tuner to I2C client Used tda18212 tuner is implemented as a I2C driver. Use em28xx tuner I2C client for tda18212 driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 06457934a48c..9682c52d67d1 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -373,7 +373,6 @@ static struct tda18271_config kworld_ub435q_v2_config = { }; static struct tda18212_config kworld_ub435q_v3_config = { - .i2c_address = 0x60, .if_atsc_vsb = 3600, .if_atsc_qam = 3600, }; @@ -1437,6 +1436,15 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; case EM2874_BOARD_KWORLD_UB435Q_V3: + { + struct i2c_client *client; + struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus]; + struct i2c_board_info board_info = { + .type = "tda18212", + .addr = 0x60, + .platform_data = &kworld_ub435q_v3_config, + }; + dvb->fe[0] = dvb_attach(lgdt3305_attach, &em2874_lgdt3305_nogate_dev, &dev->i2c_adap[dev->def_i2c_bus]); @@ -1445,14 +1453,26 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } - /* Attach the demodulator. */ - if (!dvb_attach(tda18212_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], - &kworld_ub435q_v3_config)) { - result = -EINVAL; + /* attach tuner */ + kworld_ub435q_v3_config.fe = dvb->fe[0]; + request_module("tda18212"); + client = i2c_new_device(adapter, &board_info); + if (client == NULL || client->dev.driver == NULL) { + dvb_frontend_detach(dvb->fe[0]); + result = -ENODEV; goto out_free; } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dvb_frontend_detach(dvb->fe[0]); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; break; + } case EM2874_BOARD_PCTV_HD_MINI_80E: dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0] != NULL) { -- cgit v1.2.3 From 0e584cc29567f9ad248420f9cbd35c0ae3b5e821 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 23:05:31 -0300 Subject: [media] tda18212: convert driver to I2C binding Convert driver from DVB proprietary model to common I2C model. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18212.c | 129 ++++++++++++++++++++++++---------------- drivers/media/tuners/tda18212.h | 14 ----- 2 files changed, 79 insertions(+), 64 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 15b09f8d85c0..659787b805a3 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -24,8 +24,8 @@ #define MAX_XFER_SIZE 64 struct tda18212_priv { - struct tda18212_config *cfg; - struct i2c_adapter *i2c; + struct tda18212_config cfg; + struct i2c_client *client; u32 if_frequency; }; @@ -38,7 +38,7 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->cfg->i2c_address, + .addr = priv->client->addr, .flags = 0, .len = 1 + len, .buf = buf, @@ -46,7 +46,7 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, }; if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -55,12 +55,12 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -74,12 +74,12 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[2] = { { - .addr = priv->cfg->i2c_address, + .addr = priv->client->addr, .flags = 0, .len = 1, .buf = ®, }, { - .addr = priv->cfg->i2c_address, + .addr = priv->client->addr, .flags = I2C_M_RD, .len = len, .buf = buf, @@ -87,19 +87,19 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, }; if (len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c rd reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; } - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->client->adapter, msg, 2); if (ret == 2) { memcpy(val, buf, len); ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%02x len=%d\n", + KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -166,7 +166,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) [ATSC_QAM] = { 0x7d, 0x20, 0x63 }, }; - dev_dbg(&priv->i2c->dev, + dev_dbg(&priv->client->dev, "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", __func__, c->delivery_system, c->frequency, c->bandwidth_hz); @@ -176,25 +176,25 @@ static int tda18212_set_params(struct dvb_frontend *fe) switch (c->delivery_system) { case SYS_ATSC: - if_khz = priv->cfg->if_atsc_vsb; + if_khz = priv->cfg.if_atsc_vsb; i = ATSC_VSB; break; case SYS_DVBC_ANNEX_B: - if_khz = priv->cfg->if_atsc_qam; + if_khz = priv->cfg.if_atsc_qam; i = ATSC_QAM; break; case SYS_DVBT: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg->if_dvbt_6; + if_khz = priv->cfg.if_dvbt_6; i = DVBT_6; break; case 7000000: - if_khz = priv->cfg->if_dvbt_7; + if_khz = priv->cfg.if_dvbt_7; i = DVBT_7; break; case 8000000: - if_khz = priv->cfg->if_dvbt_8; + if_khz = priv->cfg.if_dvbt_8; i = DVBT_8; break; default: @@ -205,15 +205,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) case SYS_DVBT2: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg->if_dvbt2_6; + if_khz = priv->cfg.if_dvbt2_6; i = DVBT2_6; break; case 7000000: - if_khz = priv->cfg->if_dvbt2_7; + if_khz = priv->cfg.if_dvbt2_7; i = DVBT2_7; break; case 8000000: - if_khz = priv->cfg->if_dvbt2_8; + if_khz = priv->cfg.if_dvbt2_8; i = DVBT2_8; break; default: @@ -223,7 +223,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) break; case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: - if_khz = priv->cfg->if_dvbc; + if_khz = priv->cfg.if_dvbc; i = DVBC_8; break; default: @@ -266,7 +266,7 @@ exit: return ret; error: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); goto exit; } @@ -279,13 +279,6 @@ static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int tda18212_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops tda18212_tuner_ops = { .info = { .name = "NXP TDA18212", @@ -295,34 +288,36 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = { .frequency_step = 1000, }, - .release = tda18212_release, - .set_params = tda18212_set_params, .get_if_frequency = tda18212_get_if_frequency, }; -struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) +static int tda18212_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct tda18212_priv *priv = NULL; + struct tda18212_config *cfg = client->dev.platform_data; + struct dvb_frontend *fe = cfg->fe; + struct tda18212_priv *priv; int ret; u8 chip_id = chip_id; char *version; - priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + goto err; + } - priv->cfg = cfg; - priv->i2c = i2c; - fe->tuner_priv = priv; + memcpy(&priv->cfg, cfg, sizeof(struct tda18212_config)); + priv->client = client; + /* check if the tuner is there */ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - /* check if the tuner is there */ ret = tda18212_rd_reg(priv, 0x00, &chip_id); - dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ @@ -338,23 +333,57 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, version = "S"; /* slave */ break; default: + ret = -ENODEV; goto err; } - dev_info(&priv->i2c->dev, + dev_info(&priv->client->dev, "%s: NXP TDA18212HN/%s successfully identified\n", KBUILD_MODNAME, version); + fe->tuner_priv = priv; memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, - sizeof(struct dvb_tuner_ops)); + sizeof(struct dvb_tuner_ops)); + i2c_set_clientdata(client, priv); - return fe; + return 0; err: - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); kfree(priv); - return NULL; + return ret; } -EXPORT_SYMBOL(tda18212_attach); + +static int tda18212_remove(struct i2c_client *client) +{ + struct tda18212_priv *priv = i2c_get_clientdata(client); + struct dvb_frontend *fe = priv->cfg.fe; + + dev_dbg(&client->dev, "%s:\n", __func__); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(priv); + + return 0; +} + +static const struct i2c_device_id tda18212_id[] = { + {"tda18212", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tda18212_id); + +static struct i2c_driver tda18212_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tda18212", + }, + .probe = tda18212_probe, + .remove = tda18212_remove, + .id_table = tda18212_id, +}; + +module_i2c_driver(tda18212_driver); MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h index 265559a4306d..e58c9096d79c 100644 --- a/drivers/media/tuners/tda18212.h +++ b/drivers/media/tuners/tda18212.h @@ -25,8 +25,6 @@ #include "dvb_frontend.h" struct tda18212_config { - u8 i2c_address; - u16 if_dvbt_6; u16 if_dvbt_7; u16 if_dvbt_8; @@ -44,16 +42,4 @@ struct tda18212_config { struct dvb_frontend *fe; }; -#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 -static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, struct tda18212_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - #endif -- cgit v1.2.3 From bdb32655f2fa5055cad1145dac17b76243d20a02 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 23:26:27 -0300 Subject: [media] tda18212: clean logging There is no need to print module name nor function name as those are done by kernel logging system when dev_xxx logging is used and driver is proper I2C driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18212.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 659787b805a3..5d1d78595c86 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -47,8 +47,8 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, if (1 + len > sizeof(buf)) { dev_warn(&priv->client->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); + "i2c wr reg=%04x: len=%d is too big!\n", + reg, len); return -EINVAL; } @@ -59,8 +59,9 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, if (ret == 1) { ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->client->dev, + "i2c wr failed=%d reg=%02x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -88,8 +89,8 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, if (len > sizeof(buf)) { dev_warn(&priv->client->dev, - "%s: i2c rd reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); + "i2c rd reg=%04x: len=%d is too big!\n", + reg, len); return -EINVAL; } @@ -98,8 +99,9 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, memcpy(val, buf, len); ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); + dev_warn(&priv->client->dev, + "i2c rd failed=%d reg=%02x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -167,8 +169,8 @@ static int tda18212_set_params(struct dvb_frontend *fe) }; dev_dbg(&priv->client->dev, - "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", - __func__, c->delivery_system, c->frequency, + "delivery_system=%d frequency=%d bandwidth_hz=%d\n", + c->delivery_system, c->frequency, c->bandwidth_hz); if (fe->ops.i2c_gate_ctrl) @@ -266,7 +268,7 @@ exit: return ret; error: - dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&priv->client->dev, "failed=%d\n", ret); goto exit; } @@ -305,7 +307,7 @@ static int tda18212_probe(struct i2c_client *client, priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -317,7 +319,7 @@ static int tda18212_probe(struct i2c_client *client, fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ ret = tda18212_rd_reg(priv, 0x00, &chip_id); - dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id); + dev_dbg(&priv->client->dev, "chip_id=%02x\n", chip_id); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ @@ -338,8 +340,7 @@ static int tda18212_probe(struct i2c_client *client, } dev_info(&priv->client->dev, - "%s: NXP TDA18212HN/%s successfully identified\n", - KBUILD_MODNAME, version); + "NXP TDA18212HN/%s successfully identified\n", version); fe->tuner_priv = priv; memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, @@ -348,7 +349,7 @@ static int tda18212_probe(struct i2c_client *client, return 0; err: - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); kfree(priv); return ret; } @@ -358,7 +359,7 @@ static int tda18212_remove(struct i2c_client *client) struct tda18212_priv *priv = i2c_get_clientdata(client); struct dvb_frontend *fe = priv->cfg.fe; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; -- cgit v1.2.3 From e4a42e1866edf68c7ddfc42b07676238af49f4df Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Aug 2014 23:40:23 -0300 Subject: [media] tda18212: rename state from 'priv' to 'dev' foo_dev seems to be most correct term for the structure holding data of each device instance. It is most used term in Kernel codebase and also examples from book Linux Device Drivers, Third Edition, uses it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18212.c | 104 ++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 5d1d78595c86..24948c7971e3 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -23,7 +23,7 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 -struct tda18212_priv { +struct tda18212_dev { struct tda18212_config cfg; struct i2c_client *client; @@ -31,14 +31,13 @@ struct tda18212_priv { }; /* write multiple registers */ -static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) +static int tda18212_wr_regs(struct tda18212_dev *dev, u8 reg, u8 *val, int len) { int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = 0, .len = 1 + len, .buf = buf, @@ -46,7 +45,7 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, }; if (1 + len > sizeof(buf)) { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "i2c wr reg=%04x: len=%d is too big!\n", reg, len); return -EINVAL; @@ -55,11 +54,11 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, buf[0] = reg; memcpy(&buf[1], val, len); - ret = i2c_transfer(priv->client->adapter, msg, 1); + ret = i2c_transfer(dev->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%02x len=%d\n", ret, reg, len); ret = -EREMOTEIO; @@ -68,19 +67,18 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, } /* read multiple registers */ -static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, - int len) +static int tda18212_rd_regs(struct tda18212_dev *dev, u8 reg, u8 *val, int len) { int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[2] = { { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = 0, .len = 1, .buf = ®, }, { - .addr = priv->client->addr, + .addr = dev->client->addr, .flags = I2C_M_RD, .len = len, .buf = buf, @@ -88,18 +86,18 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, }; if (len > sizeof(buf)) { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "i2c rd reg=%04x: len=%d is too big!\n", reg, len); return -EINVAL; } - ret = i2c_transfer(priv->client->adapter, msg, 2); + ret = i2c_transfer(dev->client->adapter, msg, 2); if (ret == 2) { memcpy(val, buf, len); ret = 0; } else { - dev_warn(&priv->client->dev, + dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%02x len=%d\n", ret, reg, len); ret = -EREMOTEIO; @@ -109,26 +107,26 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, } /* write single register */ -static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) +static int tda18212_wr_reg(struct tda18212_dev *dev, u8 reg, u8 val) { - return tda18212_wr_regs(priv, reg, &val, 1); + return tda18212_wr_regs(dev, reg, &val, 1); } /* read single register */ -static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) +static int tda18212_rd_reg(struct tda18212_dev *dev, u8 reg, u8 *val) { - return tda18212_rd_regs(priv, reg, val, 1); + return tda18212_rd_regs(dev, reg, val, 1); } #if 0 /* keep, useful when developing driver */ -static void tda18212_dump_regs(struct tda18212_priv *priv) +static void tda18212_dump_regs(struct tda18212_dev *dev) { int i; u8 buf[256]; #define TDA18212_RD_LEN 32 for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) - tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); + tda18212_rd_regs(dev, i, &buf[i], TDA18212_RD_LEN); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, sizeof(buf), true); @@ -139,7 +137,7 @@ static void tda18212_dump_regs(struct tda18212_priv *priv) static int tda18212_set_params(struct dvb_frontend *fe) { - struct tda18212_priv *priv = fe->tuner_priv; + struct tda18212_dev *dev = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_khz; @@ -168,7 +166,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) [ATSC_QAM] = { 0x7d, 0x20, 0x63 }, }; - dev_dbg(&priv->client->dev, + dev_dbg(&dev->client->dev, "delivery_system=%d frequency=%d bandwidth_hz=%d\n", c->delivery_system, c->frequency, c->bandwidth_hz); @@ -178,25 +176,25 @@ static int tda18212_set_params(struct dvb_frontend *fe) switch (c->delivery_system) { case SYS_ATSC: - if_khz = priv->cfg.if_atsc_vsb; + if_khz = dev->cfg.if_atsc_vsb; i = ATSC_VSB; break; case SYS_DVBC_ANNEX_B: - if_khz = priv->cfg.if_atsc_qam; + if_khz = dev->cfg.if_atsc_qam; i = ATSC_QAM; break; case SYS_DVBT: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg.if_dvbt_6; + if_khz = dev->cfg.if_dvbt_6; i = DVBT_6; break; case 7000000: - if_khz = priv->cfg.if_dvbt_7; + if_khz = dev->cfg.if_dvbt_7; i = DVBT_7; break; case 8000000: - if_khz = priv->cfg.if_dvbt_8; + if_khz = dev->cfg.if_dvbt_8; i = DVBT_8; break; default: @@ -207,15 +205,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) case SYS_DVBT2: switch (c->bandwidth_hz) { case 6000000: - if_khz = priv->cfg.if_dvbt2_6; + if_khz = dev->cfg.if_dvbt2_6; i = DVBT2_6; break; case 7000000: - if_khz = priv->cfg.if_dvbt2_7; + if_khz = dev->cfg.if_dvbt2_7; i = DVBT2_7; break; case 8000000: - if_khz = priv->cfg.if_dvbt2_8; + if_khz = dev->cfg.if_dvbt2_8; i = DVBT2_8; break; default: @@ -225,7 +223,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) break; case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: - if_khz = priv->cfg.if_dvbc; + if_khz = dev->cfg.if_dvbc; i = DVBC_8; break; default: @@ -233,15 +231,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) goto error; } - ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); + ret = tda18212_wr_reg(dev, 0x23, bw_params[i][2]); if (ret) goto error; - ret = tda18212_wr_reg(priv, 0x06, 0x00); + ret = tda18212_wr_reg(dev, 0x06, 0x00); if (ret) goto error; - ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); + ret = tda18212_wr_reg(dev, 0x0f, bw_params[i][0]); if (ret) goto error; @@ -254,12 +252,12 @@ static int tda18212_set_params(struct dvb_frontend *fe) buf[6] = ((c->frequency / 1000) >> 0) & 0xff; buf[7] = 0xc1; buf[8] = 0x01; - ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); + ret = tda18212_wr_regs(dev, 0x12, buf, sizeof(buf)); if (ret) goto error; /* actual IF rounded as it is on register */ - priv->if_frequency = buf[3] * 50 * 1000; + dev->if_frequency = buf[3] * 50 * 1000; exit: if (fe->ops.i2c_gate_ctrl) @@ -268,15 +266,15 @@ exit: return ret; error: - dev_dbg(&priv->client->dev, "failed=%d\n", ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); goto exit; } static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct tda18212_priv *priv = fe->tuner_priv; + struct tda18212_dev *dev = fe->tuner_priv; - *frequency = priv->if_frequency; + *frequency = dev->if_frequency; return 0; } @@ -299,27 +297,27 @@ static int tda18212_probe(struct i2c_client *client, { struct tda18212_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct tda18212_priv *priv; + struct tda18212_dev *dev; int ret; u8 chip_id = chip_id; char *version; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - memcpy(&priv->cfg, cfg, sizeof(struct tda18212_config)); - priv->client = client; + memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config)); + dev->client = client; /* check if the tuner is there */ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - ret = tda18212_rd_reg(priv, 0x00, &chip_id); - dev_dbg(&priv->client->dev, "chip_id=%02x\n", chip_id); + ret = tda18212_rd_reg(dev, 0x00, &chip_id); + dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ @@ -339,31 +337,31 @@ static int tda18212_probe(struct i2c_client *client, goto err; } - dev_info(&priv->client->dev, + dev_info(&dev->client->dev, "NXP TDA18212HN/%s successfully identified\n", version); - fe->tuner_priv = priv; + fe->tuner_priv = dev; memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, sizeof(struct dvb_tuner_ops)); - i2c_set_clientdata(client, priv); + i2c_set_clientdata(client, dev); return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(priv); + kfree(dev); return ret; } static int tda18212_remove(struct i2c_client *client) { - struct tda18212_priv *priv = i2c_get_clientdata(client); - struct dvb_frontend *fe = priv->cfg.fe; + struct tda18212_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->cfg.fe; dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(priv); + kfree(dev); return 0; } -- cgit v1.2.3 From 3b60b761cbec21af35f08d9220023c1f93b0df2c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Aug 2014 01:00:46 -0300 Subject: [media] tda18212: convert to RegMap API Use RegMap API to handle all the boring I2C register access boilerplate stuff. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 1 + drivers/media/tuners/tda18212.c | 131 ++++++---------------------------------- 2 files changed, 18 insertions(+), 114 deletions(-) diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 48bff2e23d93..69a9fa5dd076 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -204,6 +204,7 @@ config MEDIA_TUNER_FC0013 config MEDIA_TUNER_TDA18212 tristate "NXP TDA18212 silicon tuner" depends on MEDIA_SUPPORT && I2C + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help NXP TDA18212 silicon tuner driver. diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 24948c7971e3..d93e0667b46b 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -19,122 +19,16 @@ */ #include "tda18212.h" - -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 +#include struct tda18212_dev { struct tda18212_config cfg; struct i2c_client *client; + struct regmap *regmap; u32 if_frequency; }; -/* write multiple registers */ -static int tda18212_wr_regs(struct tda18212_dev *dev, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = dev->client->addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (1 + len > sizeof(buf)) { - dev_warn(&dev->client->dev, - "i2c wr reg=%04x: len=%d is too big!\n", - reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(dev->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&dev->client->dev, - "i2c wr failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int tda18212_rd_regs(struct tda18212_dev *dev, u8 reg, u8 *val, int len) -{ - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[2] = { - { - .addr = dev->client->addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = dev->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf, - } - }; - - if (len > sizeof(buf)) { - dev_warn(&dev->client->dev, - "i2c rd reg=%04x: len=%d is too big!\n", - reg, len); - return -EINVAL; - } - - ret = i2c_transfer(dev->client->adapter, msg, 2); - if (ret == 2) { - memcpy(val, buf, len); - ret = 0; - } else { - dev_warn(&dev->client->dev, - "i2c rd failed=%d reg=%02x len=%d\n", - ret, reg, len); - ret = -EREMOTEIO; - } - - return ret; -} - -/* write single register */ -static int tda18212_wr_reg(struct tda18212_dev *dev, u8 reg, u8 val) -{ - return tda18212_wr_regs(dev, reg, &val, 1); -} - -/* read single register */ -static int tda18212_rd_reg(struct tda18212_dev *dev, u8 reg, u8 *val) -{ - return tda18212_rd_regs(dev, reg, val, 1); -} - -#if 0 /* keep, useful when developing driver */ -static void tda18212_dump_regs(struct tda18212_dev *dev) -{ - int i; - u8 buf[256]; - - #define TDA18212_RD_LEN 32 - for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) - tda18212_rd_regs(dev, i, &buf[i], TDA18212_RD_LEN); - - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, - sizeof(buf), true); - - return; -} -#endif - static int tda18212_set_params(struct dvb_frontend *fe) { struct tda18212_dev *dev = fe->tuner_priv; @@ -231,15 +125,15 @@ static int tda18212_set_params(struct dvb_frontend *fe) goto error; } - ret = tda18212_wr_reg(dev, 0x23, bw_params[i][2]); + ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]); if (ret) goto error; - ret = tda18212_wr_reg(dev, 0x06, 0x00); + ret = regmap_write(dev->regmap, 0x06, 0x00); if (ret) goto error; - ret = tda18212_wr_reg(dev, 0x0f, bw_params[i][0]); + ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]); if (ret) goto error; @@ -252,7 +146,7 @@ static int tda18212_set_params(struct dvb_frontend *fe) buf[6] = ((c->frequency / 1000) >> 0) & 0xff; buf[7] = 0xc1; buf[8] = 0x01; - ret = tda18212_wr_regs(dev, 0x12, buf, sizeof(buf)); + ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf)); if (ret) goto error; @@ -299,8 +193,12 @@ static int tda18212_probe(struct i2c_client *client, struct dvb_frontend *fe = cfg->fe; struct tda18212_dev *dev; int ret; - u8 chip_id = chip_id; + unsigned int chip_id; char *version; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { @@ -311,12 +209,17 @@ static int tda18212_probe(struct i2c_client *client, memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config)); dev->client = client; + dev->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err; + } /* check if the tuner is there */ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ - ret = tda18212_rd_reg(dev, 0x00, &chip_id); + ret = regmap_read(dev->regmap, 0x00, &chip_id); dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id); if (fe->ops.i2c_gate_ctrl) -- cgit v1.2.3 From a0ffe4c0908b27b35ce56d35ba6f3c10be3fd371 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 15 Aug 2014 13:21:15 -0300 Subject: [media] radio-si470x-usb: use USB API functions rather than constants This patch introduces the use of the function usb_endpoint_is_int_in. The Coccinelle semantic patch that makes these changes is as follows: @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bEndpointAddress & \(USB_ENDPOINT_DIR_MASK\|0x80\)) == - \(USB_DIR_IN\|0x80\)) + usb_endpoint_dir_in(epd) @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bmAttributes & \(USB_ENDPOINT_XFERTYPE_MASK\|3\)) == - \(USB_ENDPOINT_XFER_INT\|3\)) + usb_endpoint_xfer_int(epd) @@ struct usb_endpoint_descriptor *epd; @@ - (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)) + usb_endpoint_is_int_in(epd) Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 494fac061306..57f0bc3b60e7 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -607,9 +607,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* Set up interrupt endpoint information. */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == - USB_DIR_IN) && ((endpoint->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) + if (usb_endpoint_is_int_in(endpoint)) radio->int_in_endpoint = endpoint; } if (!radio->int_in_endpoint) { -- cgit v1.2.3 From 18cb65033832df8d33aa3a9c9c3e32016fc09cf5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 16 Aug 2014 03:57:30 -0300 Subject: [media] tvp7002: Don't update device->streaming if write to register fails This ensures device->streaming has correct status. Signed-off-by: Axel Lin Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 11f2387e1dab..51bac762638b 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -775,25 +775,20 @@ static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) { struct tvp7002 *device = to_tvp7002(sd); - int error = 0; + int error; if (device->streaming == enable) return 0; - if (enable) { - /* Set output state on (low impedance means stream on) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); - device->streaming = enable; - } else { - /* Set output state off (high impedance means stream off) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03); - if (error) - v4l2_dbg(1, debug, sd, "Unable to stop streaming\n"); - - device->streaming = enable; + /* low impedance: on, high impedance: off */ + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, enable ? 0x00 : 0x03); + if (error) { + v4l2_dbg(1, debug, sd, "Fail to set streaming\n"); + return error; } - return error; + device->streaming = enable; + return 0; } /* -- cgit v1.2.3 From 69486eb00b3e89735dddb48c8b93ac28458a9c80 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 22 Aug 2014 13:41:56 -0300 Subject: [media] drivers: media: b2c2: flexcop.h: Fix typo in include guard Three trailing underscores is one too many. Signed-off-by: Rasmus Villemoes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h index 897b10c85ad9..8942bdacbf61 100644 --- a/drivers/media/common/b2c2/flexcop.h +++ b/drivers/media/common/b2c2/flexcop.h @@ -4,7 +4,7 @@ * see flexcop.c for copyright information */ #ifndef __FLEXCOP_H__ -#define __FLEXCOP_H___ +#define __FLEXCOP_H__ #define FC_LOG_PREFIX "b2c2-flexcop" #include "flexcop-common.h" -- cgit v1.2.3 From 825fd08dbbd830b3f42e0f014f4c9f6eba5c434c Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 22 Aug 2014 13:45:17 -0300 Subject: [media] drivers: media: i2c: adv7343_regs.h: Fix typo in #ifndef Test for definedness of the macro which is actually defined, and which matches the name of the file. Signed-off-by: Rasmus Villemoes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7343_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h index 446606764346..2f04ce4b9118 100644 --- a/drivers/media/i2c/adv7343_regs.h +++ b/drivers/media/i2c/adv7343_regs.h @@ -13,7 +13,7 @@ * GNU General Public License for more details. */ -#ifndef ADV7343_REG_H +#ifndef ADV7343_REGS_H #define ADV7343_REGS_H struct adv7343_std_info { -- cgit v1.2.3 From 12561ad622de254d69ec1baaf6734afc602a2c30 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Aug 2014 08:57:59 -0300 Subject: [media] videobuf2-core: take mmap_sem before calling __qbuf_userptr (Changes since v2: dropped local variable as suggested by Laurent) Commit f035eb4e976ef5a059e30bc91cfd310ff030a7d3 (videobuf2: fix lockdep warning) unfortunately removed the mmap_sem lock that is needed around the call to __qbuf_userptr. Amazingly nobody noticed this (especially me as the author) until Jan Kara pointed this out to me. Signed-off-by: Hans Verkuil Reported-by: Jan Kara Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 7e6aff673a5a..15b02f940ced 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1627,7 +1627,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = __qbuf_mmap(vb, b); break; case V4L2_MEMORY_USERPTR: + down_read(¤t->mm->mmap_sem); ret = __qbuf_userptr(vb, b); + up_read(¤t->mm->mmap_sem); break; case V4L2_MEMORY_DMABUF: ret = __qbuf_dmabuf(vb, b); -- cgit v1.2.3 From b7900eedfb393dcea9794fbb6d57e4d43338a16b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 31 Aug 2014 07:19:21 -0300 Subject: [media] videobuf: Allow reqbufs(0) to free current buffers All the infrastructure for this is already there, and despite our desires for the old videobuf code to go away, it is currently still in use in 18 drivers. Allowing reqbufs(0) makes these drivers behave consistent with modern drivers, making live easier for userspace, see e.g. : https://bugzilla.gnome.org/show_bug.cgi?id=735660 Signed-off-by: Hans de Goede Acked-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index fb5ee5dd8fe9..b91a266d0b7e 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -441,11 +441,6 @@ int videobuf_reqbufs(struct videobuf_queue *q, unsigned int size, count; int retval; - if (req->count < 1) { - dprintk(1, "reqbufs: count invalid (%d)\n", req->count); - return -EINVAL; - } - if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { @@ -471,6 +466,12 @@ int videobuf_reqbufs(struct videobuf_queue *q, goto done; } + if (req->count == 0) { + dprintk(1, "reqbufs: count invalid (%d)\n", req->count); + retval = __videobuf_free(q); + goto done; + } + count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; -- cgit v1.2.3 From 55d3b439acad5c9faf34765f8391a13d153a1e81 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 6 Sep 2014 12:26:47 -0300 Subject: [media] media: davinci: vpif_display: drop setting of vb2 buffer state to ACTIVE this patch drops setting of vb2 buffer state to VB2_BUF_STATE_ACTIVE, as any buffer queued to the driver is marked ACTIVE by the vb2 core. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 2ce3ddfcca80..76f829d6b10b 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -196,8 +196,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) list_del(&common->cur_frm->list); spin_unlock_irqrestore(&common->irqlock, flags); - /* Mark state of the current frame to active */ - common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0); common->set_addr((addr + common->ytop_off), @@ -306,8 +304,6 @@ static void process_progressive_mode(struct common_obj *common) /* Remove that buffer from the buffer queue */ list_del(&common->next_frm->list); spin_unlock(&common->irqlock); - /* Mark status of the buffer as active */ - common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; /* Set top and bottom field addrs in VPIF registers */ addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); -- cgit v1.2.3 From 3b8a269b7dd64cab4645f95daf3e470e72adfed8 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 6 Sep 2014 12:26:48 -0300 Subject: [media] media: davinci: vpif_capture: drop setting of vb2 buffer state to ACTIVE this patch drops setting of vb2 buffer state to VB2_BUF_STATE_ACTIVE, as any buffer queued to the driver is marked ACTIVE by the vb2 core. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index cf15bb1962ef..881efcdbee87 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -213,8 +213,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) /* Remove buffer from the buffer queue */ list_del(&common->cur_frm->list); spin_unlock_irqrestore(&common->irqlock, flags); - /* Mark state of the current frame to active */ - common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0); @@ -350,7 +348,6 @@ static void vpif_schedule_next_buffer(struct common_obj *common) /* Remove that buffer from the buffer queue */ list_del(&common->next_frm->list); spin_unlock(&common->irqlock); - common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); /* Set top and bottom field addresses in VPIF registers */ -- cgit v1.2.3 From ead130335f35fb732921ee0ffde6639be35aa108 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 6 Sep 2014 12:26:49 -0300 Subject: [media] media: videobuf2-core.h: add a helper to get status of start_streaming() this patch adds a helper to get the status if start_streaming() was called successfully. Signed-off-by: Lad, Prabhakar Cc: Pawel Osciak Cc: Marek Szyprowski Cc: Kyungmin Park Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 5a10d8d695b4..b3c9973463ed 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -590,6 +590,15 @@ vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no) return 0; } +/** + * vb2_start_streaming_called() - return streaming status of driver + * @q: videobuf queue + */ +static inline bool vb2_start_streaming_called(struct vb2_queue *q) +{ + return q->start_streaming_called; +} + /* * The following functions are not part of the vb2 core API, but are simple * helper functions that you can use in your struct v4l2_file_operations, -- cgit v1.2.3 From 815789244eda0b3be11fb1824354ca20c8ec3508 Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 6 Sep 2014 12:26:50 -0300 Subject: [media] media: davinci: vpif_display: fix the check on suspend/resume callbacks It is possible to call STREAMON without having any buffers queued. So vb2_is_streaming() can return true without start_streaming() having been called. Only after at least one buffer has been queued will start_streaming be called. The check vb2_is_streaming() is incorrect as this would start the DMA without having proper DMA pointers set up. this patch uses vb2_start_streaming_called() instead to check is streaming was called. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 76f829d6b10b..8d6ced56253c 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1400,7 +1400,7 @@ static int vpif_suspend(struct device *dev) ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - if (!vb2_is_streaming(&common->buffer_queue)) + if (!vb2_start_streaming_called(&common->buffer_queue)) continue; mutex_lock(&common->lock); @@ -1432,7 +1432,7 @@ static int vpif_resume(struct device *dev) ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - if (!vb2_is_streaming(&common->buffer_queue)) + if (!vb2_start_streaming_called(&common->buffer_queue)) continue; mutex_lock(&common->lock); -- cgit v1.2.3 From c54d4a0b08bc4deddd3919d64f4121eaa487e28e Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 6 Sep 2014 12:26:51 -0300 Subject: [media] media: davinci: vpif_capture: fix the check on suspend/resume callbacks It is possible to call STREAMON without having any buffers queued. So vb2_is_streaming() can return true without start_streaming() having been called. Only after at least one buffer has been queued will start_streaming be called. The check vb2_is_streaming() is incorrect as this would start the DMA without having proper DMA pointers set up. this patch uses vb2_start_streaming_called() instead to check is streaming was called. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 881efcdbee87..3ccb26ff43c8 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1596,7 +1596,7 @@ static int vpif_suspend(struct device *dev) ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - if (!vb2_is_streaming(&common->buffer_queue)) + if (!vb2_start_streaming_called(&common->buffer_queue)) continue; mutex_lock(&common->lock); @@ -1630,7 +1630,7 @@ static int vpif_resume(struct device *dev) ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - if (!vb2_is_streaming(&common->buffer_queue)) + if (!vb2_start_streaming_called(&common->buffer_queue)) continue; mutex_lock(&common->lock); -- cgit v1.2.3 From 7000e325de875fa8a5dd3885c8e8f0f12cf71eaf Mon Sep 17 00:00:00 2001 From: Prabhakar Lad Date: Sat, 16 Aug 2014 17:33:18 -0300 Subject: [media] media: davinci: remove unneeded dependency ARCH_OMAP3 this patch removes unneeded dependency of ARCH_OMAP3 on VIDEO_DM6446_CCDC. Also the top level platform Makefile descended into davinci/ without any dependency so just drop the dependency obj-y, as obj-$(CONFIG_ARCH_DAVINCI) already exists. Reported-by: Andreas Ruprecht Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 2 -- drivers/media/platform/davinci/Kconfig | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 8d3fcfef099c..579046bc276f 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -47,8 +47,6 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ -obj-y += davinci/ - obj-y += omap/ ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index b04016e8532d..d9e1ddb586b1 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -31,7 +31,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" depends on VIDEO_V4L2 - depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST + depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help -- cgit v1.2.3 From e3d6eb1c16ef174a8fbbdd40770f5cbace0710e4 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 3 Sep 2014 16:38:39 -0300 Subject: [media] v4l: Add camera pan/tilt speed controls The V4L2_CID_PAN_SPEED and V4L2_CID_TILT_SPEED controls allow to move the camera by setting its rotation speed around its axis. Signed-off-by: Vincent Palatin Reviewed-by: Pawel Osciak Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 10 ++++++++++ Documentation/DocBook/media/v4l/controls.xml | 21 +++++++++++++++++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++ include/uapi/linux/v4l2-controls.h | 2 ++ 4 files changed, 35 insertions(+) diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index eee6f0f4aa43..7aa7c5d41e3b 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2545,6 +2545,16 @@ fields changed from _s32 to _u32. +
+ V4L2 in Linux 3.18 + + + Added V4L2_CID_PAN_SPEED and + V4L2_CID_TILT_SPEED camera controls. + + +
+
Relation of V4L2 to other Linux multimedia APIs diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index a7eb1bde8b92..e013e4bf244c 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3965,6 +3965,27 @@ by exposure, white balance or focus controls. + + V4L2_CID_PAN_SPEED  + integer + This control turns the +camera horizontally at the specific speed. The unit is undefined. A +positive value moves the camera to the right (clockwise when viewed +from above), a negative value to the left. A value of zero stops the motion +if one is in progress and has no effect otherwise. + + + + + V4L2_CID_TILT_SPEED  + integer + This control turns the +camera vertically at the specified speed. The unit is undefined. A +positive value moves the camera up, a negative value down. A value of zero +stops the motion if one is in progress and has no effect otherwise. + + + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 35d1f3d5045b..86012140923f 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -796,6 +796,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop"; case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status"; case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range"; + case V4L2_CID_PAN_SPEED: return "Pan, Speed"; + case V4L2_CID_TILT_SPEED: return "Tilt, Speed"; /* FM Radio Modulator controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 8b930210a4b9..661f119a51b8 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -746,6 +746,8 @@ enum v4l2_auto_focus_range { V4L2_AUTO_FOCUS_RANGE_INFINITY = 3, }; +#define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32) +#define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33) /* FM Modulator class control IDs */ -- cgit v1.2.3 From 3ea375239ca06014b8b421ab1d73d6628d22036f Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 3 Sep 2014 21:47:48 -0300 Subject: [media] v4l: uvcvideo: Add support for pan/tilt speed controls Map V4L2_CID_TILT_SPEED and V4L2_CID_PAN_SPEED to the standard UVC CT_PANTILT_RELATIVE_CONTROL terminal control request. Tested by plugging a Logitech ConferenceCam C3000e USB camera and controlling pan/tilt from the userspace using the VIDIOC_S_CTRL ioctl. Verified that it can pan and tilt at the same time in both directions. Signed-off-by: Vincent Palatin Reviewed-by: Pawel Osciak Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 58 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 0eb82106d2ff..d2d1755145c8 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -309,9 +309,8 @@ static struct uvc_control_info uvc_ctrls[] = { .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, .index = 12, .size = 4, - .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN - | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES - | UVC_CTRL_FLAG_GET_DEF + .flags = UVC_CTRL_FLAG_SET_CUR + | UVC_CTRL_FLAG_GET_RANGE | UVC_CTRL_FLAG_AUTO_UPDATE, }, { @@ -391,6 +390,35 @@ static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, data[2] = min((int)abs(value), 0xff); } +static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, + __u8 query, const __u8 *data) +{ + unsigned int first = mapping->offset / 8; + __s8 rel = (__s8)data[first]; + + switch (query) { + case UVC_GET_CUR: + return (rel == 0) ? 0 : (rel > 0 ? data[first+1] + : -data[first+1]); + case UVC_GET_MIN: + return -data[first+1]; + case UVC_GET_MAX: + case UVC_GET_RES: + case UVC_GET_DEF: + default: + return data[first+1]; + } +} + +static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, + __s32 value, __u8 *data) +{ + unsigned int first = mapping->offset / 8; + + data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; + data[first+1] = min_t(int, abs(value), 0xff); +} + static struct uvc_control_mapping uvc_ctrl_mappings[] = { { .id = V4L2_CID_BRIGHTNESS, @@ -676,6 +704,30 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, + { + .id = V4L2_CID_PAN_SPEED, + .name = "Pan (Speed)", + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, + .size = 16, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_INTEGER, + .data_type = UVC_CTRL_DATA_TYPE_SIGNED, + .get = uvc_ctrl_get_rel_speed, + .set = uvc_ctrl_set_rel_speed, + }, + { + .id = V4L2_CID_TILT_SPEED, + .name = "Tilt (Speed)", + .entity = UVC_GUID_UVC_CAMERA, + .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, + .size = 16, + .offset = 16, + .v4l2_type = V4L2_CTRL_TYPE_INTEGER, + .data_type = UVC_CTRL_DATA_TYPE_SIGNED, + .get = uvc_ctrl_get_rel_speed, + .set = uvc_ctrl_set_rel_speed, + }, { .id = V4L2_CID_PRIVACY, .name = "Privacy", -- cgit v1.2.3 From 17e1319fd051f6f1d8b923ca3104c3391610ab32 Mon Sep 17 00:00:00 2001 From: William Manley Date: Thu, 13 Mar 2014 09:38:48 -0300 Subject: [media] uvcvideo: Work around buggy Logitech C920 firmware The uvcvideo webcam driver exposes the v4l2 control "Exposure (Absolute)" which allows the user to control the exposure time of the webcam, essentially controlling the brightness of the received image. By default the webcam automatically adjusts the exposure time automatically but the if you set the control "Exposure, Auto"="Manual Mode" the user can fix the exposure time. Unfortunately it seems that the Logitech C920 has a firmware bug where it will forget that it's in manual mode temporarily during initialisation. This means that the camera doesn't respect the exposure time that the user requested if they request it before starting to stream video. They end up with a video stream which is either too bright or too dark and must reset the controls after video starts streaming. This patch introduces the quirk UVC_QUIRK_RESTORE_CTRLS_ON_INIT which causes the cached controls to be re-uploaded to the camera immediately after initialising the camera. This quirk is applied to the C920 to work around this camera bug. Signed-off-by: William Manley Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 2 +- drivers/media/usb/uvc/uvc_driver.c | 11 ++++++++++- drivers/media/usb/uvc/uvc_video.c | 6 ++++++ drivers/media/usb/uvc/uvcvideo.h | 3 ++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index d2d1755145c8..3e59b288b8a8 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1847,7 +1847,7 @@ done: * - Handle restore order (Auto-Exposure Mode should be restored before * Exposure Time). */ -int uvc_ctrl_resume_device(struct uvc_device *dev) +int uvc_ctrl_restore_values(struct uvc_device *dev) { struct uvc_control *ctrl; struct uvc_entity *entity; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index f8135f4e3b52..51dfa74a81a9 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2000,7 +2000,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) int ret = 0; if (reset) { - ret = uvc_ctrl_resume_device(dev); + ret = uvc_ctrl_restore_values(dev); if (ret < 0) return ret; } @@ -2175,6 +2175,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0 }, + /* Logitech HD Pro Webcam C920 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x082d, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_RESTORE_CTRLS_ON_INIT }, /* Chicony CNF7129 (Asus EEE 100HE) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 7e350d788fe1..a2bddf48171f 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1678,6 +1678,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) } } + /* The Logitech C920 temporarily forgets that it should not be adjusting + * Exposure Absolute during init so restore controls to stored values. + */ + if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT) + uvc_ctrl_restore_values(stream->dev); + return 0; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index b1f69a6d4068..39c4f941b63d 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -147,6 +147,7 @@ #define UVC_QUIRK_FIX_BANDWIDTH 0x00000080 #define UVC_QUIRK_PROBE_DEF 0x00000100 #define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200 +#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 @@ -688,7 +689,7 @@ extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, const struct uvc_control_mapping *mapping); extern int uvc_ctrl_init_device(struct uvc_device *dev); extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); -extern int uvc_ctrl_resume_device(struct uvc_device *dev); +extern int uvc_ctrl_restore_values(struct uvc_device *dev); extern int uvc_ctrl_begin(struct uvc_video_chain *chain); extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, -- cgit v1.2.3 From 62ea864f84fed6e04dd033d500d4c9183a83d590 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 8 Jun 2014 12:16:48 -0300 Subject: [media] media: usb: uvc: add a quirk for Dell XPS M1330 webcam As reported on [1], this device needs this quirk to be able to reliably initialise the webcam. [1] http://ubuntuforums.org/showthread.php?t=2145996 Cc: stable@vger.kernel.org Signed-off-by: Paul Fertser Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 51dfa74a81a9..7c8322d4fc63 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2238,6 +2238,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_DEF }, + /* Dell XPS M1330 (OmniVision OV7670 webcam) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x05a9, + .idProduct = 0x7670, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_DEF }, /* Apple Built-In iSight */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, -- cgit v1.2.3 From de8eae36057b50086278af1ec4d96fc9a2e35f0b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Jul 2014 08:52:08 -0300 Subject: [media] media: Use strlcpy instead of custom code Replace strncpy + manually setting the terminating '\0' with an strlcpy call. Reported-by: Joe Perches Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 73a432934bd8..7b39440192d6 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -103,10 +103,8 @@ static long media_device_enum_entities(struct media_device *mdev, return -EINVAL; u_ent.id = ent->id; - if (ent->name) { - strncpy(u_ent.name, ent->name, sizeof(u_ent.name)); - u_ent.name[sizeof(u_ent.name) - 1] = '\0'; - } + if (ent->name) + strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); u_ent.type = ent->type; u_ent.revision = ent->revision; u_ent.flags = ent->flags; -- cgit v1.2.3 From fcc0d3db28922f9ba21ea6c7b23ea10ffb5d3521 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 21 Jul 2014 17:06:33 -0300 Subject: [media] v4l: Add ARGB555X and XRGB555X pixel formats The existing RGB555X pixel format is ill-defined in respect to its alpha bit and its meaning is driver dependent. Create new standard ARGB555X and XRGB555X variants with clearly defined meanings and make the existing variant deprecated. The new pixel formats 4CC values have been selected to match the DRM 4CCs for the same in-memory formats. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/pixfmt-packed-rgb.xml | 50 ++++++++++++++++++++-- include/uapi/linux/videodev2.h | 3 ++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 2aae8e9452a4..65a11867e0ae 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -237,9 +237,9 @@ for a pixel lie next to each other in memory. g4 g3 - - V4L2_PIX_FMT_RGB555X - 'RGBQ' + + V4L2_PIX_FMT_ARGB555X + 'AR15' | (1 << 31) a r4 @@ -259,6 +259,28 @@ for a pixel lie next to each other in memory. b1 b0 + + V4L2_PIX_FMT_XRGB555X + 'XR15' | (1 << 31) + + - + r4 + r3 + r2 + r1 + r0 + g4 + g3 + + g2 + g1 + g0 + b4 + b3 + b2 + b1 + b0 + V4L2_PIX_FMT_RGB565X 'RGBR' @@ -800,6 +822,28 @@ image g4 g3 + + V4L2_PIX_FMT_RGB555X + 'RGBQ' + + a + r4 + r3 + r2 + r1 + r0 + g4 + g3 + + g2 + g1 + g0 + b4 + b3 + b2 + b1 + b0 + V4L2_PIX_FMT_BGR32 'BGR4' diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 0b1ba5c6a8d2..1c2f84fd4d99 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -79,6 +79,7 @@ /* Four-character-code (FOURCC) */ #define v4l2_fourcc(a, b, c, d)\ ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) +#define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1 << 31)) /* * E N U M S @@ -307,6 +308,8 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16 XRGB-1-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16 ARGB-5-5-5 BE */ +#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16 XRGB-5-5-5 BE */ #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ -- cgit v1.2.3 From 22889ef8162b86c25b6c609624a9c53f9fd7f642 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 21 Jul 2014 19:36:58 -0300 Subject: [media] v4l: Fix ARGB32 fourcc value in the documentation The ARGB32 pixel format's fourcc value is defined to 'BA24' in the videodev2.h header, but documented as 'AX24'. Fix the documentation. Reported-by: Hans Verkuil Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 65a11867e0ae..6ab4f0f3db64 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -486,7 +486,7 @@ for a pixel lie next to each other in memory. V4L2_PIX_FMT_ARGB32 - 'AX24' + 'BA24' a7 a6 -- cgit v1.2.3 From 969ec1f6bd925092109eaf21501a9d64adfc7ad4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 23 Aug 2014 04:40:01 -0300 Subject: [media] hackrf: HackRF SDR driver V4L2 driver for HackRF SDR. Very basic version, with reduced feature set. Driver implements receiver only, hardware supports also transmitter. USB ID 1d50:6089. Model HackRF One Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/Kconfig | 3 +- drivers/media/usb/Makefile | 3 +- drivers/media/usb/hackrf/Kconfig | 10 + drivers/media/usb/hackrf/Makefile | 1 + drivers/media/usb/hackrf/hackrf.c | 1142 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1157 insertions(+), 2 deletions(-) create mode 100644 drivers/media/usb/hackrf/Kconfig create mode 100644 drivers/media/usb/hackrf/Makefile create mode 100644 drivers/media/usb/hackrf/hackrf.c diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index d6e8edc59b6d..056181f2f569 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -56,8 +56,9 @@ endif if MEDIA_SDR_SUPPORT comment "Software defined radio USB devices" -source "drivers/media/usb/msi2500/Kconfig" source "drivers/media/usb/airspy/Kconfig" +source "drivers/media/usb/hackrf/Kconfig" +source "drivers/media/usb/msi2500/Kconfig" endif endif #MEDIA_USB_SUPPORT diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index b5b645b91f4e..6f2eb7c8416c 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -9,8 +9,9 @@ obj-y += zr364xx/ stkwebcam/ s2255/ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ obj-$(CONFIG_USB_GSPCA) += gspca/ obj-$(CONFIG_USB_PWC) += pwc/ -obj-$(CONFIG_USB_MSI2500) += msi2500/ obj-$(CONFIG_USB_AIRSPY) += airspy/ +obj-$(CONFIG_USB_HACKRF) += hackrf/ +obj-$(CONFIG_USB_MSI2500) += msi2500/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_AU0828) += au0828/ obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig new file mode 100644 index 000000000000..937e6f5c1e8e --- /dev/null +++ b/drivers/media/usb/hackrf/Kconfig @@ -0,0 +1,10 @@ +config USB_HACKRF + tristate "HackRF" + depends on VIDEO_V4L2 + select VIDEOBUF2_VMALLOC + ---help--- + This is a video4linux2 driver for HackRF SDR device. + + To compile this driver as a module, choose M here: the + module will be called hackrf + diff --git a/drivers/media/usb/hackrf/Makefile b/drivers/media/usb/hackrf/Makefile new file mode 100644 index 000000000000..73064a24cd4e --- /dev/null +++ b/drivers/media/usb/hackrf/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_HACKRF) += hackrf.o diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c new file mode 100644 index 000000000000..94276525b037 --- /dev/null +++ b/drivers/media/usb/hackrf/hackrf.c @@ -0,0 +1,1142 @@ +/* + * HackRF driver + * + * Copyright (C) 2014 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* HackRF USB API commands (from HackRF Library) */ +enum { + CMD_SET_TRANSCEIVER_MODE = 0x01, + CMD_SAMPLE_RATE_SET = 0x06, + CMD_BASEBAND_FILTER_BANDWIDTH_SET = 0x07, + CMD_BOARD_ID_READ = 0x0e, + CMD_VERSION_STRING_READ = 0x0f, + CMD_SET_FREQ = 0x10, + CMD_SET_LNA_GAIN = 0x13, + CMD_SET_VGA_GAIN = 0x14, +}; + +/* + * bEndpointAddress 0x81 EP 1 IN + * Transfer Type Bulk + * wMaxPacketSize 0x0200 1x 512 bytes + */ +#define MAX_BULK_BUFS (6) +#define BULK_BUFFER_SIZE (128 * 512) + +static const struct v4l2_frequency_band bands_adc[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 200000, + .rangehigh = 24000000, + }, +}; + +static const struct v4l2_frequency_band bands_rf[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1, + .rangehigh = 4294967294, /* max u32, hw goes over 7GHz */ + }, +}; + +/* stream formats */ +struct hackrf_format { + char *name; + u32 pixelformat; + u32 buffersize; +}; + +/* format descriptions for capture and preview */ +static struct hackrf_format formats[] = { + { + .name = "Complex S8", + .pixelformat = V4L2_SDR_FMT_CS8, + .buffersize = BULK_BUFFER_SIZE, + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); + +/* intermediate buffers with raw data from the USB device */ +struct hackrf_frame_buf { + struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */ + struct list_head list; +}; + +struct hackrf_dev { +#define POWER_ON (1 << 1) +#define URB_BUF (1 << 2) +#define USB_STATE_URB_BUF (1 << 3) + unsigned long flags; + + struct device *dev; + struct usb_device *udev; + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* videobuf2 queue and queued buffers list */ + struct vb2_queue vb_queue; + struct list_head queued_bufs; + spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + unsigned sequence; /* Buffer sequence counter */ + unsigned int vb_full; /* vb is full and packets dropped */ + + /* Note if taking both locks v4l2_lock must always be locked first! */ + struct mutex v4l2_lock; /* Protects everything else */ + struct mutex vb_queue_lock; /* Protects vb_queue */ + + struct urb *urb_list[MAX_BULK_BUFS]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_BULK_BUFS]; + dma_addr_t dma_addr[MAX_BULK_BUFS]; + int urbs_initialized; + int urbs_submitted; + + /* USB control message buffer */ + #define BUF_SIZE 24 + u8 buf[BUF_SIZE]; + + /* Current configuration */ + unsigned int f_adc; + unsigned int f_rf; + u32 pixelformat; + u32 buffersize; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + struct v4l2_ctrl *lna_gain; + struct v4l2_ctrl *if_gain; + + /* Sample rate calc */ + unsigned long jiffies_next; + unsigned int sample; + unsigned int sample_measured; +}; + +#define hackrf_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \ + char *_direction; \ + if (_t & USB_DIR_IN) \ + _direction = "<<<"; \ + else \ + _direction = ">>>"; \ + dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \ + _t, _r, _v & 0xff, _v >> 8, _i & 0xff, \ + _i >> 8, _l & 0xff, _l >> 8, _direction, _l, _b); \ +} + +/* execute firmware command */ +static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value, + u16 index, u8 *data, u16 size) +{ + int ret; + unsigned int pipe; + u8 requesttype; + + switch (request) { + case CMD_SET_TRANSCEIVER_MODE: + case CMD_SET_FREQ: + case CMD_SAMPLE_RATE_SET: + case CMD_BASEBAND_FILTER_BANDWIDTH_SET: + pipe = usb_sndctrlpipe(dev->udev, 0); + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + break; + case CMD_BOARD_ID_READ: + case CMD_VERSION_STRING_READ: + case CMD_SET_LNA_GAIN: + case CMD_SET_VGA_GAIN: + pipe = usb_rcvctrlpipe(dev->udev, 0); + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + break; + default: + dev_err(dev->dev, "Unknown command %02x\n", request); + ret = -EINVAL; + goto err; + } + + /* write request */ + if (!(requesttype & USB_DIR_IN)) + memcpy(dev->buf, data, size); + + ret = usb_control_msg(dev->udev, pipe, request, requesttype, value, + index, dev->buf, size, 1000); + hackrf_dbg_usb_control_msg(dev->dev, request, requesttype, value, + index, dev->buf, size); + if (ret < 0) { + dev_err(dev->dev, "usb_control_msg() failed %d request %02x\n", + ret, request); + goto err; + } + + /* read request */ + if (requesttype & USB_DIR_IN) + memcpy(data, dev->buf, size); + + return 0; +err: + return ret; +} + +/* Private functions */ +static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev) +{ + unsigned long flags; + struct hackrf_frame_buf *buf = NULL; + + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + if (list_empty(&dev->queued_bufs)) + goto leave; + + buf = list_entry(dev->queued_bufs.next, struct hackrf_frame_buf, list); + list_del(&buf->list); +leave: + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); + return buf; +} + +static unsigned int hackrf_convert_stream(struct hackrf_dev *dev, + void *dst, void *src, unsigned int src_len) +{ + memcpy(dst, src, src_len); + + /* calculate sample rate and output it in 10 seconds intervals */ + if (unlikely(time_is_before_jiffies(dev->jiffies_next))) { + #define MSECS 10000UL + unsigned int msecs = jiffies_to_msecs(jiffies - + dev->jiffies_next + msecs_to_jiffies(MSECS)); + unsigned int samples = dev->sample - dev->sample_measured; + + dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS); + dev->sample_measured = dev->sample; + dev_dbg(dev->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); + } + + /* total number of samples */ + dev->sample += src_len / 2; + + return src_len; +} + +/* + * This gets called for the bulk stream pipe. This is done in interrupt + * time, so it has to be fast, not crash, and not stall. Neat. + */ +static void hackrf_urb_complete(struct urb *urb) +{ + struct hackrf_dev *dev = urb->context; + struct hackrf_frame_buf *fbuf; + + dev_dbg_ratelimited(dev->dev, "status=%d length=%d/%d errors=%d\n", + urb->status, urb->actual_length, + urb->transfer_buffer_length, urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dev_err_ratelimited(dev->dev, "URB failed %d\n", urb->status); + break; + } + + if (likely(urb->actual_length > 0)) { + void *ptr; + unsigned int len; + /* get free framebuffer */ + fbuf = hackrf_get_next_fill_buf(dev); + if (unlikely(fbuf == NULL)) { + dev->vb_full++; + dev_notice_ratelimited(dev->dev, + "videobuf is full, %d packets dropped\n", + dev->vb_full); + goto skip; + } + + /* fill framebuffer */ + ptr = vb2_plane_vaddr(&fbuf->vb, 0); + len = hackrf_convert_stream(dev, ptr, urb->transfer_buffer, + urb->actual_length); + vb2_set_plane_payload(&fbuf->vb, 0, len); + v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp); + fbuf->vb.v4l2_buf.sequence = dev->sequence++; + vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); + } +skip: + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int hackrf_kill_urbs(struct hackrf_dev *dev) +{ + int i; + + for (i = dev->urbs_submitted - 1; i >= 0; i--) { + dev_dbg(dev->dev, "kill urb=%d\n", i); + /* stop the URB */ + usb_kill_urb(dev->urb_list[i]); + } + dev->urbs_submitted = 0; + + return 0; +} + +static int hackrf_submit_urbs(struct hackrf_dev *dev) +{ + int i, ret; + + for (i = 0; i < dev->urbs_initialized; i++) { + dev_dbg(dev->dev, "submit urb=%d\n", i); + ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC); + if (ret) { + dev_err(dev->dev, "Could not submit URB no. %d - get them all back\n", + i); + hackrf_kill_urbs(dev); + return ret; + } + dev->urbs_submitted++; + } + + return 0; +} + +static int hackrf_free_stream_bufs(struct hackrf_dev *dev) +{ + if (dev->flags & USB_STATE_URB_BUF) { + while (dev->buf_num) { + dev->buf_num--; + dev_dbg(dev->dev, "free buf=%d\n", dev->buf_num); + usb_free_coherent(dev->udev, dev->buf_size, + dev->buf_list[dev->buf_num], + dev->dma_addr[dev->buf_num]); + } + } + dev->flags &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int hackrf_alloc_stream_bufs(struct hackrf_dev *dev) +{ + dev->buf_num = 0; + dev->buf_size = BULK_BUFFER_SIZE; + + dev_dbg(dev->dev, "all in all I will use %u bytes for streaming\n", + MAX_BULK_BUFS * BULK_BUFFER_SIZE); + + for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) { + dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev, + BULK_BUFFER_SIZE, GFP_ATOMIC, + &dev->dma_addr[dev->buf_num]); + if (!dev->buf_list[dev->buf_num]) { + dev_dbg(dev->dev, "alloc buf=%d failed\n", + dev->buf_num); + hackrf_free_stream_bufs(dev); + return -ENOMEM; + } + + dev_dbg(dev->dev, "alloc buf=%d %p (dma %llu)\n", dev->buf_num, + dev->buf_list[dev->buf_num], + (long long)dev->dma_addr[dev->buf_num]); + dev->flags |= USB_STATE_URB_BUF; + } + + return 0; +} + +static int hackrf_free_urbs(struct hackrf_dev *dev) +{ + int i; + + hackrf_kill_urbs(dev); + + for (i = dev->urbs_initialized - 1; i >= 0; i--) { + if (dev->urb_list[i]) { + dev_dbg(dev->dev, "free urb=%d\n", i); + /* free the URBs */ + usb_free_urb(dev->urb_list[i]); + } + } + dev->urbs_initialized = 0; + + return 0; +} + +static int hackrf_alloc_urbs(struct hackrf_dev *dev) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < MAX_BULK_BUFS; i++) { + dev_dbg(dev->dev, "alloc urb=%d\n", i); + dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!dev->urb_list[i]) { + dev_dbg(dev->dev, "failed\n"); + for (j = 0; j < i; j++) + usb_free_urb(dev->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(dev->urb_list[i], + dev->udev, + usb_rcvbulkpipe(dev->udev, 0x81), + dev->buf_list[i], + BULK_BUFFER_SIZE, + hackrf_urb_complete, dev); + + dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + dev->urb_list[i]->transfer_dma = dev->dma_addr[i]; + dev->urbs_initialized++; + } + + return 0; +} + +/* Must be called with vb_queue_lock hold */ +static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev) +{ + unsigned long flags; + + dev_dbg(dev->dev, "\n"); + + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + while (!list_empty(&dev->queued_bufs)) { + struct hackrf_frame_buf *buf; + + buf = list_entry(dev->queued_bufs.next, + struct hackrf_frame_buf, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); +} + +/* The user yanked out the cable... */ +static void hackrf_disconnect(struct usb_interface *intf) +{ + struct v4l2_device *v = usb_get_intfdata(intf); + struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev); + + dev_dbg(dev->dev, "\n"); + + mutex_lock(&dev->vb_queue_lock); + mutex_lock(&dev->v4l2_lock); + /* No need to keep the urbs around after disconnection */ + dev->udev = NULL; + v4l2_device_disconnect(&dev->v4l2_dev); + video_unregister_device(&dev->vdev); + mutex_unlock(&dev->v4l2_lock); + mutex_unlock(&dev->vb_queue_lock); + + v4l2_device_put(&dev->v4l2_dev); +} + +/* Videobuf2 operations */ +static int hackrf_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) +{ + struct hackrf_dev *dev = vb2_get_drv_priv(vq); + + dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers); + + /* Need at least 8 buffers */ + if (vq->num_buffers + *nbuffers < 8) + *nbuffers = 8 - vq->num_buffers; + *nplanes = 1; + sizes[0] = PAGE_ALIGN(dev->buffersize); + + dev_dbg(dev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); + return 0; +} + +static void hackrf_buf_queue(struct vb2_buffer *vb) +{ + struct hackrf_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct hackrf_frame_buf *buf = + container_of(vb, struct hackrf_frame_buf, vb); + unsigned long flags; + + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + list_add_tail(&buf->list, &dev->queued_bufs); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); +} + +static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct hackrf_dev *dev = vb2_get_drv_priv(vq); + int ret; + + dev_dbg(dev->dev, "\n"); + + if (!dev->udev) + return -ENODEV; + + mutex_lock(&dev->v4l2_lock); + + dev->sequence = 0; + + set_bit(POWER_ON, &dev->flags); + + ret = hackrf_alloc_stream_bufs(dev); + if (ret) + goto err; + + ret = hackrf_alloc_urbs(dev); + if (ret) + goto err; + + ret = hackrf_submit_urbs(dev); + if (ret) + goto err; + + /* start hardware streaming */ + ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0); + if (ret) + goto err; + + goto exit_mutex_unlock; +err: + hackrf_kill_urbs(dev); + hackrf_free_urbs(dev); + hackrf_free_stream_bufs(dev); + clear_bit(POWER_ON, &dev->flags); + + /* return all queued buffers to vb2 */ + { + struct hackrf_frame_buf *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->queued_bufs, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + } + +exit_mutex_unlock: + mutex_unlock(&dev->v4l2_lock); + + return ret; +} + +static void hackrf_stop_streaming(struct vb2_queue *vq) +{ + struct hackrf_dev *dev = vb2_get_drv_priv(vq); + + dev_dbg(dev->dev, "\n"); + + mutex_lock(&dev->v4l2_lock); + + /* stop hardware streaming */ + hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 0, 0, NULL, 0); + + hackrf_kill_urbs(dev); + hackrf_free_urbs(dev); + hackrf_free_stream_bufs(dev); + + hackrf_cleanup_queued_bufs(dev); + + clear_bit(POWER_ON, &dev->flags); + + mutex_unlock(&dev->v4l2_lock); +} + +static struct vb2_ops hackrf_vb2_ops = { + .queue_setup = hackrf_queue_setup, + .buf_queue = hackrf_buf_queue, + .start_streaming = hackrf_start_streaming, + .stop_streaming = hackrf_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int hackrf_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct hackrf_dev *dev = video_drvdata(file); + + dev_dbg(dev->dev, "\n"); + + strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strlcpy(cap->card, dev->vdev.name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_queue; + int i; + + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); + + if (vb2_is_busy(q)) + return -EBUSY; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < NUM_FORMATS; i++) { + if (f->fmt.sdr.pixelformat == formats[i].pixelformat) { + dev->pixelformat = formats[i].pixelformat; + dev->buffersize = formats[i].buffersize; + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +static int hackrf_g_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&dev->pixelformat); + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + f->fmt.sdr.pixelformat = dev->pixelformat; + f->fmt.sdr.buffersize = dev->buffersize; + + return 0; +} + +static int hackrf_try_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + int i; + + dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +static int hackrf_enum_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + + dev_dbg(dev->dev, "index=%d\n", f->index); + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + + return 0; +} + +static int hackrf_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *v) +{ + struct hackrf_dev *dev = video_drvdata(file); + int ret; + + dev_dbg(dev->dev, "index=%d\n", v->index); + + if (v->index == 0) + ret = 0; + else if (v->index == 1) + ret = 0; + else + ret = -EINVAL; + + return ret; +} + +static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +{ + struct hackrf_dev *dev = video_drvdata(file); + int ret; + + dev_dbg(dev->dev, "index=%d\n", v->index); + + if (v->index == 0) { + strlcpy(v->name, "HackRF ADC", sizeof(v->name)); + v->type = V4L2_TUNER_ADC; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands_adc[0].rangelow; + v->rangehigh = bands_adc[0].rangehigh; + ret = 0; + } else if (v->index == 1) { + strlcpy(v->name, "HackRF RF", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands_rf[0].rangelow; + v->rangehigh = bands_rf[0].rangehigh; + ret = 0; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hackrf_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + int ret; + unsigned int upper, lower; + u8 buf[8]; + + dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); + + if (f->tuner == 0) { + dev->f_adc = clamp_t(unsigned int, f->frequency, + bands_adc[0].rangelow, bands_adc[0].rangehigh); + dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc); + upper = dev->f_adc; + lower = 1; + buf[0] = (upper >> 0) & 0xff; + buf[1] = (upper >> 8) & 0xff; + buf[2] = (upper >> 16) & 0xff; + buf[3] = (upper >> 24) & 0xff; + buf[4] = (lower >> 0) & 0xff; + buf[5] = (lower >> 8) & 0xff; + buf[6] = (lower >> 16) & 0xff; + buf[7] = (lower >> 24) & 0xff; + ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8); + } else if (f->tuner == 1) { + dev->f_rf = clamp_t(unsigned int, f->frequency, + bands_rf[0].rangelow, bands_rf[0].rangehigh); + dev_dbg(dev->dev, "RF frequency=%u Hz\n", dev->f_rf); + upper = dev->f_rf / 1000000; + lower = dev->f_rf % 1000000; + buf[0] = (upper >> 0) & 0xff; + buf[1] = (upper >> 8) & 0xff; + buf[2] = (upper >> 16) & 0xff; + buf[3] = (upper >> 24) & 0xff; + buf[4] = (lower >> 0) & 0xff; + buf[5] = (lower >> 8) & 0xff; + buf[6] = (lower >> 16) & 0xff; + buf[7] = (lower >> 24) & 0xff; + ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8); + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hackrf_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct hackrf_dev *dev = video_drvdata(file); + int ret; + + dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type); + + if (f->tuner == 0) { + f->type = V4L2_TUNER_ADC; + f->frequency = dev->f_adc; + ret = 0; + } else if (f->tuner == 1) { + f->type = V4L2_TUNER_RF; + f->frequency = dev->f_rf; + ret = 0; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hackrf_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + struct hackrf_dev *dev = video_drvdata(file); + int ret; + + dev_dbg(dev->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); + + if (band->tuner == 0) { + if (band->index >= ARRAY_SIZE(bands_adc)) { + ret = -EINVAL; + } else { + *band = bands_adc[band->index]; + ret = 0; + } + } else if (band->tuner == 1) { + if (band->index >= ARRAY_SIZE(bands_rf)) { + ret = -EINVAL; + } else { + *band = bands_rf[band->index]; + ret = 0; + } + } else { + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops hackrf_ioctl_ops = { + .vidioc_querycap = hackrf_querycap, + + .vidioc_s_fmt_sdr_cap = hackrf_s_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = hackrf_g_fmt_sdr_cap, + .vidioc_enum_fmt_sdr_cap = hackrf_enum_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = hackrf_try_fmt_sdr_cap, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .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, + + .vidioc_s_tuner = hackrf_s_tuner, + .vidioc_g_tuner = hackrf_g_tuner, + + .vidioc_s_frequency = hackrf_s_frequency, + .vidioc_g_frequency = hackrf_g_frequency, + .vidioc_enum_freq_bands = hackrf_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +static const struct v4l2_file_operations hackrf_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 struct video_device hackrf_template = { + .name = "HackRF One", + .release = video_device_release_empty, + .fops = &hackrf_fops, + .ioctl_ops = &hackrf_ioctl_ops, +}; + +static void hackrf_video_release(struct v4l2_device *v) +{ + struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev); + + v4l2_ctrl_handler_free(&dev->hdl); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); +} + +static int hackrf_set_bandwidth(struct hackrf_dev *dev) +{ + int ret, i; + u16 u16tmp, u16tmp2; + unsigned int bandwidth; + + static const struct { + u32 freq; + } bandwidth_lut[] = { + { 1750000}, /* 1.75 MHz */ + { 2500000}, /* 2.5 MHz */ + { 3500000}, /* 3.5 MHz */ + { 5000000}, /* 5 MHz */ + { 5500000}, /* 5.5 MHz */ + { 6000000}, /* 6 MHz */ + { 7000000}, /* 7 MHz */ + { 8000000}, /* 8 MHz */ + { 9000000}, /* 9 MHz */ + {10000000}, /* 10 MHz */ + {12000000}, /* 12 MHz */ + {14000000}, /* 14 MHz */ + {15000000}, /* 15 MHz */ + {20000000}, /* 20 MHz */ + {24000000}, /* 24 MHz */ + {28000000}, /* 28 MHz */ + }; + + dev_dbg(dev->dev, "bandwidth auto=%d->%d val=%d->%d f_adc=%u\n", + dev->bandwidth_auto->cur.val, + dev->bandwidth_auto->val, dev->bandwidth->cur.val, + dev->bandwidth->val, dev->f_adc); + + if (dev->bandwidth_auto->val == true) + bandwidth = dev->f_adc; + else + bandwidth = dev->bandwidth->val; + + for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) { + if (bandwidth <= bandwidth_lut[i].freq) { + bandwidth = bandwidth_lut[i].freq; + break; + } + } + + dev->bandwidth->val = bandwidth; + dev->bandwidth->cur.val = bandwidth; + + dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq); + + u16tmp = 0; + u16tmp |= ((bandwidth >> 0) & 0xff) << 0; + u16tmp |= ((bandwidth >> 8) & 0xff) << 8; + u16tmp2 = 0; + u16tmp2 |= ((bandwidth >> 16) & 0xff) << 0; + u16tmp2 |= ((bandwidth >> 24) & 0xff) << 8; + + ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET, + u16tmp, u16tmp2, NULL, 0); + if (ret) + dev_dbg(dev->dev, "failed=%d\n", ret); + + return ret; +} + +static int hackrf_set_lna_gain(struct hackrf_dev *dev) +{ + int ret; + u8 u8tmp; + + dev_dbg(dev->dev, "lna val=%d->%d\n", + dev->lna_gain->cur.val, dev->lna_gain->val); + + ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0, dev->lna_gain->val, + &u8tmp, 1); + if (ret) + dev_dbg(dev->dev, "failed=%d\n", ret); + + return ret; +} + +static int hackrf_set_if_gain(struct hackrf_dev *dev) +{ + int ret; + u8 u8tmp; + + dev_dbg(dev->dev, "val=%d->%d\n", + dev->if_gain->cur.val, dev->if_gain->val); + + ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0, dev->if_gain->val, + &u8tmp, 1); + if (ret) + dev_dbg(dev->dev, "failed=%d\n", ret); + + return ret; +} + +static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct hackrf_dev *dev = container_of(ctrl->handler, + struct hackrf_dev, hdl); + int ret; + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: + case V4L2_CID_RF_TUNER_BANDWIDTH: + ret = hackrf_set_bandwidth(dev); + break; + case V4L2_CID_RF_TUNER_LNA_GAIN: + ret = hackrf_set_lna_gain(dev); + break; + case V4L2_CID_RF_TUNER_IF_GAIN: + ret = hackrf_set_if_gain(dev); + break; + default: + dev_dbg(dev->dev, "unknown ctrl: id=%d name=%s\n", + ctrl->id, ctrl->name); + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops hackrf_ctrl_ops = { + .s_ctrl = hackrf_s_ctrl, +}; + +static int hackrf_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct hackrf_dev *dev; + int ret; + u8 u8tmp, buf[BUF_SIZE]; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + + mutex_init(&dev->v4l2_lock); + mutex_init(&dev->vb_queue_lock); + spin_lock_init(&dev->queued_bufs_lock); + INIT_LIST_HEAD(&dev->queued_bufs); + dev->dev = &intf->dev; + dev->udev = interface_to_usbdev(intf); + dev->f_adc = bands_adc[0].rangelow; + dev->f_rf = bands_rf[0].rangelow; + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; + + /* Detect device */ + ret = hackrf_ctrl_msg(dev, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1); + if (ret == 0) + ret = hackrf_ctrl_msg(dev, CMD_VERSION_STRING_READ, 0, 0, + buf, BUF_SIZE); + if (ret) { + dev_err(dev->dev, "Could not detect board\n"); + goto err_free_mem; + } + + buf[BUF_SIZE - 1] = '\0'; + + dev_info(dev->dev, "Board ID: %02x\n", u8tmp); + dev_info(dev->dev, "Firmware version: %s\n", buf); + + /* Init videobuf2 queue structure */ + dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; + dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + dev->vb_queue.drv_priv = dev; + dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf); + dev->vb_queue.ops = &hackrf_vb2_ops; + dev->vb_queue.mem_ops = &vb2_vmalloc_memops; + dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&dev->vb_queue); + if (ret) { + dev_err(dev->dev, "Could not initialize vb2 queue\n"); + goto err_free_mem; + } + + /* Init video_device structure */ + dev->vdev = hackrf_template; + dev->vdev.queue = &dev->vb_queue; + dev->vdev.queue->lock = &dev->vb_queue_lock; + video_set_drvdata(&dev->vdev, dev); + + /* Register the v4l2_device structure */ + dev->v4l2_dev.release = hackrf_video_release; + ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev); + if (ret) { + dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret); + goto err_free_mem; + } + + /* Register controls */ + v4l2_ctrl_handler_init(&dev->hdl, 4); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops, + V4L2_CID_RF_TUNER_BANDWIDTH, + 1750000, 28000000, 50000, 1750000); + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); + dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0); + dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops, + V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0); + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(dev->dev, "Could not initialize controls\n"); + goto err_free_controls; + } + + v4l2_ctrl_handler_setup(&dev->hdl); + + dev->v4l2_dev.ctrl_handler = &dev->hdl; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->v4l2_lock; + + ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1); + if (ret) { + dev_err(dev->dev, "Failed to register as video device (%d)\n", + ret); + goto err_unregister_v4l2_dev; + } + dev_info(dev->dev, "Registered as %s\n", + video_device_node_name(&dev->vdev)); + dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n"); + return 0; + +err_free_controls: + v4l2_ctrl_handler_free(&dev->hdl); +err_unregister_v4l2_dev: + v4l2_device_unregister(&dev->v4l2_dev); +err_free_mem: + kfree(dev); + return ret; +} + +/* USB device ID list */ +static struct usb_device_id hackrf_id_table[] = { + { USB_DEVICE(0x1d50, 0x6089) }, /* HackRF One */ + { } +}; +MODULE_DEVICE_TABLE(usb, hackrf_id_table); + +/* USB subsystem interface */ +static struct usb_driver hackrf_driver = { + .name = KBUILD_MODNAME, + .probe = hackrf_probe, + .disconnect = hackrf_disconnect, + .id_table = hackrf_id_table, +}; + +module_usb_driver(hackrf_driver); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("HackRF"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e5ab1477bc4d213c602cb7427b6594db35d5c4c4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 10 Sep 2014 04:20:15 -0300 Subject: [media] MAINTAINERS: add HackRF SDR driver HackRF SDR driver. Video4Linux USB device. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6eb60a4e7339..5958dd2bb7cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4172,6 +4172,16 @@ L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes F: drivers/tty/hvc/ +HACKRF 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/hackrf/ + HARDWARE MONITORING M: Jean Delvare M: Guenter Roeck -- cgit v1.2.3 From 720b055d4b2ac8a73118019e1a01d8e6c8f63332 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 21 Sep 2014 20:35:05 -0300 Subject: [media] hackrf: Fix a long constant drivers/media/usb/hackrf/hackrf.c:64:3: warning: this decimal constant is unsigned only in ISO C90 [enabled by default] .rangehigh = 4294967294, /* max u32, hw goes over 7GHz */ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hackrf/hackrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 94276525b037..328b5ba47a0a 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -61,7 +61,7 @@ static const struct v4l2_frequency_band bands_rf[] = { .index = 0, .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, .rangelow = 1, - .rangehigh = 4294967294, /* max u32, hw goes over 7GHz */ + .rangehigh = 4294967294LL, /* max u32, hw goes over 7GHz */ }, }; -- cgit v1.2.3 From e93e7fd9f5a3fffec7792dbcc4c3574653effda7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 9 Sep 2014 04:42:43 -0300 Subject: [media] v4l2: uvcvideo: Allow using larger buffers A test in uvc_video_decode_isoc() checks whether an image has been received from the camera completely. For this the data amount is compared to the buffer length, which, however, doesn't have to be equal to the image size. Switch to using formats .sizeimage field for an exact expected image size. [Renamed image_size to frame_size] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 1 + drivers/media/usb/uvc/uvc_video.c | 2 +- drivers/media/usb/uvc/uvcvideo.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 378ae02e593b..60a8e2c3631e 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -318,6 +318,7 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; + stream->frame_size = fmt->fmt.pix.sizeimage; done: mutex_unlock(&stream->mutex); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index a2bddf48171f..9ace520bb079 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1143,7 +1143,7 @@ static int uvc_video_encode_data(struct uvc_streaming *stream, static void uvc_video_validate_buffer(const struct uvc_streaming *stream, struct uvc_buffer *buf) { - if (buf->length != buf->bytesused && + if (stream->frame_size != buf->bytesused && !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)) buf->error = 1; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 39c4f941b63d..6f676c29ec09 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -457,6 +457,8 @@ struct uvc_streaming { struct uvc_format *def_format; struct uvc_format *cur_format; struct uvc_frame *cur_frame; + size_t frame_size; + /* Protect access to ctrl, cur_format, cur_frame and hardware video * probe control. */ -- cgit v1.2.3 From 625c3442dcc79722c60afc398beac4c11f0395ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Sep 2014 06:28:02 -0300 Subject: [media] DocBook media: fix wrong prototype G_EDID is an RW ioctl, so the struct v4l2_edid isn't const. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-g-edid.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml index fa91651978e0..6df40db4c8ba 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml @@ -24,7 +24,7 @@ int ioctl int fd int request - const struct v4l2_edid *argp + struct v4l2_edid *argp -- cgit v1.2.3 From 62f28725a8dc5c16d3d63606f046899ae41fcf4a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 06:11:44 -0300 Subject: [media] vivid: add teletext support to VBI capture This is useful to test teletext capture applications like alevt and mtt. It also fixes a previously undetected bug where the PAL VBI start line of the second field was off by one. Using the new field start defines helps a lot fixing such bugs. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/vivid.txt | 10 ++-- drivers/media/platform/vivid/vivid-vbi-cap.c | 43 +++++++++++----- drivers/media/platform/vivid/vivid-vbi-gen.c | 76 +++++++++++++++++++++++++++- drivers/media/platform/vivid/vivid-vbi-gen.h | 2 +- drivers/media/platform/vivid/vivid-vbi-out.c | 7 +-- drivers/media/platform/vivid/vivid-vid-cap.c | 2 +- drivers/media/platform/vivid/vivid-vid-out.c | 2 +- 7 files changed, 117 insertions(+), 25 deletions(-) diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt index 4f1d4424f563..eeb11a28e4fc 100644 --- a/Documentation/video4linux/vivid.txt +++ b/Documentation/video4linux/vivid.txt @@ -422,7 +422,7 @@ generate Closed Caption and XDS data. The closed caption stream will alternate between "Hello world!" and "Closed captions test" every second. The XDS stream will give the current time once a minute. For 50 Hz standards it will generate the Wide Screen Signal which is based on the actual Video -Aspect Ratio control setting. +Aspect Ratio control setting and teletext pages 100-159, one page per frame. The VBI device will only work for the S-Video and TV inputs, it will give back an error if the current input is a webcam or HDMI. @@ -435,8 +435,8 @@ There are three types of VBI output devices: those that only support raw (undecoded) VBI, those that only support sliced (decoded) VBI and those that support both. This is determined by the node_types module option. -The sliced VBI output supports the Wide Screen Signal for 50 Hz standards -and Closed Captioning + XDS for 60 Hz standards. +The sliced VBI output supports the Wide Screen Signal and the teletext signal +for 50 Hz standards and Closed Captioning + XDS for 60 Hz standards. The VBI device will only work for the S-Video output, it will give back an error if the current output is HDMI. @@ -910,7 +910,8 @@ capture device. For VBI looping to work all of the above must be valid and in addition the vbi output must be configured for sliced VBI. The VBI capture side can be configured -for either raw or sliced VBI. +for either raw or sliced VBI. Note that at the moment only CC/XDS (60 Hz formats) +and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped. Section 10.2: Radio & RDS Looping @@ -1090,6 +1091,7 @@ Just as a reminder and in no particular order: - Add virtual sub-devices and media controller support - Some support for testing compressed video - Add support to loop raw VBI output to raw VBI input +- Add support to loop teletext sliced VBI output to VBI input - Fix sequence/field numbering when looping of video with alternate fields - Add support for V4L2_CID_BG_COLOR for video outputs - Add ARGB888 overlay support: better testing of the alpha channel diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index e239cfdc030d..2166d0bf6fe2 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -37,25 +37,25 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) if (!is_60hz) { if (dev->loop_video) { if (dev->vbi_out_have_wss) { - vbi_gen->data[0].data[0] = dev->vbi_out_wss[0]; - vbi_gen->data[0].data[1] = dev->vbi_out_wss[1]; + vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; + vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; } else { - vbi_gen->data[0].id = 0; + vbi_gen->data[12].id = 0; } } else { switch (tpg_g_video_aspect(&dev->tpg)) { case TPG_VIDEO_ASPECT_14X9_CENTRE: - vbi_gen->data[0].data[0] = 0x01; + vbi_gen->data[12].data[0] = 0x01; break; case TPG_VIDEO_ASPECT_16X9_CENTRE: - vbi_gen->data[0].data[0] = 0x0b; + vbi_gen->data[12].data[0] = 0x0b; break; case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: - vbi_gen->data[0].data[0] = 0x07; + vbi_gen->data[12].data[0] = 0x07; break; case TPG_VIDEO_ASPECT_4X3: default: - vbi_gen->data[0].data[0] = 0x08; + vbi_gen->data[12].data[0] = 0x08; break; } } @@ -83,8 +83,8 @@ static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *v vbi->offset = 24; vbi->samples_per_line = 1440; vbi->sample_format = V4L2_PIX_FMT_GREY; - vbi->start[0] = is_60hz ? 10 : 6; - vbi->start[1] = is_60hz ? 273 : 318; + vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; + vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; vbi->reserved[0] = 0; @@ -125,8 +125,10 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *bu memset(vbuf, 0, vb2_plane_size(&buf->vb, 0)); if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { - vbuf[0] = dev->vbi_gen.data[0]; - vbuf[1] = dev->vbi_gen.data[1]; + unsigned i; + + for (i = 0; i < 25; i++) + vbuf[i] = dev->vbi_gen.data[i]; } v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); @@ -280,8 +282,14 @@ void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_se vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; } - if (vbi->service_set & V4L2_SLICED_WSS_625) + if (vbi->service_set & V4L2_SLICED_WSS_625) { + unsigned i; + + for (i = 7; i <= 18; i++) + vbi->service_lines[0][i] = + vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; + } } int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) @@ -306,7 +314,8 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) return -EINVAL; - service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; vivid_fill_service_lines(vbi, service_set); return 0; } @@ -345,11 +354,17 @@ int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_ return -EINVAL; } - cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; if (is_60hz) { cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; } else { + unsigned i; + + for (i = 7; i <= 18; i++) + cap->service_lines[0][i] = + cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; cap->service_lines[0][23] = V4L2_SLICED_WSS_625; } return 0; diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c index 450ec3ca5d9a..a2159de83d0b 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -57,6 +57,27 @@ static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data, } } +static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 6937500 / 10; /* Teletext has a 6.9375 MHz transmission rate */ + u8 teletext[45] = { 0x55, 0x55, 0x27 }; + unsigned bit = 0; + int i; + + memcpy(teletext + 3, data->data, sizeof(teletext) - 3); + /* prevents 32 bit overflow */ + sampling_rate /= 10; + + for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10; + + while (i < n) + buf[i++] = val; + } +} + static void cc_insert(u8 *cc, u8 ch) { unsigned tot = 0; @@ -102,7 +123,7 @@ void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, { unsigned idx; - for (idx = 0; idx < 2; idx++) { + for (idx = 0; idx < 25; idx++) { const struct v4l2_sliced_vbi_data *data = vbi->data + idx; unsigned start_2nd_field; unsigned line = data->line; @@ -123,6 +144,8 @@ void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate); else if (data->id == V4L2_SLICED_WSS_625) vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate); + else if (data->id == V4L2_SLICED_TELETEXT_B) + vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate); } } @@ -197,6 +220,41 @@ static void vivid_vbi_gen_set_time_of_day(u8 *packet) packet[15] = calc_parity(0x100 - checksum); } +static const u8 hamming[16] = { + 0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f, + 0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea +}; + +static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame) +{ + unsigned offset = 2; + unsigned i; + + packet[0] = hamming[1 + ((line & 1) << 3)]; + packet[1] = hamming[line >> 1]; + memset(packet + 2, 0x20, 40); + if (line == 0) { + /* subcode */ + packet[2] = hamming[frame % 10]; + packet[3] = hamming[frame / 10]; + packet[4] = hamming[0]; + packet[5] = hamming[0]; + packet[6] = hamming[0]; + packet[7] = hamming[0]; + packet[8] = hamming[0]; + packet[9] = hamming[1]; + offset = 10; + } + packet += offset; + memcpy(packet, "Page: 100 Row: 10", 17); + packet[7] = '0' + frame / 10; + packet[8] = '0' + frame % 10; + packet[15] = '0' + line / 10; + packet[16] = '0' + line % 10; + for (i = 0; i < 42 - offset; i++) + packet[i] = calc_parity(packet[i]); +} + void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, bool is_60hz, unsigned seqnr) { @@ -207,10 +265,26 @@ void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, memset(vbi->data, 0, sizeof(vbi->data)); if (!is_60hz) { + unsigned i; + + for (i = 0; i <= 11; i++) { + data0->id = V4L2_SLICED_TELETEXT_B; + data0->line = 7 + i; + vivid_vbi_gen_teletext(data0->data, i, frame); + data0++; + } data0->id = V4L2_SLICED_WSS_625; data0->line = 23; /* 4x3 video aspect ratio */ data0->data[0] = 0x08; + data0++; + for (i = 0; i <= 11; i++) { + data0->id = V4L2_SLICED_TELETEXT_B; + data0->field = 1; + data0->line = 7 + i; + vivid_vbi_gen_teletext(data0->data, 12 + i, frame); + data0++; + } return; } diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h index 401dd47c0f1d..8444abe905ea 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.h +++ b/drivers/media/platform/vivid/vivid-vbi-gen.h @@ -21,7 +21,7 @@ #define _VIVID_VBI_GEN_H_ struct vivid_vbi_gen_data { - struct v4l2_sliced_vbi_data data[2]; + struct v4l2_sliced_vbi_data data[25]; u8 time_of_day_packet[16]; }; diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index 039316d835b4..9d00a07ecdcd 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -149,8 +149,8 @@ int vidioc_g_fmt_vbi_out(struct file *file, void *priv, vbi->offset = 24; vbi->samples_per_line = 1440; vbi->sample_format = V4L2_PIX_FMT_GREY; - vbi->start[0] = is_60hz ? 10 : 6; - vbi->start[1] = is_60hz ? 273 : 318; + vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; + vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; vbi->reserved[0] = 0; @@ -195,7 +195,8 @@ int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_forma if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) return -EINVAL; - service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : V4L2_SLICED_WSS_625; + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; vivid_fill_service_lines(vbi, service_set); return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index b016aeda7ff3..331c54429b40 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -419,7 +419,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) } else { dev->src_rect.height = 576; dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 }; - dev->service_set_cap = V4L2_SLICED_WSS_625; + dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; } tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); break; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index d0e0e955b3de..69c2dbd2d165 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -234,7 +234,7 @@ void vivid_update_format_out(struct vivid_dev *dev) } else { dev->sink_rect.height = 576; dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 }; - dev->service_set_out = V4L2_SLICED_WSS_625; + dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; } dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; break; -- cgit v1.2.3 From c166845c9c452e9639a2e8b44581ce95942e89a5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 07:36:38 -0300 Subject: [media] v4l2-dv-timings: only check standards if non-zero If one or both of the timings being compared have the standards field with value 0, then accept that. Only check for matching standards if both timings have actually filled in that field. Otherwise no match will ever be found since when timings are detected the standards field will typically be set to 0 by the driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index ce1c9f5d9dee..b1d8dbb39665 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -164,7 +164,8 @@ bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t, bt->width > cap->max_width || bt->pixelclock < cap->min_pixelclock || bt->pixelclock > cap->max_pixelclock || - (cap->standards && !(bt->standards & cap->standards)) || + (cap->standards && bt->standards && + !(bt->standards & cap->standards)) || (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) || (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE))) return false; -- cgit v1.2.3 From f8789e6d9c824aeaeeb5b44b926dc8e960487cfe Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 07:36:39 -0300 Subject: [media] adv7604/adv7842: fix il_vbackporch typo and zero the struct Both adv7604 and adv7842 had the same typo in the code that sets the vertical backporch for the second interlaced field: it was assigned to vbackporch instead of il_vbackporch. In addition, the timings struct wasn't zeroed in the adv7842 driver, leaving several fields to undefined values causing the timing match function to fail. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/adv7842.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index d4fa213ba74a..a836de6cb73c 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1593,7 +1593,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, bt->height += hdmi_read16(sd, 0x0b, 0xfff); bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2; bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; - bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; + bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; } adv7604_fill_optional_dv_timings_fields(sd, timings); } else { diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 0d554919cdd5..48b628bc6714 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1435,6 +1435,8 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s:\n", __func__); + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + /* SDP block */ if (state->mode == ADV7842_MODE_SDP) return -ENODATA; @@ -1483,7 +1485,7 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, hdmi_read(sd, 0x2d)) / 2; bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + hdmi_read(sd, 0x31)) / 2; - bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + + bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + hdmi_read(sd, 0x35)) / 2; } adv7842_fill_optional_dv_timings_fields(sd, timings); -- cgit v1.2.3 From 420b21761986dc16521e72951b9fc6e5d0a515df Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 10:19:32 -0300 Subject: [media] cx23885: fix VBI support Tested VBI support and discovered that the wrong offset was used. After this change it is now working. Verified with CC/XDS for NTSC and WSS/Teletext on PAL. It also reported the wrong start lines for the second field. That's now fixed as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 4 ++-- drivers/media/pci/cx23885/cx23885-vbi.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index cb94366b9504..331eddac7222 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1228,11 +1228,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, /* Sync to line 6, so US CC line 21 will appear in line '12' * in the userland vbi payload */ if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 6, + rp = cx23885_risc_field(rp, sglist, top_offset, 0, bpl, padding, lines, 0, true); if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, bpl, padding, lines, 0, UNSET == top_offset); diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 67b71f9b41f4..a7c6ef8f3ea3 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -54,14 +54,14 @@ int cx23885_vbi_fmt(struct file *file, void *priv, f->fmt.vbi.flags = 0; if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 272; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9; f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT; f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ - f->fmt.vbi.start[0] = 6; - f->fmt.vbi.start[1] = 318; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5; f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT; f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT; } -- cgit v1.2.3 From 1c5eaa23d8fb8bb8c0f4707eeb456a870d7c18c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 10:19:33 -0300 Subject: [media] cx23885: fix size helper functions The norm_swidth function was unused and is dropped. It's not clear what the purpose of that function was. The norm_maxh function was changed so it tests for 60 Hz standards rather than for 50 Hz standards. The is the preferred order. The norm_maxw function was poorly written and used: it gives the maximum allowed line width for the given standard. For 60 Hz that's 720, but for 50 Hz that's 768 which allows for 768x576 which gives you square pixels. For 60 Hz formats it is 640x480 that gives square pixels, so there is no need to go beyond 720. The initial width was set using norm_maxh(), which was wrong. Just set to 720, that's what you normally use. Since the initial standard was NTSC anyway the initial width was always 720 anyway. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 2 +- drivers/media/pci/cx23885/cx23885.h | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index f0ea904d4669..682a4f95df6b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1154,7 +1154,7 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->tvnorm = V4L2_STD_NTSC_M; dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); dev->field = V4L2_FIELD_INTERLACED; - dev->width = norm_maxw(dev->tvnorm); + dev->width = 720; dev->height = norm_maxh(dev->tvnorm); /* init video dma queues */ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0e4f4061087f..39a89855d1d5 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -612,15 +612,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci, static inline unsigned int norm_maxw(v4l2_std_id norm) { - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; + return (norm & V4L2_STD_525_60) ? 720 : 768; } static inline unsigned int norm_maxh(v4l2_std_id norm) { - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -static inline unsigned int norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; + return (norm & V4L2_STD_525_60) ? 480 : 576; } -- cgit v1.2.3 From 312487ccfde9df5e39cd23d1c686b5cce8bab046 Mon Sep 17 00:00:00 2001 From: Morgan Phillips Date: Mon, 8 Sep 2014 09:32:22 -0300 Subject: [media] sn9c20x.c: fix checkpatch error: that open brace { should be on the previous line Signed-off-by: Morgan Phillips Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sn9c20x.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 41a9a892f79c..95467f009d47 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1787,8 +1787,9 @@ static int sd_init(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int i; u8 value; - u8 i2c_init[9] = - {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}; + u8 i2c_init[9] = { + 0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + }; for (i = 0; i < ARRAY_SIZE(bridge_init); i++) { value = bridge_init[i][1]; @@ -2242,8 +2243,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; int avg_lum, is_jpeg; - static const u8 frame_header[] = - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; + static const u8 frame_header[] = { + 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96 + }; is_jpeg = (sd->fmt & 0x03) == 0; if (len >= 64 && memcmp(data, frame_header, 6) == 0) { -- cgit v1.2.3 From e0aa2b28d4b5cdf3d878331bce88d05b303304a0 Mon Sep 17 00:00:00 2001 From: Morgan Phillips Date: Mon, 8 Sep 2014 09:49:47 -0300 Subject: [media] sn9c20x: fix checkpatch warning: sizeof cmatrix should be sizeof(cmatrix) Signed-off-by: Morgan Phillips Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sn9c20x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 95467f009d47..d0ee899584a9 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1297,7 +1297,7 @@ static void set_cmatrix(struct gspca_dev *gspca_dev, s32 hue_coord, hue_index = 180 + hue; u8 cmatrix[21]; - memset(cmatrix, 0, sizeof cmatrix); + memset(cmatrix, 0, sizeof(cmatrix)); cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26; cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; -- cgit v1.2.3 From eb500df22c930f5185bcfc66fd501358d45ce071 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 19 Sep 2014 13:02:11 -0300 Subject: [media] em28xx: Get rid of some unused modprobe parameters at vbi code There are two modprobe parameters for VBI that aren't used anywhere (one for debug, the other one related to the buffer size). Get rid of them! Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-vbi.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 6d7f657f6f55..34ee1e03a732 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -29,17 +29,6 @@ #include "em28xx.h" #include "em28xx-v4l.h" -static unsigned int vbibufs = 5; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - -static unsigned int vbi_debug; -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); - -#define dprintk(level, fmt, arg...) if (vbi_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) - /* ------------------------------------------------------------------ */ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, -- cgit v1.2.3 From 6694ba62c7231f68f12a2d9466bcbdf734637f04 Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Mon, 4 Aug 2014 17:04:52 -0300 Subject: [media] drivers/media/dvb-frontends/stv0900_sw.c: Fix break placement Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81621 Reported-by: David Binderman Signed-off-by: Andrey Utkin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0900_sw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index 4ce1d260b3eb..a0a7b1664c53 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1733,9 +1733,10 @@ static void stv0900_set_search_standard(struct stv0900_internal *intp, break; case STV0900_SEARCH_DSS: dprintk("Search Standard = DSS\n"); - case STV0900_SEARCH_DVBS2: break; + case STV0900_SEARCH_DVBS2: dprintk("Search Standard = DVBS2\n"); + break; case STV0900_AUTO_SEARCH: default: dprintk("Search Standard = AUTO\n"); -- cgit v1.2.3 From a375218460a625f15b5403d15d9a67d8f8951177 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 7 Aug 2014 02:41:45 -0300 Subject: [media] dvb: remove 0x prefix from decimal value in printf The returned code is 0, 1 or an error. It doesn't make sense to print it in hexadecimal. Signed-off-by: Hans Wennborg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 1827c0a29e95..bc9a0adda3cb 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -115,7 +115,7 @@ static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) }; ret = i2c_transfer(state->i2c_adap, msg, 2); if (ret != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)", + dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)", reg, ret); return -EREMOTEIO; -- cgit v1.2.3 From 612f676bbef9b937764db453c931ea48be8020ef Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 7 Aug 2014 02:42:04 -0300 Subject: [media] dvb: return the error from i2c_transfer if negative Just returns whatever error that was returned by the i2c core, in the case of errors, only returning -EREMOTEIO if the transfer size is not what it was expected. Signed-off-by: Hans Wennborg Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a16.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index bc9a0adda3cb..3ddea4471d2b 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -118,6 +118,8 @@ static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)", reg, ret); + if (ret < 0) + return ret; return -EREMOTEIO; } *val = b1[0]; -- cgit v1.2.3 From 9408d8f0f86b9eaafc3c5a07f148f009a6abcfc6 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 15 Aug 2014 13:18:53 -0300 Subject: [media] media/rc/imon.c: use USB API functions rather than constants This patch introduces the use of the function usb_endpoint_type. The Coccinelle semantic patch that makes these changes is as follows: @@ struct usb_endpoint_descriptor *epd; @@ - (epd->bmAttributes & \(USB_ENDPOINT_XFERTYPE_MASK\|3\)) + usb_endpoint_type(epd) Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index cd511a7b4cab..74daceec2f74 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2123,7 +2123,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { ep = &iface_desc->endpoint[i].desc; ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; - ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + ep_type = usb_endpoint_type(ep); if (!ir_ep_found && ep_dir == USB_DIR_IN && ep_type == USB_ENDPOINT_XFER_INT) { -- cgit v1.2.3 From 5611588b86492eded428cad0f698c39178f88d23 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 15 Aug 2014 13:22:35 -0300 Subject: [media] rc-core: use USB API functions rather than constants This patch introduces the use of !usb_endpoint_dir_in(epd) and !usb_endpoint_xfer_int(epd). The Coccinelle semantic patch that makes these changes is as follows: - ((epd->bEndpointAddress & \(USB_ENDPOINT_DIR_MASK\|0x80\)) != - \(USB_DIR_IN\|0x80\)) + !usb_endpoint_dir_in(epd) @@ struct usb_endpoint_descriptor *epd; @@ - ((epd->bmAttributes & \(USB_ENDPOINT_XFERTYPE_MASK\|3\)) != - \(USB_ENDPOINT_XFER_INT\|3\)) + !usb_endpoint_xfer_int(epd) Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/streamzap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 80c4feeb01ea..bf4a44272f0e 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -362,16 +362,14 @@ static int streamzap_probe(struct usb_interface *intf, } sz->endpoint = &(iface_host->endpoint[0].desc); - if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - != USB_DIR_IN) { + if (!usb_endpoint_dir_in(sz->endpoint)) { dev_err(&intf->dev, "%s: endpoint doesn't match input device " "02%02x\n", __func__, sz->endpoint->bEndpointAddress); retval = -ENODEV; goto free_sz; } - if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) { + if (!usb_endpoint_xfer_int(sz->endpoint)) { dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " "02%02x\n", __func__, sz->endpoint->bmAttributes); retval = -ENODEV; -- cgit v1.2.3 From 78e719a5f30b7017b575c08220f4480e3140c6f1 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 15 Aug 2014 15:16:58 -0300 Subject: [media] em28xx-input: i2c IR decoders: improve i2c_client handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using a temporary stack allocated i2c_client in em28xx_i2c_ir_handle_key(), allocate/free the i2c_client at module init/uninit and hook it into struct em28xx_IR (if the device has an i2c IR decoder). This reduces the frame size of function em28xx_i2c_ir_handle_key() and speeds it up a bit. Also make sure that all fields of struct i2c_client are initialized properly. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index e978a2ae6f21..581f6dad4ca9 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -71,8 +71,7 @@ struct em28xx_IR { unsigned int last_readcount; u64 rc_type; - /* i2c slave address of external device (if used) */ - u16 i2c_dev_addr; + struct i2c_client *i2c_client; int (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode); int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); @@ -294,16 +293,11 @@ 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 scancode; enum rc_type protocol; int rc; - struct i2c_client client; - - client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus]; - client.addr = ir->i2c_dev_addr; - rc = ir->get_key_i2c(&client, &protocol, &scancode); + rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode); if (rc < 0) { dprintk("ir->get_key_i2c() failed: %d\n", rc); return rc; @@ -361,7 +355,7 @@ static void em28xx_ir_work(struct work_struct *work) { struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work); - if (ir->i2c_dev_addr) /* external i2c device */ + if (ir->i2c_client) /* external i2c device */ em28xx_i2c_ir_handle_key(ir); else /* internal device */ em28xx_ir_handle_key(ir); @@ -756,7 +750,13 @@ static int em28xx_ir_init(struct em28xx *dev) goto error; } - ir->i2c_dev_addr = i2c_rc_dev_addr; + ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!ir->i2c_client) + goto error; + ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus]; + ir->i2c_client->addr = i2c_rc_dev_addr; + ir->i2c_client->flags = 0; + /* NOTE: all other fields of i2c_client are unused */ } else { /* internal device */ switch (dev->chip_id) { case CHIP_ID_EM2860: @@ -815,6 +815,7 @@ static int em28xx_ir_init(struct em28xx *dev) return 0; error: + kfree(ir->i2c_client); dev->ir = NULL; rc_free_device(rc); kfree(ir); @@ -841,6 +842,8 @@ static int em28xx_ir_fini(struct em28xx *dev) if (ir->rc) rc_unregister_device(ir->rc); + kfree(ir->i2c_client); + /* done */ kfree(ir); dev->ir = NULL; -- cgit v1.2.3 From eafeda9666f634abc1b133ee4b578708269d99ab Mon Sep 17 00:00:00 2001 From: Maks Naumov Date: Fri, 15 Aug 2014 16:23:20 -0300 Subject: [media] media: stv0367: fix frontend modulation initialization with FE_CAB_MOD_QAM256 It was using the wrong constant for QAM256 on get_frontend. Signed-off-by: Maks Naumov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 59f622ae80e8..7f010683dbf8 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -3163,7 +3163,7 @@ static int stv0367cab_get_frontend(struct dvb_frontend *fe) case FE_CAB_MOD_QAM128: p->modulation = QAM_128; break; - case QAM_256: + case FE_CAB_MOD_QAM256: p->modulation = QAM_256; break; default: -- cgit v1.2.3 From 886da6ac33ac7e82392f1bc8b7b25b058710a269 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Sep 2014 17:36:53 -0300 Subject: [media] stv0367: Remove an unused parameter cab_state->modulation is initialized with a wrong value: drivers/media/dvb-frontends/stv0367.c:3000:42: warning: mixing different enum types drivers/media/dvb-frontends/stv0367.c:3000:42: int enum fe_modulation versus drivers/media/dvb-frontends/stv0367.c:3000:42: int enum stv0367cab_mod as it was declared as "enum stv0367cab_mod". While it could be fixed, there's no value on it, as this is never used. So, just remove the modulation from cab_state structure. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0367.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 7f010683dbf8..b31ff265ff24 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -59,7 +59,6 @@ struct stv0367cab_state { int locked; /* channel found */ u32 freq_khz; /* found frequency (in kHz) */ u32 symbol_rate; /* found symbol rate (in Bds) */ - enum stv0367cab_mod modulation; /* modulation */ fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ }; @@ -2997,7 +2996,6 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, if (QAMFEC_Lock) { signalType = FE_CAB_DATAOK; - cab_state->modulation = p->modulation; cab_state->spect_inv = stv0367_readbits(state, F367CAB_QUAD_INV); #if 0 -- cgit v1.2.3 From 1ba3f927ad66759b0081fe1f96d77500c9a622c3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Sep 2014 17:48:01 -0300 Subject: [media] au0828-cards: remove a comment about i2c clock stretching This comment is already at the au0828-i2c where it belongs. So, remove it from a board's entry. It doesn't make any sense there, as we're setting the clock to 250kHz there, slowing it down only at the au0828-i2c. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index d229c6dbddb9..585a8f84228c 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -73,12 +73,6 @@ struct au0828_board au0828_boards[] = { .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, .has_ir_i2c = 1, - /* The au0828 hardware i2c implementation does not properly - support the xc5000's i2c clock stretching. So we need to - lower the clock frequency enough where the 15us clock - stretch fits inside of a normal clock cycle, or else the - au0828 fails to set the STOP bit. A 30 KHz clock puts the - clock pulse width at 18us */ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, .input = { { -- cgit v1.2.3 From b13b47e0b5eecbd18ebaa7f6657ca0f53eb783a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Aug 2014 08:51:28 -0300 Subject: [media] au0828: explicitly identify boards with analog TV Right now, the au0828 driver uses .tuner to detect if analog tv is being used or not. By not filling .tuner fields at the board struct, the I2C core can't do decisions based on it. So, add a field to explicitly tell when analog TV is supported. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 4 +++- drivers/media/usb/au0828/au0828.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 585a8f84228c..9fd3c4b222f6 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -47,6 +47,7 @@ struct au0828_board au0828_boards[] = { .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, .has_ir_i2c = 1, + .has_analog = 1, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, .input = { { @@ -73,6 +74,7 @@ struct au0828_board au0828_boards[] = { .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, .has_ir_i2c = 1, + .has_analog = 1, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, .input = { { @@ -226,7 +228,7 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) } /* Setup tuners */ - if (dev->board.tuner_type != TUNER_ABSENT) { + if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) { /* Load the tuner module, which does the attach */ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tuner", dev->board.tuner_addr, NULL); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index a7cc6e397fdd..36815a369c68 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -90,6 +90,7 @@ struct au0828_board { unsigned char tuner_addr; unsigned char i2c_clk_divider; unsigned char has_ir_i2c:1; + unsigned char has_analog:1; struct au0828_input input[AU0828_MAX_INPUT]; }; -- cgit v1.2.3 From 5d40018623a53f5e21cb3393ab9ef2a3a7bc57dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Aug 2014 08:51:29 -0300 Subject: [media] au0828: fill tuner type on all boards This is used by the I2C code in order to slow down the speed to 20 kHz on devices with xc5000 or xc5000c. So, it needs to be filled for all devices that use either xc5000 or xc5000c. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 9fd3c4b222f6..9eb77ac2153b 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -98,20 +98,20 @@ struct au0828_board au0828_boards[] = { }, [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { .name = "Hauppauge HVR950Q rev xxF8", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, }, [AU0828_BOARD_DVICO_FUSIONHDTV7] = { .name = "DViCO FusionHDTV USB", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, }, [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { .name = "Hauppauge Woodbury", - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, }, }; -- cgit v1.2.3 From 1148f6fdb0136b6cf9ec5e1ff6db2dfa899b3906 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 08:20:23 -0300 Subject: [media] v4l: ti-vpe: use c99 initializers in structures Use c99 initializers for structures. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @decl@ identifier i1,fld; type T; field list[n] fs; @@ struct i1 { fs T fld; ...}; @bad@ identifier decl.i1,i2; expression e; initializer list[decl.n] is; @@ struct i1 i2 = { is, + .fld = e - e ,...}; // Signed-off-by: Julia Lawall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index febeca70211b..7c3c7469da1d 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -139,12 +139,12 @@ struct vpe_dei_regs { * default expert DEI register values, unlikely to be modified. */ static const struct vpe_dei_regs dei_regs = { - 0x020C0804u, - 0x0118100Fu, - 0x08040200u, - 0x1010100Cu, - 0x10101010u, - 0x10101010u, + .mdt_spacial_freq_thr_reg = 0x020C0804u, + .edi_config_reg = 0x0118100Fu, + .edi_lut_reg0 = 0x08040200u, + .edi_lut_reg1 = 0x1010100Cu, + .edi_lut_reg2 = 0x10101010u, + .edi_lut_reg3 = 0x10101010u, }; /* -- cgit v1.2.3 From 09628b2c2105722e61b8c799531304a1cd317b2e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 22 Sep 2014 18:57:45 -0300 Subject: [media] dib0700_devices: Use c99 initializers for structures. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @decl@ identifier i1,fld; type T; field list[n] fs; @@ struct i1 { fs T fld; ...}; @bad@ identifier decl.i1,i2; expression e; initializer list[decl.n] is; @@ struct i1 i2 = { is, + .fld = e - e ,...}; // Not sure why, but some tables are still using the old way, but at least several of them got fixed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dib0700_devices.c | 383 +++++++++++++++------------- 1 file changed, 211 insertions(+), 172 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index ce47d3f1c850..e1757b8f5f5d 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -220,12 +220,21 @@ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - 0, - 20452225, + .internal = 60000, + .sampling = 30000, + .pll_prediv = 1, + .pll_ratio = 8, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = 0, + .timf = 20452225, }; static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { @@ -342,57 +351,57 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ static struct dibx000_agc_config xc3028_agc_config = { - BAND_VHF | BAND_UHF, /* band_caps */ - + .band_caps = BAND_VHF | BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0, * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | - (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */ - - 712, /* inv_gain */ - 21, /* time_stabiliz */ - - 0, /* alpha_level */ - 118, /* thlock */ - - 0, /* wbd_inv */ - 2867, /* wbd_ref */ - 0, /* wbd_sel */ - 2, /* wbd_alpha */ - - 0, /* agc1_max */ - 0, /* agc1_min */ - 39718, /* agc2_max */ - 9930, /* agc2_min */ - 0, /* agc1_pt1 */ - 0, /* agc1_pt2 */ - 0, /* agc1_pt3 */ - 0, /* agc1_slope1 */ - 0, /* agc1_slope2 */ - 0, /* agc2_pt1 */ - 128, /* agc2_pt2 */ - 29, /* agc2_slope1 */ - 29, /* agc2_slope2 */ - - 17, /* alpha_mant */ - 27, /* alpha_exp */ - 23, /* beta_mant */ - 51, /* beta_exp */ - - 1, /* perform_agc_softsplit */ + .setup = (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + .inv_gain = 712, + .time_stabiliz = 21, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 2867, + .wbd_sel = 0, + .wbd_alpha = 2, + .agc1_max = 0, + .agc1_min = 0, + .agc2_max = 39718, + .agc2_min = 9930, + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 0, + .agc1_slope1 = 0, + .agc1_slope2 = 0, + .agc2_pt1 = 0, + .agc2_pt2 = 128, + .agc2_slope1 = 29, + .agc2_slope2 = 29, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 1, }; /* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */ static struct dibx000_bandwidth_config xc3028_bw_config = { - 60000, 30000, /* internal, sampling */ - 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ - 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, - modulo */ - (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ - (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ - 20452225, /* timf */ - 30000000, /* xtal_hz */ + .internal = 60000, + .sampling = 30000, + .pll_prediv = 1, + .pll_ratio = 8, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 0, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */ + .ifreq = (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */ + .timf = 20452225, + .xtal_hz = 30000000, }; static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { @@ -614,59 +623,55 @@ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { }; static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { - BAND_UHF | BAND_VHF, - + .band_caps = BAND_UHF | BAND_VHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - - 712, - 41, - - 0, - 118, - - 0, - 4095, - 0, - 0, - - 42598, - 16384, - 42598, - 0, - - 0, - 137, - 255, - - 0, - 255, - - 0, - 0, - - 0, - 41, - - 15, - 25, - - 28, - 48, - - 0, + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + .inv_gain = 712, + .time_stabiliz = 41, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 4095, + .wbd_sel = 0, + .wbd_alpha = 0, + .agc1_max = 42598, + .agc1_min = 16384, + .agc2_max = 42598, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 137, + .agc1_pt3 = 255, + .agc1_slope1 = 0, + .agc1_slope2 = 255, + .agc2_pt1 = 0, + .agc2_pt2 = 0, + .agc2_slope1 = 0, + .agc2_slope2 = 41, + .alpha_mant = 15, + .alpha_exp = 25, + .beta_mant = 28, + .beta_exp = 48, + .perform_agc_softsplit = 0, }; static struct dibx000_bandwidth_config stk7700p_pll_config = { - 60000, 30000, - 1, 8, 3, 1, 0, - 0, 0, 1, 1, 0, - (3 << 14) | (1 << 12) | (524 << 0), - 60258167, - 20452225, - 30000000, + .internal = 60000, + .sampling = 30000, + .pll_prediv = 1, + .pll_ratio = 8, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 0, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = 60258167, + .timf = 20452225, + .xtal_hz = 30000000, }; static struct dib7000m_config stk7700p_dib7000m_config = { @@ -758,45 +763,36 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) /* DIB7070 generic */ static struct dibx000_agc_config dib7070_agc_config = { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) - | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - - 600, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, - - 65535, - 0, - - 65535, - 0, - - 0, - 40, - 183, - 206, - 255, - 72, - 152, - 88, - 90, - - 17, - 27, - 23, - 51, - - 0, + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, }; static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -952,13 +948,22 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - 60000, 15000, - 1, 20, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 12000000, + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, }; static struct dib7000p_config dib7070p_dib7000p_config = { @@ -1169,14 +1174,22 @@ static struct dibx000_agc_config dib807x_agc_config[2] = { }; static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = { - 60000, 15000, /* internal, sampling*/ - 1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/ - 0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core, - ADClkSrc, modulo */ - (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ - (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ - 18179755, /* timf*/ - 12000000, /* xtal_hz*/ + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/ + .ifreq = (0 << 25) | 0, /* ifreq = 0.000000 MHz*/ + .timf = 18179755, + .xtal_hz = 12000000, }; static struct dib8000_config dib807x_dib8000_config[2] = { @@ -1921,13 +1934,22 @@ static struct dibx000_agc_config dib8096p_agc_config[2] = { }; static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = { - 108000, 13500, - 1, 9, 1, 0, 0, - 0, 0, 0, 0, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20199729, - 12000000, + .internal = 108000, + .sampling = 13500, + .pll_prediv = 1, + .pll_ratio = 9, + .pll_range = 1, + .pll_reset = 0, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 0, + .ADClkSrc = 0, + .modulo = 2, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20199729, + .xtal_hz = 12000000, }; static struct dib8000_config tfe8096p_dib8000_config = { @@ -2724,13 +2746,22 @@ static struct dibx000_agc_config dib7090_agc_config[2] = { }; static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { - 60000, 15000, - 1, 5, 0, 0, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (524 << 0), - (0 << 25) | 0, - 20452225, - 15000000, + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 5, + .pll_range = 0, + .pll_reset = 0, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 15000000, }; static struct dib7000p_config nim7090_dib7000p_config = { @@ -3498,14 +3529,22 @@ static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = { }; static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = { - 60000, 30000, /* internal, sampling */ - 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */ - 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, */ - /* ADClkSrc, modulo */ - (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ - 39370534, /* ifreq */ - 20452225, /* timf */ - 30000000 /* xtal */ + .internal = 60000, + .sampling = 30000, + .pll_prediv = 1, + .pll_ratio = 8, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 0, + .sad_cfg = (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */ + .ifreq = 39370534, + .timf = 20452225, + .xtal_hz = 30000000 }; /* FIXME: none of these inputs are validated yet */ -- cgit v1.2.3 From 990a6a997774fae9667f08805ea6c7fe25381b84 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Fri, 22 Aug 2014 13:50:42 -0300 Subject: [media] MAINTAINERS: add sp2 entry Add a maintainer for the new CIMaX SP2 driver. Signed-off-by: Olli Salonen Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5958dd2bb7cc..e80a2755b3e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8594,6 +8594,14 @@ F: include/sound/dmaengine_pcm.h F: sound/core/pcm_dmaengine.c F: sound/soc/soc-generic-dmaengine-pcm.c +SP2 MEDIA DRIVER +M: Olli Salonen +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/dvb-frontends/sp2* + SPARC + UltraSPARC (sparc/sparc64) M: "David S. Miller" L: sparclinux@vger.kernel.org -- cgit v1.2.3 From 47c0b565ecd827984f43e52a4ec9b9a191feb80c Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 27 Aug 2014 22:12:43 -0300 Subject: [media] vpfe_standards[] can be static make vpfe_standards[] static. Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index c557eb5ebf6b..3ff817b80f22 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -125,7 +125,7 @@ static DEFINE_MUTEX(ccdc_lock); /* ccdc configuration */ static struct ccdc_config *ccdc_cfg; -const struct vpfe_standard vpfe_standards[] = { +static const struct vpfe_standard vpfe_standards[] = { {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, }; -- cgit v1.2.3 From 1eb96047052fe13557d6f278c835ef8b88ac3b4c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 29 Aug 2014 00:49:43 -0300 Subject: [media] v4l: ti-vpe: Remove casting the return value which is a void pointer Casting the return value which is a void pointer is redundant. The conversion from void pointer to any other pointer type is guaranteed by the C programming language. Signed-off-by: Jingoo Han Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 7c3c7469da1d..9a081c291159 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2344,8 +2344,7 @@ v4l2_dev_unreg: static int vpe_remove(struct platform_device *pdev) { - struct vpe_dev *dev = - (struct vpe_dev *) platform_get_drvdata(pdev); + struct vpe_dev *dev = platform_get_drvdata(pdev); v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME); -- cgit v1.2.3 From 55bea40070f33a6b52c605a74b4920bad645d0ea Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Sun, 31 Aug 2014 08:35:06 -0300 Subject: [media] si2165: Load driver for all hardware revisions Current firmware is only for revision D. Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2165.c | 26 +++++++++++++++++--------- drivers/media/dvb-frontends/si2165_priv.h | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 4386092975d0..7de0612be9fa 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -44,9 +44,7 @@ struct si2165_state { struct si2165_config config; - /* chip revision */ - u8 revcode; - /* chip type */ + u8 chip_revcode; u8 chip_type; /* calculated by xtal and div settings */ @@ -407,7 +405,7 @@ static int si2165_upload_firmware(struct si2165_state *state) int ret; const struct firmware *fw = NULL; - u8 *fw_file = SI2165_FIRMWARE; + u8 *fw_file; const u8 *data; u32 len; u32 offset; @@ -415,10 +413,20 @@ static int si2165_upload_firmware(struct si2165_state *state) u8 block_count; u16 crc_expected; + switch (state->chip_revcode) { + case 0x03: /* revision D */ + fw_file = SI2165_FIRMWARE_REV_D; + break; + default: + dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n", + KBUILD_MODNAME, state->chip_revcode); + return 0; + } + /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); if (ret) { - dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n", + dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n", KBUILD_MODNAME, fw_file); goto error; } @@ -984,7 +992,7 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, if (val != state->config.chip_mode) goto error; - io_ret = si2165_readreg8(state, 0x0023 , &state->revcode); + io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode); if (io_ret < 0) goto error; @@ -998,13 +1006,13 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, goto error; dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n", - KBUILD_MODNAME, state->revcode, state->chip_type); + KBUILD_MODNAME, state->chip_revcode, state->chip_type); /* It is a guess that register 0x0118 (chip type?) can be used to * differ between si2161, si2163 and si2165 * Only si2165 has been tested. */ - if (state->revcode == 0x03 && state->chip_type == 0x07) { + if (state->chip_type == 0x07) { state->has_dvbt = true; state->has_dvbc = true; } else { @@ -1037,4 +1045,4 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver"); MODULE_AUTHOR("Matthias Schwarzott "); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(SI2165_FIRMWARE); +MODULE_FIRMWARE(SI2165_FIRMWARE_REV_D); diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h index d4cc93fe1096..2b70cf12cd79 100644 --- a/drivers/media/dvb-frontends/si2165_priv.h +++ b/drivers/media/dvb-frontends/si2165_priv.h @@ -18,6 +18,6 @@ #ifndef _DVB_SI2165_PRIV #define _DVB_SI2165_PRIV -#define SI2165_FIRMWARE "dvb-demod-si2165.fw" +#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw" #endif /* _DVB_SI2165_PRIV */ -- cgit v1.2.3 From 119bd82e0e87903ef45fffe9c17b1fb6a99cc628 Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Sun, 31 Aug 2014 08:35:07 -0300 Subject: [media] si2165: enable Si2161 support Additionally print chip name with revision symbolically. This is a preparation for supporting new Hauppauge WinTV-HVR-900-H based on cx231xx. Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2165.c | 39 +++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 7de0612be9fa..98ddb49ad52b 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -1,5 +1,5 @@ /* - Driver for Silicon Labs SI2165 DVB-C/-T Demodulator + Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator Copyright (C) 2013-2014 Matthias Schwarzott @@ -916,7 +916,7 @@ static void si2165_release(struct dvb_frontend *fe) static struct dvb_frontend_ops si2165_ops = { .info = { - .name = "Silicon Labs Si2165", + .name = "Silicon Labs ", .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | @@ -956,6 +956,8 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, int n; int io_ret; u8 val; + char rev_char; + const char *chip_name; if (config == NULL || i2c == NULL) goto error; @@ -1005,22 +1007,35 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, if (io_ret < 0) goto error; - dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n", - KBUILD_MODNAME, state->chip_revcode, state->chip_type); + if (state->chip_revcode < 26) + rev_char = 'A' + state->chip_revcode; + else + rev_char = '?'; - /* It is a guess that register 0x0118 (chip type?) can be used to - * differ between si2161, si2163 and si2165 - * Only si2165 has been tested. - */ - if (state->chip_type == 0x07) { + switch (state->chip_type) { + case 0x06: + chip_name = "Si2161"; + state->has_dvbt = true; + break; + case 0x07: + chip_name = "Si2165"; state->has_dvbt = true; state->has_dvbc = true; - } else { - dev_err(&state->i2c->dev, "%s: Unsupported chip.\n", - KBUILD_MODNAME); + break; + default: + dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n", + KBUILD_MODNAME, state->chip_type, state->chip_revcode); goto error; } + dev_info(&state->i2c->dev, + "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n", + KBUILD_MODNAME, chip_name, rev_char, state->chip_type, + state->chip_revcode); + + strlcat(state->frontend.ops.info.name, chip_name, + sizeof(state->frontend.ops.info.name)); + n = 0; if (state->has_dvbt) { state->frontend.ops.delsys[n++] = SYS_DVBT; -- cgit v1.2.3 From 57cbf3efc8b610b605cbbef6cba8c1759ca9aa87 Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Sun, 31 Aug 2014 08:35:08 -0300 Subject: [media] cx231xx: Add support for Hauppauge WinTV-HVR-900H (111xxx) Add support for: [2040:b138] Hauppauge WinTV HVR-900H (111xxx) The hardware is similar to [2040:b130] Hauppauge WinTV 930C-HD (model 1113xx) The only difference is the demod Si2161 instead of Si2165 (but both are supported by the si2165 driver). Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 8039b769f258..a03a31a4b911 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -705,7 +705,7 @@ struct cx231xx_board cx231xx_boards[] = { }, }, [CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = { - .name = "Hauppauge WinTV 930C-HD (1113xx) / PCTV QuatroStick 521e", + .name = "Hauppauge WinTV 930C-HD (1113xx) / HVR-900H (111xxx) / PCTV QuatroStick 521e", .tuner_type = TUNER_NXP_TDA18271, .tuner_addr = 0x60, .tuner_gpio = RDE250_XCV_TUNER, @@ -815,6 +815,9 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb131), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx}, + /* Hauppauge WinTV-HVR-900-H */ + {USB_DEVICE(0x2040, 0xb138), + .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb140), .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xc200), -- cgit v1.2.3 From 8618ac4d016a8a81f185111310bdd60e22843127 Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Sun, 31 Aug 2014 08:35:09 -0300 Subject: [media] cx231xx: Add support for Hauppauge WinTV-HVR-901H (1114xx) Add support for: [2040:b139] Hauppauge WinTV HVR-901H (1114xx) According to the inf file, the hardware is similar to [2040:b131] Hauppauge WinTV 930C-HD (model 1114xx) The only difference is the demod Si2161 instead of Si2165 (but both are supported by the si2165 driver). Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index a03a31a4b911..791f00c6276b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -744,7 +744,7 @@ struct cx231xx_board cx231xx_boards[] = { } }, }, [CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx] = { - .name = "Hauppauge WinTV 930C-HD (1114xx) / PCTV QuatroStick 522e", + .name = "Hauppauge WinTV 930C-HD (1114xx) / HVR-901H (1114xx) / PCTV QuatroStick 522e", .tuner_type = TUNER_ABSENT, .tuner_addr = 0x60, .tuner_gpio = RDE250_XCV_TUNER, @@ -818,6 +818,9 @@ struct usb_device_id cx231xx_id_table[] = { /* Hauppauge WinTV-HVR-900-H */ {USB_DEVICE(0x2040, 0xb138), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, + /* Hauppauge WinTV-HVR-901-H */ + {USB_DEVICE(0x2040, 0xb139), + .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx}, {USB_DEVICE(0x2040, 0xb140), .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xc200), -- cgit v1.2.3 From 66756611c12cfff7260a3c388900dae480a1179d Mon Sep 17 00:00:00 2001 From: Matthias Schwarzott Date: Sun, 31 Aug 2014 08:35:10 -0300 Subject: [media] mceusb: add support for more cx231xx devices Add support for the si2161-based cx231xx devices: [2040:b138] Hauppauge WinTV HVR-900-H (model 111xxx) [2040:b139] Hauppauge WinTV HVR-901-H (model 1114xx) They're similar to the already supported: [2040:b130] Hauppauge WinTV 930C-HD (model 1113xx) Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 45b0894288e5..383e24af91ec 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -397,6 +397,10 @@ static struct usb_device_id mceusb_dev_table[] = { .driver_info = HAUPPAUGE_CX_HYBRID_TV }, { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131), .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb138), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb139), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, { USB_DEVICE(VENDOR_PCTV, 0x0259), .driver_info = HAUPPAUGE_CX_HYBRID_TV }, { USB_DEVICE(VENDOR_PCTV, 0x025e), -- cgit v1.2.3 From fb91bde9d3664dd879655f3a1013c0b5728e7a09 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 27 Dec 2013 00:16:13 -0300 Subject: [media] em28xx: check if a device has audio earlier" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GIT_AUTHOR_DATE=1409603039 This reverts commit b99f0aadd33fad269c8e62b5bec8b5c012a44a56 Author: Mauro Carvalho Chehab [media] em28xx: check if a device has audio earlier Better to split chipset detection from the audio setup. So, move the detection code to em28xx_init_dev(). It broke analog audio of the Hauppauge winTV HVR 900 and very likely many other em28xx devices. Background: The local variable has_audio in em28xx_usb_probe() describes if the currently probed _usb_interface_ has an audio endpoint, while dev->audio_mode.has_audio means that the _device_ as a whole provides analog audio. Hence it is wrong to set dev->audio_mode.has_audio = has_audio in em28xx_usb_probe(). As result, audio support is no longer detected and configured on devices which have the audio endpoint on a separate interface, because em28xx_audio_setup() bails out immediately at the beginning. Revert the faulty commit to restore the old audio detection procedure, which checks the chip configuration register to determine if the device has analog audio. Cc: # 3.14 to 3.16 Reported-by: Oravecz Csaba Tested-by: Oravecz Csaba Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 11 ----------- drivers/media/usb/em28xx/em28xx-core.c | 12 +++++++++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 230d6a21b6d3..582c1e192472 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3098,16 +3098,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, } } - if (dev->chip_id == CHIP_ID_EM2870 || - dev->chip_id == CHIP_ID_EM2874 || - dev->chip_id == CHIP_ID_EM28174 || - dev->chip_id == CHIP_ID_EM28178) { - /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = false; - dev->has_audio_class = false; - dev->has_alsa_audio = false; - } - if (chip_name != default_chip_name) printk(KERN_INFO DRIVER_NAME ": chip ID is %s\n", chip_name); @@ -3377,7 +3367,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->alt = -1; dev->is_audio_only = has_audio && !(has_video || has_dvb); dev->has_alsa_audio = has_audio; - dev->audio_mode.has_audio = has_audio; dev->has_video = has_video; dev->ifnum = ifnum; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 225a73518cf2..2f82e929a574 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -506,8 +506,18 @@ int em28xx_audio_setup(struct em28xx *dev) int vid1, vid2, feat, cfg; u32 vid; - if (!dev->audio_mode.has_audio) + if (dev->chip_id == CHIP_ID_EM2870 || + dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM28178) { + /* Digital only device - don't load any alsa module */ + dev->audio_mode.has_audio = false; + dev->has_audio_class = false; + dev->has_alsa_audio = false; return 0; + } + + dev->audio_mode.has_audio = true; /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); -- cgit v1.2.3 From 3232e04df7224f31a31cfe927096f3d03ba743ab Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Sep 2014 08:10:05 -0300 Subject: [media] staging: lirc: freeing ERR_PTRs We call kfree(data_buf) in the error handling and that will oops if this is an error pointer. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_imon.c | 1 + drivers/staging/media/lirc/lirc_sasem.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index 96c76b33770b..5441f40cf5a1 100644 --- a/drivers/staging/media/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c @@ -414,6 +414,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, data_buf = memdup_user(buf, n_bytes); if (IS_ERR(data_buf)) { retval = PTR_ERR(data_buf); + data_buf = NULL; goto exit; } diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c index 81f90e17e1e6..c32e2965da87 100644 --- a/drivers/staging/media/lirc/lirc_sasem.c +++ b/drivers/staging/media/lirc/lirc_sasem.c @@ -392,6 +392,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, data_buf = memdup_user((void const __user *)buf, n_bytes); if (IS_ERR(data_buf)) { retval = PTR_ERR(data_buf); + data_buf = NULL; goto exit; } -- cgit v1.2.3 From 9380e112f7b9ab83b57062f2164476e76c5533c7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 4 Sep 2014 10:04:38 -0300 Subject: [media] hdpvr: reduce memory footprint when debugging There is no need to use hex_dump_to_buffer() since we have a kernel helper to dump up to 64 bytes just via printk(). Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-control.c | 21 ++++++--------------- drivers/media/usb/hdpvr/hdpvr-core.c | 27 ++++++--------------------- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/drivers/media/usb/hdpvr/hdpvr-control.c b/drivers/media/usb/hdpvr/hdpvr-control.c index 6053661dc04b..6e86032ea5db 100644 --- a/drivers/media/usb/hdpvr/hdpvr-control.c +++ b/drivers/media/usb/hdpvr/hdpvr-control.c @@ -59,13 +59,10 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf) 1000); #ifdef HDPVR_DEBUG - if (hdpvr_debug & MSG_INFO) { - char print_buf[15]; - hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf, - sizeof(print_buf), 0); + if (hdpvr_debug & MSG_INFO) v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "get video info returned: %d, %s\n", ret, print_buf); - } + "get video info returned: %d, %5ph\n", ret, + dev->usbc_buf); #endif mutex_unlock(&dev->usbc_mutex); @@ -82,9 +79,6 @@ int get_video_info(struct hdpvr_device *dev, struct hdpvr_video_info *vidinf) int get_input_lines_info(struct hdpvr_device *dev) { -#ifdef HDPVR_DEBUG - char print_buf[9]; -#endif int ret, lines; mutex_lock(&dev->usbc_mutex); @@ -96,13 +90,10 @@ int get_input_lines_info(struct hdpvr_device *dev) 1000); #ifdef HDPVR_DEBUG - if (hdpvr_debug & MSG_INFO) { - hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf, - sizeof(print_buf), 0); + if (hdpvr_debug & MSG_INFO) v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "get input lines info returned: %d, %s\n", ret, - print_buf); - } + "get input lines info returned: %d, %3ph\n", ret, + dev->usbc_buf); #else (void)ret; /* suppress compiler warning */ #endif diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index c5638964c3f2..42b4cdf28cfd 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -124,14 +124,6 @@ static int device_authorization(struct hdpvr_device *dev) int ret, retval = -ENOMEM; char request_type = 0x38, rcv_request = 0x81; char *response; -#ifdef HDPVR_DEBUG - size_t buf_size = 46; - char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL); - if (!print_buf) { - v4l2_err(&dev->v4l2_dev, "Out of memory\n"); - return retval; - } -#endif mutex_lock(&dev->usbc_mutex); ret = usb_control_msg(dev->udev, @@ -147,11 +139,9 @@ static int device_authorization(struct hdpvr_device *dev) } #ifdef HDPVR_DEBUG else { - hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, - 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "Status request returned, len %d: %s\n", - ret, print_buf); + "Status request returned, len %d: %46ph\n", + ret, dev->usbc_buf); } #endif @@ -189,15 +179,13 @@ static int device_authorization(struct hdpvr_device *dev) response = dev->usbc_buf+38; #ifdef HDPVR_DEBUG - hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", - print_buf); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %8ph\n", + response); #endif challenge(response); #ifdef HDPVR_DEBUG - 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); + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %8ph\n", + response); #endif msleep(100); @@ -213,9 +201,6 @@ static int device_authorization(struct hdpvr_device *dev) retval = ret != 8; unlock: mutex_unlock(&dev->usbc_mutex); -#ifdef HDPVR_DEBUG - kfree(print_buf); -#endif return retval; } -- cgit v1.2.3 From f2e323ec96077642d397bb1c355def536d489d16 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 Sep 2014 09:09:28 -0300 Subject: [media] ttusb-dec: buffer overflow in ioctl We need to add a limit check here so we don't overflow the buffer. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusbdecfe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index 5c45c9d0712d..9c29552aedec 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -156,6 +156,9 @@ static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struc 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if (cmd->msg_len > sizeof(b) - 4) + return -EINVAL; + memcpy(&b[4], cmd->msg, cmd->msg_len); state->config->send_command(fe, 0x72, -- cgit v1.2.3 From 3011e5e592a2d31556cc3eff335a1ecccd473fa0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 8 Sep 2014 08:18:43 -0300 Subject: [media] firewire: firedtv-avc: potential buffer overflow "program_info_length" is user controlled and can go up to 4095. The operand[] array has 509 bytes so we need to add a limit here to prevent buffer overflows. Signed-off-by: Dan Carpenter Reviewed-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/firewire/firedtv-avc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c index d1a1a1324ef8..ac17567f0822 100644 --- a/drivers/media/firewire/firedtv-avc.c +++ b/drivers/media/firewire/firedtv-avc.c @@ -1157,6 +1157,10 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) if (pmt_cmd_id != 1 && pmt_cmd_id != 4) dev_err(fdtv->device, "invalid pmt_cmd_id %d\n", pmt_cmd_id); + if (program_info_length > sizeof(c->operand) - write_pos) { + ret = -EINVAL; + goto out; + } memcpy(&c->operand[write_pos], &msg[read_pos], program_info_length); @@ -1180,6 +1184,11 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) dev_err(fdtv->device, "invalid pmt_cmd_id %d " "at stream level\n", pmt_cmd_id); + if (es_info_length > sizeof(c->operand) - write_pos) { + ret = -EINVAL; + goto out; + } + memcpy(&c->operand[write_pos], &msg[read_pos], es_info_length); read_pos += es_info_length; -- cgit v1.2.3 From e947d9ad8ab118d51ff07b7d93c3c1a3e9f7c42f Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 8 Sep 2014 19:10:43 -0300 Subject: [media] mceusb: fix usbdev leak mceusb_init_rc_dev() does usb_get_dev(), but there is no any usb_put_dev() in the driver. The patch tries to straighten logic. It moves usb_get_dev() directly to mceusb_dev_probe() and adds usb_put_dev() to an error path and to mceusb_dev_disconnect(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 383e24af91ec..2cdb740cde48 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1202,10 +1202,9 @@ static void mceusb_flash_led(struct mceusb_dev *ir) mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED)); } -static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir, - struct usb_interface *intf) +static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) { - struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); + struct usb_device *udev = ir->usbdev; struct device *dev = ir->dev; struct rc_dev *rc; int ret; @@ -1345,7 +1344,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, if (!ir->urb_in) goto urb_in_alloc_fail; - ir->usbdev = dev; + ir->usbdev = usb_get_dev(dev); ir->dev = &intf->dev; ir->len_in = maxp; ir->flags.microsoft_gen1 = is_microsoft_gen1; @@ -1366,7 +1365,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, snprintf(name + strlen(name), sizeof(name) - strlen(name), " %s", buf); - ir->rc = mceusb_init_rc_dev(ir, intf); + ir->rc = mceusb_init_rc_dev(ir); if (!ir->rc) goto rc_dev_fail; @@ -1412,6 +1411,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, /* Error-handling path */ rc_dev_fail: + usb_put_dev(ir->usbdev); usb_free_urb(ir->urb_in); urb_in_alloc_fail: usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); @@ -1439,6 +1439,7 @@ static void mceusb_dev_disconnect(struct usb_interface *intf) usb_kill_urb(ir->urb_in); usb_free_urb(ir->urb_in); usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + usb_put_dev(dev); kfree(ir); } -- cgit v1.2.3 From cf3b576d52c1f0a204f0c8bdecc22a338f7ca5a4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Sep 2014 09:05:28 -0300 Subject: [media] dvb: si21xx: buffer overflow in si21_writeregs() "len" is user controlled and can be up to 255. Anything more than 59 will cause a buffer overflow so we need to add a test for that. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si21xx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index 73b47cc6a13b..16850e2bf02f 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -236,6 +236,9 @@ static int si21_writeregs(struct si21xx_state *state, u8 reg1, .len = len + 1 }; + if (len > sizeof(buf) - 1) + return -EINVAL; + msg.buf[0] = reg1; memcpy(msg.buf + 1, data, len); -- cgit v1.2.3 From 7ac95cf59d59473e680937319594ce0719497e98 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Sep 2014 09:11:23 -0300 Subject: [media] firewire: firedtv-avc: fix more potential buffer overflow "program_info_length" is user controlled and can go up to 4095. The operand[] array has 509 bytes so we need to add a limit here to prevent buffer overflows. The " - 4" in the limit check is because we have 4 bytes more data to add after the memcpy(). [mchehab@osg.samsung.com: as I merged the version 1 of the patch, I needed to rebase to apply just the differences between v1 and v2] Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/firewire/firedtv-avc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c index ac17567f0822..251a556112a9 100644 --- a/drivers/media/firewire/firedtv-avc.c +++ b/drivers/media/firewire/firedtv-avc.c @@ -1157,7 +1157,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) if (pmt_cmd_id != 1 && pmt_cmd_id != 4) dev_err(fdtv->device, "invalid pmt_cmd_id %d\n", pmt_cmd_id); - if (program_info_length > sizeof(c->operand) - write_pos) { + if (program_info_length > sizeof(c->operand) - 4 - write_pos) { ret = -EINVAL; goto out; } @@ -1184,7 +1184,8 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) dev_err(fdtv->device, "invalid pmt_cmd_id %d " "at stream level\n", pmt_cmd_id); - if (es_info_length > sizeof(c->operand) - write_pos) { + if (es_info_length > sizeof(c->operand) - 4 - + write_pos) { ret = -EINVAL; goto out; } -- cgit v1.2.3 From d87a50586dbeb2b6019b9e695799838401f21db6 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Thu, 11 Sep 2014 17:01:38 -0300 Subject: [media] si2157: Add support for Si2147-A30 tuner This patch adds support for Si2147-A30 tuner. Fairly trivial, no firmware needed for this tuner. However, command 14 00 02 07 01 00 seems to be mandatory. On Si2157 and Si2158 the value 0x0100 is the default value, so this patch does not impact the existing tuners/devices. On Si2147 the default is 0x0000 and I can't get a lock with that value. While here, fix the return length of the previous set command to 4 bytes. Signed-off-by: Olli Salonen Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 13 +++++++++++-- drivers/media/tuners/si2157.h | 2 +- drivers/media/tuners/si2157_priv.h | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 5901484011b9..cf97142e01e6 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari * @@ -113,12 +113,14 @@ static int si2157_init(struct dvb_frontend *fe) #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) + #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) switch (chip_id) { case SI2158_A20: fw_file = SI2158_A20_FIRMWARE; break; case SI2157_A30: + case SI2147_A30: goto skip_fw_download; break; default: @@ -265,7 +267,14 @@ static int si2157_set_params(struct dvb_frontend *fe) if (s->inversion) cmd.args[5] = 0x01; cmd.wlen = 6; - cmd.rlen = 1; + cmd.rlen = 4; + ret = si2157_cmd_execute(s, &cmd); + if (ret) + goto err; + + memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); + cmd.wlen = 6; + cmd.rlen = 4; ret = si2157_cmd_execute(s, &cmd); if (ret) goto err; diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index 6da4d5d1c817..d3b19cadb4a1 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari * diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 4080a57962f0..e71ffafed951 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2157/2158 silicon tuner driver + * Silicon Labs Si2147/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari * -- cgit v1.2.3 From 072f1a489efa348223db07730c4b946a4b1ca0cc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 11 Sep 2014 19:43:46 -0300 Subject: [media] v4l: videobuf2: Fix typos in comments The buffer flags are incorrectly referred to as V4L2_BUF_FLAGS_* instead of V4L2_BUF_FLAG_* in comments. Fix it. Signed-off-by: Laurent Pinchart Acked-by: Marek Szyprowski Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index b3c9973463ed..a8608ce37a75 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -356,8 +356,8 @@ 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 - * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAGS_TIMESTAMP_* and - * V4L2_BUF_FLAGS_TSTAMP_SRC_* + * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAG_TIMESTAMP_* and + * V4L2_BUF_FLAG_TSTAMP_SRC_* * @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. -- cgit v1.2.3 From 60a24ba03c5dcd51a754cb45e7d65753126f58ce Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 13 Sep 2014 05:52:19 -0300 Subject: [media] em28xx: remove some unnecessary fields from struct em28xx_audio_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fields "ac97_feat", "ac97_vendor_id" and "i2s_samplerates" of struct em28xx_audio_mode are used nowhere, except in function em28xx_audio_setup(). So get rid of them and use local variables instead. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 16 +++++++--------- drivers/media/usb/em28xx/em28xx.h | 6 ------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 2f82e929a574..3bbab0e468de 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -505,6 +505,7 @@ int em28xx_audio_setup(struct em28xx *dev) { int vid1, vid2, feat, cfg; u32 vid; + u8 i2s_samplerates; if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 || @@ -534,15 +535,15 @@ int em28xx_audio_setup(struct em28xx *dev) if (dev->chip_id < CHIP_ID_EM2860 && (cfg & EM28XX_CHIPCFG_AUDIOMASK) == EM2820_CHIPCFG_I2S_1_SAMPRATE) - dev->audio_mode.i2s_samplerates = 1; + i2s_samplerates = 1; else if (dev->chip_id >= CHIP_ID_EM2860 && (cfg & EM28XX_CHIPCFG_AUDIOMASK) == EM2860_CHIPCFG_I2S_5_SAMPRATES) - dev->audio_mode.i2s_samplerates = 5; + i2s_samplerates = 5; else - dev->audio_mode.i2s_samplerates = 3; + i2s_samplerates = 3; em28xx_info("I2S Audio (%d sample rate(s))\n", - dev->audio_mode.i2s_samplerates); + i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; @@ -569,15 +570,12 @@ int em28xx_audio_setup(struct em28xx *dev) goto init_audio; vid = vid1 << 16 | vid2; - - dev->audio_mode.ac97_vendor_id = vid; em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); feat = em28xx_read_ac97(dev, AC97_RESET); if (feat < 0) goto init_audio; - dev->audio_mode.ac97_feat = feat; em28xx_warn("AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ @@ -596,8 +594,8 @@ init_audio: em28xx_info("Empia 202 AC97 audio processor detected\n"); break; case EM28XX_AC97_SIGMATEL: - em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n", - dev->audio_mode.ac97_vendor_id & 0xff); + em28xx_info("Sigmatel audio processor detected (stac 97%02x)\n", + vid & 0xff); break; case EM28XX_AC97_OTHER: em28xx_warn("Unknown AC97 audio processor detected!\n"); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 84ef8efdb148..1f38163352b6 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -309,13 +309,7 @@ enum em28xx_ac97_mode { struct em28xx_audio_mode { enum em28xx_ac97_mode ac97; - - u16 ac97_feat; - u32 ac97_vendor_id; - unsigned int has_audio:1; - - u8 i2s_samplerates; }; /* em28xx has two audio inputs: tuner and line in. -- cgit v1.2.3 From c5874208ff78a5180ef0456caa117704983f3a45 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 13 Sep 2014 05:52:20 -0300 Subject: [media] em28xx: simplify usb audio class handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As far as we know devices can either have audio class or vendor class usb interfaces but not both at the same time. Even if both interface types could be provided by devices at the same time, the current code is totally broken for that case. So clean up and simplify the usb audio class handling by replacing fields "has_audio_class" (device has usb audio class compliant interface) and "has_alsa_audio" (device has vendor audio interface) in struct em28xx with a single enum em28xx_usb_audio_type. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 8 ++++---- drivers/media/usb/em28xx/em28xx-cards.c | 30 ++++++++++++++++-------------- drivers/media/usb/em28xx/em28xx-core.c | 8 ++++---- drivers/media/usb/em28xx/em28xx.h | 9 +++++++-- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index e881ef7b6445..90c7a83989d1 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -893,7 +893,7 @@ static int em28xx_audio_init(struct em28xx *dev) static int devnr; int err; - if (!dev->has_alsa_audio) { + if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ @@ -975,7 +975,7 @@ static int em28xx_audio_fini(struct em28xx *dev) if (dev == NULL) return 0; - if (!dev->has_alsa_audio) { + if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ @@ -1003,7 +1003,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev == NULL) return 0; - if (!dev->has_alsa_audio) + if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; em28xx_info("Suspending audio extension"); @@ -1017,7 +1017,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev == NULL) return 0; - if (!dev->has_alsa_audio) + if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; em28xx_info("Resuming audio extension"); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 582c1e192472..f1425882a843 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2931,9 +2931,9 @@ static void request_module_async(struct work_struct *work) #if defined(CONFIG_MODULES) && defined(MODULE) if (dev->has_video) request_module("em28xx-v4l"); - if (dev->has_audio_class) + if (dev->usb_audio_type == EM28XX_USB_AUDIO_CLASS) request_module("snd-usb-audio"); - else if (dev->has_alsa_audio) + else if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) request_module("em28xx-alsa"); if (dev->board.has_dvb) request_module("em28xx-dvb"); @@ -3180,7 +3180,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_device *udev; struct em28xx *dev = NULL; int retval; - bool has_audio = false, has_video = false, has_dvb = false; + bool has_vendor_audio = false, has_video = false, has_dvb = false; int i, nr, try_bulk; const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; char *speed; @@ -3262,7 +3262,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, break; case 0x83: if (usb_endpoint_xfer_isoc(e)) { - has_audio = true; + has_vendor_audio = true; } else { printk(KERN_INFO DRIVER_NAME ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); @@ -3318,7 +3318,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } - if (!(has_audio || has_video || has_dvb)) { + if (!(has_vendor_audio || has_video || has_dvb)) { retval = -ENODEV; goto err_free; } @@ -3365,25 +3365,27 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; - dev->is_audio_only = has_audio && !(has_video || has_dvb); - dev->has_alsa_audio = has_audio; + dev->is_audio_only = has_vendor_audio && !(has_video || has_dvb); dev->has_video = has_video; dev->ifnum = ifnum; - /* Checks if audio is provided by some interface */ + if (has_vendor_audio) { + printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n", + ifnum, "(Vendor Class)"); + dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; + } + /* Checks if audio is provided by a USB Audio Class interface */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { struct usb_interface *uif = udev->config->interface[i]; if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev->has_audio_class = 1; + if (has_vendor_audio) + em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n" + "\t\tThe vendor interface will be ignored. Please contact the developers \n"); + dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; } } - if (has_audio) - printk(KERN_INFO DRIVER_NAME - ": Audio interface %i found %s\n", - ifnum, - dev->has_audio_class ? "(USB Audio Class)" : "(Vendor Class)"); if (has_video) printk(KERN_INFO DRIVER_NAME ": Video interface %i found:%s%s\n", diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 3bbab0e468de..147d73d4f03a 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -513,8 +513,7 @@ int em28xx_audio_setup(struct em28xx *dev) dev->chip_id == CHIP_ID_EM28178) { /* Digital only device - don't load any alsa module */ dev->audio_mode.has_audio = false; - dev->has_audio_class = false; - dev->has_alsa_audio = false; + dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; return 0; } @@ -528,8 +527,8 @@ int em28xx_audio_setup(struct em28xx *dev) cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { /* The device doesn't have vendor audio at all */ - dev->has_alsa_audio = false; dev->audio_mode.has_audio = false; + dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; return 0; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { if (dev->chip_id < CHIP_ID_EM2860 && @@ -560,7 +559,8 @@ int em28xx_audio_setup(struct em28xx *dev) */ em28xx_warn("AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; - dev->has_alsa_audio = false; + if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) + dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; dev->audio_mode.has_audio = false; goto init_audio; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 1f38163352b6..3fd176f99a23 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -312,6 +312,12 @@ struct em28xx_audio_mode { unsigned int has_audio:1; }; +enum em28xx_usb_audio_type { + EM28XX_USB_AUDIO_NONE = 0, + EM28XX_USB_AUDIO_CLASS, + EM28XX_USB_AUDIO_VENDOR, +}; + /* em28xx has two audio inputs: tuner and line in. However, on most devices, an auxiliary AC97 codec device is used. The AC97 device may have several different inputs and outputs, @@ -601,9 +607,8 @@ struct em28xx { unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ unsigned char disconnected:1; /* device has been diconnected */ unsigned int has_video:1; - unsigned int has_audio_class:1; - unsigned int has_alsa_audio:1; unsigned int is_audio_only:1; + enum em28xx_usb_audio_type usb_audio_type; struct em28xx_board board; -- cgit v1.2.3 From 920f1e4a528a1db01d6822026f653659ecb4983d Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 13 Sep 2014 05:52:21 -0300 Subject: [media] em28xx: get rid of field has_audio in struct em28xx_audio_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Field has_audio in struct em28xx_audio_mode is used together with value EM28XX_NO_AC97 of field ac97 to determine the internal type of audio (none/i2s/ac97). This makes the code difficult to understand: !audio_mode.has_audio && audio_mode.ac97 == EM28XX_NO_AC97 => no audio !audio_mode.has_audio && audio_mode.ac97 != EM28XX_NO_AC97 => BUG audio_mode.has_audio && audio_mode.ac97 == EM28XX_NO_AC97 => AC97 audio audio_mode.has_audio && audio_mode.ac97 != EM28XX_NO_AC97 => I2S audio Simplify the whole thing by introducing an enum em28xx_int_audio_type which describes the internal audio type (none, ac97, i2s) and is hooked directly to the device struct. Then get rid of field has_audio in struct em28xx_audio_mode. A follow-up patch will then remove struct em28xx_ac97_mode and finally the whole struct em28xx_audio_mode. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 14 ++++++++------ drivers/media/usb/em28xx/em28xx-video.c | 6 +++--- drivers/media/usb/em28xx/em28xx.h | 8 +++++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 147d73d4f03a..3413763efd25 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -433,7 +433,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) int ret, i; u8 xclk; - if (!dev->audio_mode.has_audio) + if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) return 0; /* It is assumed that all devices use master volume for output. @@ -512,25 +512,25 @@ int em28xx_audio_setup(struct em28xx *dev) dev->chip_id == CHIP_ID_EM28174 || dev->chip_id == CHIP_ID_EM28178) { /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = false; + dev->int_audio_type = EM28XX_INT_AUDIO_NONE; dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; return 0; } - dev->audio_mode.has_audio = true; - /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); em28xx_info("Config register raw data: 0x%02x\n", cfg); if (cfg < 0) { /* Register read error? */ cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ + dev->int_audio_type = EM28XX_INT_AUDIO_AC97; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { /* The device doesn't have vendor audio at all */ - dev->audio_mode.has_audio = false; + dev->int_audio_type = EM28XX_INT_AUDIO_NONE; dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; return 0; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { + dev->int_audio_type = EM28XX_INT_AUDIO_I2S; if (dev->chip_id < CHIP_ID_EM2860 && (cfg & EM28XX_CHIPCFG_AUDIOMASK) == EM2820_CHIPCFG_I2S_1_SAMPRATE) @@ -546,6 +546,8 @@ int em28xx_audio_setup(struct em28xx *dev) /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; + } else { + dev->int_audio_type = EM28XX_INT_AUDIO_AC97; } dev->audio_mode.ac97 = EM28XX_AC97_OTHER; @@ -561,7 +563,7 @@ int em28xx_audio_setup(struct em28xx *dev) dev->audio_mode.ac97 = EM28XX_NO_AC97; if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; - dev->audio_mode.has_audio = false; + dev->int_audio_type = EM28XX_INT_AUDIO_NONE; goto init_audio; } diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3642438bc7d4..3284de99fc99 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1720,7 +1720,7 @@ static int vidioc_querycap(struct file *file, void *priv, else cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; - if (dev->audio_mode.has_audio) + if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE) cap->device_caps |= V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) @@ -2514,7 +2514,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY); } - if (!dev->audio_mode.has_audio) { + if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) { v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO); } @@ -2544,7 +2544,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY); } - if (!dev->audio_mode.has_audio) { + if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) { v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO); } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 3fd176f99a23..857ad0c69c84 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -309,7 +309,12 @@ enum em28xx_ac97_mode { struct em28xx_audio_mode { enum em28xx_ac97_mode ac97; - unsigned int has_audio:1; +}; + +enum em28xx_int_audio_type { + EM28XX_INT_AUDIO_NONE = 0, + EM28XX_INT_AUDIO_AC97, + EM28XX_INT_AUDIO_I2S, }; enum em28xx_usb_audio_type { @@ -608,6 +613,7 @@ struct em28xx { unsigned char disconnected:1; /* device has been diconnected */ unsigned int has_video:1; unsigned int is_audio_only:1; + enum em28xx_int_audio_type int_audio_type; enum em28xx_usb_audio_type usb_audio_type; struct em28xx_board board; -- cgit v1.2.3 From 43c3ea312c49efa01dc3b6cd5d78dd8bed27f347 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 13 Sep 2014 05:56:46 -0300 Subject: [media] em28xx: remove dead code line from em28xx_audio_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting the value of the chip config register to EM28XX_CHIPCFG_AC97 in case of a read error is a leftover from the past which is no longer needed. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 3413763efd25..b5e52fe7957a 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -520,9 +520,8 @@ int em28xx_audio_setup(struct em28xx *dev) /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); em28xx_info("Config register raw data: 0x%02x\n", cfg); - if (cfg < 0) { - /* Register read error? */ - cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ + if (cfg < 0) { /* Register read error */ + /* Be conservative */ dev->int_audio_type = EM28XX_INT_AUDIO_AC97; } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { /* The device doesn't have vendor audio at all */ -- cgit v1.2.3 From 3bacc10cd4a85bc70bc0b6c001d3bf995c7fe04c Mon Sep 17 00:00:00 2001 From: Maciej Matraszek Date: Mon, 15 Sep 2014 05:14:48 -0300 Subject: [media] v4l2-common: fix overflow in v4l_bound_align_image() Fix clamp_align() used in v4l_bound_align_image() to prevent overflow when passed large value like UINT32_MAX. In the current implementation: clamp_align(UINT32_MAX, 8, 8192, 3) returns 8, because in line: x = (x + (1 << (align - 1))) & mask; x overflows to (-1 + 4) & 0x7 = 3, while expected value is 8192. v4l_bound_align_image() is heavily used in VIDIOC_S_FMT and VIDIOC_SUBDEV_S_FMT ioctls handlers, and documentation of the latter explicitly states that: "The modified format should be as close as possible to the original request." -- http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-subdev-g-fmt.html Thus one would expect, that passing UINT32_MAX as format width and height will result in setting maximum possible resolution for the device. Particularly, when the driver doesn't support VIDIOC_ENUM_FRAMESIZES ioctl, which is common in the codebase. Fixes changeset: b0d3159be9a3 Signed-off-by: Maciej Matraszek Acked-by: Sakari Ailus Cc: Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index ccaa38f65cf1..2e9d81f4c1a5 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -435,16 +435,13 @@ static unsigned int clamp_align(unsigned int x, unsigned int min, /* Bits that must be zero to be aligned */ unsigned int mask = ~((1 << align) - 1); + /* Clamp to aligned min and max */ + x = clamp(x, (min + ~mask) & mask, max & mask); + /* Round to nearest aligned value */ if (align) x = (x + (1 << (align - 1))) & mask; - /* Clamp to aligned value of min and max */ - if (x < min) - x = (min + ~mask) & mask; - else if (x > max) - x = max & mask; - return x; } -- cgit v1.2.3 From e87cb470896e9089d2185e1dcbe8d17b0e3361d3 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 15 Sep 2014 18:36:15 -0300 Subject: [media] imon: fix usbdev leaks imon_probe() does three usb_get_dev(), but there is no any usb_put_dev() in the driver. The patch adds usb_put_dev() to error paths, to imon_disconnect() and to imon_probe() as far as usbdev is not saved anywhere. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 74daceec2f74..b8837dd39bb2 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2283,6 +2283,7 @@ idev_setup_failed: usb_kill_urb(ictx->rx_urb_intf0); urb_submit_failed: find_endpoint_failed: + usb_put_dev(ictx->usbdev_intf0); mutex_unlock(&ictx->lock); usb_free_urb(tx_urb); tx_urb_alloc_failed: @@ -2355,6 +2356,7 @@ urb_submit_failed: input_unregister_device(ictx->touch); touch_setup_failed: find_endpoint_failed: + usb_put_dev(ictx->usbdev_intf1); mutex_unlock(&ictx->lock); usb_free_urb(rx_urb); rx_urb_alloc_failed: @@ -2468,11 +2470,13 @@ static int imon_probe(struct usb_interface *interface, usbdev->bus->busnum, usbdev->devnum); mutex_unlock(&driver_lock); + usb_put_dev(usbdev); return 0; fail: mutex_unlock(&driver_lock); + usb_put_dev(usbdev); dev_err(dev, "unable to register, err %d\n", ret); return ret; @@ -2512,6 +2516,7 @@ static void imon_disconnect(struct usb_interface *interface) if (ifnum == 0) { ictx->dev_present_intf0 = false; usb_kill_urb(ictx->rx_urb_intf0); + usb_put_dev(ictx->usbdev_intf0); input_unregister_device(ictx->idev); rc_unregister_device(ictx->rdev); if (ictx->display_supported) { @@ -2523,6 +2528,7 @@ static void imon_disconnect(struct usb_interface *interface) } else { ictx->dev_present_intf1 = false; usb_kill_urb(ictx->rx_urb_intf1); + usb_put_dev(ictx->usbdev_intf1); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { input_unregister_device(ictx->touch); del_timer_sync(&ictx->ttimer); -- cgit v1.2.3 From 146af9cb809c6b6a0f4e215570fb3f397cd55a21 Mon Sep 17 00:00:00 2001 From: Amber Thrall Date: Sat, 20 Sep 2014 01:03:15 -0300 Subject: [media] Media: USB: usbtv: Fixed all coding style issues in usbtv source files Fixed various coding styles, ignoring coding style error on line 5 for all files containing a link that is longer than 80 characters long. Signed-off-by: Amber Thrall Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-audio.c | 1 + drivers/media/usb/usbtv/usbtv-core.c | 1 + drivers/media/usb/usbtv/usbtv-video.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 2d8795f683bf..78c12d22dfbb 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -311,6 +311,7 @@ static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd) static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream) { struct usbtv *chip = snd_pcm_substream_chip(substream); + return chip->snd_buffer_pos; } diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index bf25ecf143a2..29428bef272c 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -108,6 +108,7 @@ usbtv_video_fail: static void usbtv_disconnect(struct usb_interface *intf) { struct usbtv *usbtv = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); if (!usbtv) diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 3d6ed1f7509e..9d3525f659f0 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -263,6 +263,7 @@ static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd) int part_index = (line * 2 + !odd) * 3 + (part_no % 3); u32 *dst = &frame[part_index * USBTV_CHUNK/2]; + memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src)); src += USBTV_CHUNK/2; } @@ -407,6 +408,7 @@ static void usbtv_stop(struct usbtv *usbtv) /* Cancel running transfers. */ for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { struct urb *ip = usbtv->isoc_urbs[i]; + if (ip == NULL) continue; usb_kill_urb(ip); @@ -560,6 +562,7 @@ static int usbtv_g_input(struct file *file, void *priv, unsigned int *i) static int usbtv_s_input(struct file *file, void *priv, unsigned int i) { struct usbtv *usbtv = video_drvdata(file); + return usbtv_select_input(usbtv, i); } -- cgit v1.2.3 From 271430efb21223e9654fcae58955305c5f70663b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Sep 2014 04:58:53 -0300 Subject: [media] as102: remove some unneeded checks We know "ret" is zero so we don't need to test for it. It upsets the static checkers when we test stuff but we know the answer. drivers/media/usb/as102/as102_usb_drv.c:164 as102_send_ep1() warn: we tested 'ret' before and it was 'false' drivers/media/usb/as102/as102_usb_drv.c:189 as102_read_ep2() warn: we tested 'ret' before and it was 'false' Also, we don't need to initialize "ret". Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_usb_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 43133df771ff..3f669066ccf6 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -145,7 +145,7 @@ static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, int send_buf_len, int swap32) { - int ret = 0, actual_len; + int ret, actual_len; ret = usb_bulk_msg(bus_adap->usb_dev, usb_sndbulkpipe(bus_adap->usb_dev, 1), @@ -161,13 +161,13 @@ static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, actual_len, send_buf_len); return -1; } - return ret ? ret : actual_len; + return actual_len; } static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, unsigned char *recv_buf, int recv_buf_len) { - int ret = 0, actual_len; + int ret, actual_len; if (recv_buf == NULL) return -EINVAL; @@ -186,7 +186,7 @@ static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, actual_len, recv_buf_len); return -1; } - return ret ? ret : actual_len; + return actual_len; } static struct as102_priv_ops_t as102_priv_ops = { -- cgit v1.2.3 From 692f637522f0ae230fe49aab3776603d5e2c5f31 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Sep 2014 05:00:08 -0300 Subject: [media] davinci: remove an unneeded check We don't need to check "ret", we know it's zero. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 3ff817b80f22..de55f47a77db 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -442,11 +442,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, return ret; /* Update the values of sizeimage and bytesperline */ - if (!ret) { - pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); - pix->sizeimage = pix->bytesperline * pix->height; - } - return ret; + pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); + pix->sizeimage = pix->bytesperline * pix->height; + + return 0; } static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) -- cgit v1.2.3 From 017ab36a8bce08ebdca741ea636f0b2e5006a143 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 21 Sep 2014 09:09:58 -0300 Subject: [media] v4l2-ioctl.c: fix inverted condition v4l_print_ext_controls() would print the 'size' if it was 0 and 'value' if size was non-zero, but it should have been the other way around. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 46f4c0413d7d..9ccb19a435ef 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -562,7 +562,7 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) pr_cont("class=0x%x, count=%d, error_idx=%d", p->ctrl_class, p->count, p->error_idx); for (i = 0; i < p->count; i++) { - if (p->controls[i].size) + if (!p->controls[i].size) pr_cont(", id/val=0x%x/0x%x", p->controls[i].id, p->controls[i].value); else -- cgit v1.2.3 From 033d008821b9d04e823ef7adb5ef2504506f7028 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 21 Sep 2014 06:38:55 -0300 Subject: [media] saa7134: also capture the WSS signal for 50 Hz VBI capture The saa7134 driver missed capturing line 23 of the VBI area for the 50 Hz formats. Include that line in the VBI capture. Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-vbi.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index c06dbe17a87f..4f0b1012e4f3 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); /* ------------------------------------------------------------------ */ -#define VBI_LINE_COUNT 16 +#define VBI_LINE_COUNT 17 #define VBI_LINE_LENGTH 2048 #define VBI_SCALE 0x200 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 0cfa2ca6a32a..fc4a427cb51f 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -201,7 +201,7 @@ static struct saa7134_format formats[] = { .video_v_start = 24, \ .video_v_stop = 311, \ .vbi_v_start_0 = 7, \ - .vbi_v_stop_0 = 22, \ + .vbi_v_stop_0 = 23, \ .vbi_v_start_1 = 319, \ .src_timing = 4 -- cgit v1.2.3 From 452015de2e2afaf0e2f76f28477dd3025d44bc95 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 21 Sep 2014 06:52:03 -0300 Subject: [media] saa7134: add saa7134-go7007 This patch adds support to saa7134 for 'WIS Voyager or compatible' PCI boards such as the Sensoray model 614 with which this patch was tested. It is a saa7134-based PCI board with a go7007 MPEG encoder. This was a patch when the go7007 was still in staging and was not applied when go7007 was moved to drivers/media since it needed more work. That work is now done and this last piece of go7007 support can now go in. Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/Makefile | 3 +- drivers/media/pci/saa7134/saa7134-cards.c | 29 ++ drivers/media/pci/saa7134/saa7134-core.c | 10 +- drivers/media/pci/saa7134/saa7134-go7007.c | 532 +++++++++++++++++++++++++++++ drivers/media/pci/saa7134/saa7134.h | 5 + 5 files changed, 576 insertions(+), 3 deletions(-) create mode 100644 drivers/media/pci/saa7134/saa7134-go7007.c diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile index 58de9b085689..b55bd9afda11 100644 --- a/drivers/media/pci/saa7134/Makefile +++ b/drivers/media/pci/saa7134/Makefile @@ -4,7 +4,7 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o saa7134-y += saa7134-video.o saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa7134-go7007.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o @@ -14,3 +14,4 @@ ccflags-y += -I$(srctree)/drivers/media/i2c ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends +ccflags-y += -I$(srctree)/drivers/media/usb/go7007 diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 6e4bdb90aa92..3ca078057755 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -5827,6 +5827,29 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0000800, }, }, + [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, + } }, + }, }; @@ -7079,6 +7102,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */ .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + }, { + .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, diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 9ff03a69ced4..236ed725f933 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -160,6 +160,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"); @@ -563,8 +565,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-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c new file mode 100644 index 000000000000..3e9ca4821b8c --- /dev/null +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -0,0 +1,532 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "saa7134.h" +#include "saa7134-reg.h" +#include "go7007-priv.h" + +/*#define GO7007_HPI_DEBUG*/ + +enum hpi_address { + HPI_ADDR_VIDEO_BUFFER = 0xe4, + HPI_ADDR_INIT_BUFFER = 0xea, + HPI_ADDR_INTR_RET_VALUE = 0xee, + HPI_ADDR_INTR_RET_DATA = 0xec, + HPI_ADDR_INTR_STATUS = 0xf4, + HPI_ADDR_INTR_WR_PARAM = 0xf6, + HPI_ADDR_INTR_WR_INDEX = 0xf8, +}; + +enum gpio_command { + GPIO_COMMAND_RESET = 0x00, /* 000b */ + GPIO_COMMAND_REQ1 = 0x04, /* 001b */ + GPIO_COMMAND_WRITE = 0x20, /* 010b */ + GPIO_COMMAND_REQ2 = 0x24, /* 011b */ + GPIO_COMMAND_READ = 0x80, /* 100b */ + GPIO_COMMAND_VIDEO = 0x84, /* 101b */ + GPIO_COMMAND_IDLE = 0xA0, /* 110b */ + GPIO_COMMAND_ADDR = 0xA4, /* 111b */ +}; + +struct saa7134_go7007 { + struct v4l2_subdev sd; + struct saa7134_dev *dev; + u8 *top; + u8 *bottom; + dma_addr_t top_dma; + 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 | + GO7007_SENSOR_VALID_ENABLE | + GO7007_SENSOR_TV | + GO7007_SENSOR_VBI, + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | + GO7007_AUDIO_WORD_16, + .audio_rate = 48000, + .audio_bclk_div = 8, + .audio_main_div = 2, + .hpi_buffer_cap = 7, + .num_inputs = 1, + .inputs = { + { + .name = "SAA7134", + }, + }, +}; + +/********************* Driver for GPIO HPI interface *********************/ + +static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) +{ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + /* Write HPI address */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Write low byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Write high byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + return 0; +} + +static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) +{ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + /* Write HPI address */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); + + /* Read low byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + *data = saa_readb(SAA7134_GPIO_GPSTATUS0); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Read high byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + return 0; +} + +static int saa7134_go7007_interface_reset(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + u32 status; + u16 intr_val, intr_data; + int count = 20; + + saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ + saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); + msleep(1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); + msleep(10); + + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + status = saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_debug("status is %s\n", status & 0x40 ? "OK" : "not OK"); */ + + /* enter command mode...(?) */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); + + do { + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + status = saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ + } while (--count > 0); + + /* Wait for an interrupt to indicate successful hardware reset */ + if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || + (intr_val & ~0x1) != 0x55aa) { + pr_err("saa7134-go7007: unable to reset the GO7007\n"); + return -1; + } + return 0; +} + +static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + int i; + u16 status_reg; + +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); +#endif + + for (i = 0; i < 100; ++i) { + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); + if (!(status_reg & 0x0010)) + break; + msleep(10); + } + if (i == 100) { + pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n", + status_reg); + return -1; + } + gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); + gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); + + return 0; +} + +static int saa7134_go7007_read_interrupt(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + + /* XXX we need to wait if there is no interrupt available */ + go->interrupt_available = 1; + gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); + gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n", + go->interrupt_value, go->interrupt_data); +#endif + return 0; +} + +static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, + unsigned long status) +{ + struct go7007 *go = video_get_drvdata(dev->empress_dev); + struct saa7134_go7007 *saa = go->hpi_context; + + if (!vb2_is_streaming(&go->vidq)) + return; + if (0 != (status & 0x000f0000)) + pr_debug("saa7134-go7007: irq: lost %ld\n", + (status >> 16) & 0x0f); + if (status & 0x100000) { + dma_sync_single_for_cpu(&dev->pci->dev, + saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); + go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + } else { + dma_sync_single_for_cpu(&dev->pci->dev, + saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); + go7007_parse_video_stream(go, saa->top, PAGE_SIZE); + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + } +} + +static int saa7134_go7007_stream_start(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + + saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), + 0, PAGE_SIZE, DMA_FROM_DEVICE); + 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 (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; + } + + saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); + saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); + + /* Set HPI interface for video */ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); + + /* Enable TS interface */ + saa_writeb(SAA7134_TS_PARALLEL, 0xe6); + + /* Reset TS interface */ + saa_setb(SAA7134_TS_SERIAL1, 0x01); + saa_clearb(SAA7134_TS_SERIAL1, 0x01); + + /* Set up transfer block size */ + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); + saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); + saa_writeb(SAA7134_TS_DMA1, 0); + saa_writeb(SAA7134_TS_DMA2, 0); + + /* Enable video streaming mode */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); + + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_PITCH(5), 128); + saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); + + /* Enable TS FIFO */ + saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); + + /* Enable DMA IRQ */ + saa_setl(SAA7134_IRQ1, + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); + + return 0; +} + +static int saa7134_go7007_stream_stop(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev; + + if (!saa) + return -EINVAL; + dev = saa->dev; + if (!dev) + return -EINVAL; + + /* Shut down TS FIFO */ + saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); + + /* Disable DMA IRQ */ + saa_clearl(SAA7134_IRQ1, + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); + + /* Disable TS interface */ + saa_clearb(SAA7134_TS_PARALLEL, 0x80); + + dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, + DMA_FROM_DEVICE); + dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, + DMA_FROM_DEVICE); + + return 0; +} + +static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + u16 status_reg; + int i; + +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len); +#endif + + while (len > 0) { + i = len > 64 ? 64 : len; + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + while (i-- > 0) { + saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + ++data; + --len; + } + for (i = 0; i < 100; ++i) { + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); + if (!(status_reg & 0x0002)) + break; + } + if (i == 100) { + pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n", + status_reg); + return -1; + } + } + return 0; +} + +static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { + .interface_reset = saa7134_go7007_interface_reset, + .write_interrupt = saa7134_go7007_write_interrupt, + .read_interrupt = saa7134_go7007_read_interrupt, + .stream_start = saa7134_go7007_stream_start, + .stream_stop = saa7134_go7007_stream_stop, + .send_firmware = saa7134_go7007_send_firmware, +}; +MODULE_FIRMWARE("go7007/go7007tv.bin"); + +/* --------------------------------------------------------------------------*/ + +static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ +#if 0 + struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_dev *dev = saa->dev; + + return saa7134_s_std_internal(dev, NULL, norm); +#else + return 0; +#endif +} + +static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = { + .s_std = saa7134_go7007_s_std, +}; + +static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = { + .video = &saa7134_go7007_video_ops, +}; + +/* --------------------------------------------------------------------------*/ + + +/********************* Add/remove functions *********************/ + +static int saa7134_go7007_init(struct saa7134_dev *dev) +{ + struct go7007 *go; + struct saa7134_go7007 *saa; + struct v4l2_subdev *sd; + + pr_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) { + 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)); + 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; + + /* 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) + goto allocfail; + saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!saa->bottom) + goto allocfail; + + /* Boot the GO7007 */ + if (go7007_boot_encoder(go, go->board_info->flags & + GO7007_BOARD_USE_ONBOARD_I2C) < 0) + 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 allocfail; + + /* Register the subdevice interface with the go7007 device */ + if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0) + pr_info("saa7134-go7007: register subdev failed\n"); + + dev->empress_dev = &go->vdev; + + go->status = STATUS_ONLINE; + 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; +} + +static int saa7134_go7007_fini(struct saa7134_dev *dev) +{ + struct go7007 *go; + struct saa7134_go7007 *saa; + + if (NULL == dev->empress_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); + v4l2_device_unregister_subdev(&saa->sd); + kfree(saa); + video_unregister_device(&go->vdev); + + v4l2_device_put(&go->v4l2_dev); + dev->empress_dev = NULL; + + return 0; +} + +static struct saa7134_mpeg_ops saa7134_go7007_ops = { + .type = SAA7134_MPEG_GO7007, + .init = saa7134_go7007_init, + .fini = saa7134_go7007_fini, + .irq_ts_done = saa7134_go7007_irq_ts_done, +}; + +static int __init saa7134_go7007_mod_init(void) +{ + return saa7134_ts_register(&saa7134_go7007_ops); +} + +static void __exit saa7134_go7007_mod_cleanup(void) +{ + saa7134_ts_unregister(&saa7134_go7007_ops); +} + +module_init(saa7134_go7007_mod_init); +module_exit(saa7134_go7007_mod_cleanup); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index e47edd4b57ce..1a82dd07205b 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -338,6 +338,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_ASUSTeK_PS3_100 190 #define SAA7134_BOARD_HAWELL_HW_9004V1 191 #define SAA7134_BOARD_AVERMEDIA_A706 192 +#define SAA7134_BOARD_WIS_VOYAGER 193 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -368,6 +369,7 @@ enum saa7134_mpeg_type { SAA7134_MPEG_UNUSED, SAA7134_MPEG_EMPRESS, SAA7134_MPEG_DVB, + SAA7134_MPEG_GO7007, }; enum saa7134_mpeg_ts_type { @@ -407,6 +409,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]) @@ -522,6 +525,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 */ -- cgit v1.2.3 From aff440fa6197d0f78f04cfe552c97464f7048ded Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 12:52:21 -0300 Subject: [media] saa7134: Fix compilation breakage when go7007 is not selected All error/warnings: drivers/built-in.o: In function `saa7134_go7007_fini': >> saa7134-go7007.c:(.text+0x3b628b): undefined reference to `go7007_snd_remove' drivers/built-in.o: In function `saa7134_go7007_interface_reset': >> saa7134-go7007.c:(.text+0x3b659a): undefined reference to `go7007_read_interrupt' drivers/built-in.o: In function `saa7134_go7007_init': >> saa7134-go7007.c:(.text+0x3b65fa): undefined reference to `go7007_alloc' >> saa7134-go7007.c:(.text+0x3b66ed): undefined reference to `go7007_boot_encoder' >> saa7134-go7007.c:(.text+0x3b66fe): undefined reference to `go7007_register_encoder' drivers/built-in.o: In function `saa7134_go7007_irq_ts_done': >> saa7134-go7007.c:(.text+0x3b6c2a): undefined reference to `go7007_parse_video_stream' >> saa7134-go7007.c:(.text+0x3b6c86): undefined reference to `go7007_parse_video_stream' This happens when: - VIDEO_SAA7134 is either 'm' or 'y' - VIDEO_GO7007 is not selected. Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/Kconfig | 8 ++++++++ drivers/media/pci/saa7134/Makefile | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index 18ae75546302..b44e0d70907e 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -63,3 +63,11 @@ config VIDEO_SAA7134_DVB To compile this driver as a module, choose M here: the module will be called saa7134-dvb. + +config VIDEO_SAA7134_GO7007 + tristate "go7007 support for saa7134 based TV cards" + depends on VIDEO_SAA7134 + depends on VIDEO_GO7007 + ---help--- + Enables saa7134 driver support for boards with go7007 + MPEG encoder (WIS Voyager or compatible). diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile index b55bd9afda11..09c43da67588 100644 --- a/drivers/media/pci/saa7134/Makefile +++ b/drivers/media/pci/saa7134/Makefile @@ -4,7 +4,8 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o saa7134-y += saa7134-video.o saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa7134-go7007.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o +obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o -- cgit v1.2.3 From 23ea6ec0785e25600e6bc33332cc5bc255caf91c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 07:54:09 -0300 Subject: [media] saa7134: Remove some casting warnings drivers/media/pci/saa7134/saa7134-go7007.c:247:17: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:247:17: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:247:17: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:252:17: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:252:17: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:252:17: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:299:9: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:299:9: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:299:9: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:300:9: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:300:9: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:300:9: got restricted __le32 [usertype] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-go7007.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 3e9ca4821b8c..3ac987fb7606 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -244,12 +244,12 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, dma_sync_single_for_cpu(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma); } else { dma_sync_single_for_cpu(&dev->pci->dev, saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); go7007_parse_video_stream(go, saa->top, PAGE_SIZE); - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + saa_writel(SAA7134_RS_BA1(5), saa->top_dma); } } @@ -296,8 +296,8 @@ static int saa7134_go7007_stream_start(struct go7007 *go) /* Enable video streaming mode */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_BA1(5), saa->top_dma); + saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma); saa_writel(SAA7134_RS_PITCH(5), 128); saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); -- cgit v1.2.3 From 8eb988f1be98e13d33c786ad1511f9870d3038fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 07:58:00 -0300 Subject: [media] saa7134: Remove unused status var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/pci/saa7134/saa7134-go7007.c: In function ‘saa7134_go7007_interface_reset’: drivers/media/pci/saa7134/saa7134-go7007.c:147:6: warning: variable ‘status’ set but not used [-Wunused-but-set-variable] Signed-off-by: Mauro Carvalho Chehab Acked-by: Hans Verkuil --- drivers/media/pci/saa7134/saa7134-go7007.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 3ac987fb7606..54e650b4dff1 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -144,7 +144,6 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) { struct saa7134_go7007 *saa = go->hpi_context; struct saa7134_dev *dev = saa->dev; - u32 status; u16 intr_val, intr_data; int count = 20; @@ -162,8 +161,8 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - status = saa_readb(SAA7134_GPIO_GPSTATUS2); - /*pr_debug("status is %s\n", status & 0x40 ? "OK" : "not OK"); */ + saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */ /* enter command mode...(?) */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); @@ -172,7 +171,7 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) do { saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - status = saa_readb(SAA7134_GPIO_GPSTATUS2); + saa_readb(SAA7134_GPIO_GPSTATUS2); /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ } while (--count > 0); -- cgit v1.2.3 From 5264a522a597032c009f9143686ebf0fa4e244fb Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 22 Sep 2014 21:30:46 -0300 Subject: [media] media: tuner xc5000 - release firmwware from xc5000_release() xc5000 releases firmware right after loading it. Change it to save the firmware and release it from xc5000_release(). This helps avoid fecthing firmware when forced firmware load requests come in to change analog tv frequence and when firmware needs to be reloaded after suspend and resume. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 512fe508bcd2..b72ec64b758c 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -70,6 +70,8 @@ struct xc5000_priv { struct dvb_frontend *fe; struct delayed_work timer_sleep; + + const struct firmware *firmware; }; /* Misc Defines */ @@ -1136,20 +1138,23 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) if (!force && xc5000_is_firmware_loaded(fe) == 0) return 0; - ret = request_firmware(&fw, desired_fw->name, - priv->i2c_props.adap->dev.parent); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - return ret; - } - - dprintk(1, "firmware read %Zu bytes.\n", fw->size); + if (!priv->firmware) { + ret = request_firmware(&fw, desired_fw->name, + priv->i2c_props.adap->dev.parent); + if (ret) { + pr_err("xc5000: Upload failed. rc %d\n", ret); + return ret; + } + dprintk(1, "firmware read %Zu bytes.\n", fw->size); - if (fw->size != desired_fw->size) { - printk(KERN_ERR "xc5000: Firmware file with incorrect size\n"); - ret = -EINVAL; - goto err; - } + if (fw->size != desired_fw->size) { + pr_err("xc5000: Firmware file with incorrect size\n"); + release_firmware(fw); + return -EINVAL; + } + priv->firmware = fw; + } else + fw = priv->firmware; /* Try up to 5 times to load firmware */ for (i = 0; i < 5; i++) { @@ -1232,7 +1237,6 @@ err: else printk(KERN_CONT " - too many retries. Giving up\n"); - release_firmware(fw); return ret; } @@ -1316,6 +1320,8 @@ static int xc5000_release(struct dvb_frontend *fe) if (priv) { cancel_delayed_work(&priv->timer_sleep); hybrid_tuner_release_state(priv); + if (priv->firmware) + release_firmware(priv->firmware); } mutex_unlock(&xc5000_list_mutex); -- cgit v1.2.3 From 27ccd694bb3d71d1aa8342276dd0aca872f99ec9 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 13 Aug 2014 22:09:24 -0300 Subject: [media] media: tuner xc5000 - try to avoid firmware load in resume path xc5000 doesn't load firmware at attach time instead loads it when it needs to set and change configuration from its init, frequency, digital and analog mode set interffaces. As a result, when system is suspended before firmware is loaded, firmware load can be avoided during resume. Loading formware in this scenario results in slowpath warnings during resume as it won't be in the suspend firmware cache. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index b72ec64b758c..e44c8aba6074 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1293,6 +1293,20 @@ static int xc5000_suspend(struct dvb_frontend *fe) return 0; } +static int xc5000_resume(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + dprintk(1, "%s()\n", __func__); + + /* suspended before firmware is loaded. + Avoid firmware load in resume path. */ + if (!priv->firmware) + return 0; + + return xc5000_set_params(fe); +} + static int xc5000_init(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1360,7 +1374,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, .suspend = xc5000_suspend, - .resume = xc5000_set_params, + .resume = xc5000_resume, .set_config = xc5000_set_config, .set_params = xc5000_set_digital_params, -- cgit v1.2.3 From 8db3e5df4b5aa5ab8ce1edb8ee59ca9f2c2e7cd9 Mon Sep 17 00:00:00 2001 From: "nibble.max" Date: Wed, 6 Aug 2014 01:40:01 -0300 Subject: [media] rc: add dvbsky rc keymap macro This RC will be used by DVBSky driver, added on the next patch. Signed-off-by: Nibble Max Signed-off-by: Mauro Carvalho Chehab --- include/media/rc-map.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 80f951890b4c..e7a1514075ec 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -135,6 +135,7 @@ void rc_map_init(void); #define RC_MAP_DM1105_NEC "rc-dm1105-nec" #define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" +#define RC_MAP_DVBSKY "rc-dvbsky" #define RC_MAP_EMPTY "rc-empty" #define RC_MAP_EM_TERRATEC "rc-em-terratec" #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2" -- cgit v1.2.3 From af64fb3fa4ae8d4008586e81127b0a25c86f27f5 Mon Sep 17 00:00:00 2001 From: "nibble.max" Date: Mon, 11 Aug 2014 01:45:37 -0300 Subject: [media] dvbsky: new driver to support DVBSky S860/S960 devices Support for DVBSky dvb-s2 usb: add dvb-usb-v2 driver for DVBSky dvb-s2 box, no ci support yet. Signed-off-by: Nibble Max Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 7 + drivers/media/usb/dvb-usb-v2/Makefile | 3 + drivers/media/usb/dvb-usb-v2/dvbsky.c | 460 ++++++++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 drivers/media/usb/dvb-usb-v2/dvbsky.c diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 66645b02c854..5b34323ad207 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -141,3 +141,10 @@ config DVB_USB_RTL28XXU help Say Y here to support the Realtek RTL28xxU DVB USB receiver. +config DVB_USB_DVBSKY + tristate "DVBSky USB support" + depends on DVB_USB_V2 + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + help + Say Y here to support the USB receivers from DVBSky. diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index bc38f03394cd..f10d4df0eae5 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -37,6 +37,9 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o dvb-usb-rtl28xxu-objs := rtl28xxu.o obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o +dvb-usb-dvbsky-objs := dvbsky.o +obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o + ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends ccflags-y += -I$(srctree)/drivers/media/tuners diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c new file mode 100644 index 000000000000..34688c89df11 --- /dev/null +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -0,0 +1,460 @@ +/* + * Driver for DVBSky USB2.0 receiver + * + * Copyright (C) 2013 Max nibble + * + * 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 "dvb_usb.h" +#include "m88ds3103.h" +#include "m88ts2022.h" + +#define DVBSKY_MSG_DELAY 0/*2000*/ +#define DVBSKY_BUF_LEN 64 + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +struct dvbsky_state { + struct mutex stream_mutex; + u8 ibuf[DVBSKY_BUF_LEN]; + u8 obuf[DVBSKY_BUF_LEN]; + u8 last_lock; + struct i2c_client *i2c_client_tuner; + + /* fe hook functions*/ + int (*fe_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); + int (*fe_read_status)(struct dvb_frontend *fe, + fe_status_t *status); +}; + +static int dvbsky_usb_generic_rw(struct dvb_usb_device *d, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + int ret; + struct dvbsky_state *state = d_to_priv(d); + + mutex_lock(&d->usb_mutex); + if (wlen != 0) + memcpy(state->obuf, wbuf, wlen); + + ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen, + state->ibuf, rlen); + + if (!ret && (rlen != 0)) + memcpy(rbuf, state->ibuf, rlen); + + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff) +{ + struct dvbsky_state *state = d_to_priv(d); + int ret; + u8 obuf_pre[3] = { 0x37, 0, 0 }; + u8 obuf_post[3] = { 0x36, 3, 0 }; + + mutex_lock(&state->stream_mutex); + ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0); + if (!ret && onoff) { + msleep(20); + ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0); + } + mutex_unlock(&state->stream_mutex); + return ret; +} + +static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_device *d = fe_to_d(fe); + + return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1); +} + +/* GPIO */ +static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value) +{ + int ret; + u8 obuf[3], ibuf[2]; + + obuf[0] = 0x0e; + obuf[1] = gport; + obuf[2] = value; + ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1); + if (ret) + dev_err(&d->udev->dev, "%s: %s() failed=%d\n", + KBUILD_MODNAME, __func__, ret); + return ret; +} + +/* I2C */ +static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + u8 ibuf[64], obuf[64]; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) { + dev_err(&d->udev->dev, + "dvbsky_usb: too many i2c messages[%d] than 2.", num); + ret = -EOPNOTSUPP; + goto i2c_error; + } + + if (num == 1) { + if (msg[0].len > 60) { + dev_err(&d->udev->dev, + "dvbsky_usb: too many i2c bytes[%d] than 60.", + msg[0].len); + ret = -EOPNOTSUPP; + goto i2c_error; + } + if (msg[0].flags & I2C_M_RD) { + /* single read */ + obuf[0] = 0x09; + obuf[1] = 0; + obuf[2] = msg[0].len; + obuf[3] = msg[0].addr; + ret = dvbsky_usb_generic_rw(d, obuf, 4, + ibuf, msg[0].len + 1); + if (ret) + dev_err(&d->udev->dev, "%s: %s() failed=%d\n", + KBUILD_MODNAME, __func__, ret); + if (!ret) + memcpy(msg[0].buf, &ibuf[1], msg[0].len); + } else { + /* write */ + obuf[0] = 0x08; + obuf[1] = msg[0].addr; + obuf[2] = msg[0].len; + memcpy(&obuf[3], msg[0].buf, msg[0].len); + ret = dvbsky_usb_generic_rw(d, obuf, + msg[0].len + 3, ibuf, 1); + if (ret) + dev_err(&d->udev->dev, "%s: %s() failed=%d\n", + KBUILD_MODNAME, __func__, ret); + } + } else { + if ((msg[0].len > 60) || (msg[1].len > 60)) { + dev_err(&d->udev->dev, + "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.", + msg[0].len, msg[1].len); + ret = -EOPNOTSUPP; + goto i2c_error; + } + /* write then read */ + obuf[0] = 0x09; + obuf[1] = msg[0].len; + obuf[2] = msg[1].len; + obuf[3] = msg[0].addr; + memcpy(&obuf[4], msg[0].buf, msg[0].len); + ret = dvbsky_usb_generic_rw(d, obuf, + msg[0].len + 4, ibuf, msg[1].len + 1); + if (ret) + dev_err(&d->udev->dev, "%s: %s() failed=%d\n", + KBUILD_MODNAME, __func__, ret); + + if (!ret) + memcpy(msg[1].buf, &ibuf[1], msg[1].len); + } +i2c_error: + mutex_unlock(&d->i2c_mutex); + return (ret) ? ret : num; +} + +static u32 dvbsky_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dvbsky_i2c_algo = { + .master_xfer = dvbsky_i2c_xfer, + .functionality = dvbsky_i2c_func, +}; + +#if IS_ENABLED(CONFIG_RC_CORE) +static int dvbsky_rc_query(struct dvb_usb_device *d) +{ + u32 code = 0xffff, scancode; + u8 rc5_command, rc5_system; + u8 obuf[2], ibuf[2], toggle; + int ret; + + obuf[0] = 0x10; + ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2); + if (ret) + dev_err(&d->udev->dev, "%s: %s() failed=%d\n", + KBUILD_MODNAME, __func__, ret); + if (ret == 0) + code = (ibuf[0] << 8) | ibuf[1]; + if (code != 0xffff) { + dev_dbg(&d->udev->dev, "rc code: %x\n", code); + rc5_command = code & 0x3F; + rc5_system = (code & 0x7C0) >> 6; + toggle = (code & 0x800) ? 1 : 0; + scancode = rc5_system << 8 | rc5_command; + rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle); + } + return 0; +} + +static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_BIT_RC5; + rc->query = dvbsky_rc_query; + rc->interval = 300; + return 0; +} +#else + #define dvbsky_get_rc_config NULL +#endif + +static int dvbsky_usb_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct dvbsky_state *state = d_to_priv(d); + u8 value; + + if (voltage == SEC_VOLTAGE_OFF) + value = 0; + else + value = 1; + dvbsky_gpio_ctrl(d, 0x80, value); + + return state->fe_set_voltage(fe, voltage); +} + +static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) +{ + struct dvb_usb_device *d = adap_to_d(adap); + u8 obuf[] = { 0x1e, 0x00 }; + u8 ibuf[6] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = obuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 6, + } + }; + + if (i2c_transfer(&d->i2c_adap, msg, 2) == 2) + memcpy(mac, ibuf, 6); + + dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac); + + return 0; +} + +static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct dvbsky_state *state = d_to_priv(d); + int ret; + + ret = state->fe_read_status(fe, status); + + /* it need resync slave fifo when signal change from unlock to lock.*/ + if ((*status & FE_HAS_LOCK) && (!state->last_lock)) + dvbsky_stream_ctrl(d, 1); + + state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0; + return ret; +} + +static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_CI, + .ts_clk = 16000, + .ts_clk_pol = 0, + .agc = 0x99, + .lnb_hv_pol = 1, + .lnb_en_pol = 1, +}; + +static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) +{ + struct dvbsky_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret = 0; + /* demod I2C adapter */ + struct i2c_adapter *i2c_adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct m88ts2022_config m88ts2022_config = { + .clock = 27000000, + }; + memset(&info, 0, sizeof(struct i2c_board_info)); + + /* attach demod */ + adap->fe[0] = dvb_attach(m88ds3103_attach, + &dvbsky_s960_m88ds3103_config, + &d->i2c_adap, + &i2c_adapter); + if (!adap->fe[0]) { + dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n"); + ret = -ENODEV; + goto fail_attach; + } + + /* attach tuner */ + m88ts2022_config.fe = adap->fe[0]; + strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &m88ts2022_config; + request_module("m88ts2022"); + client = i2c_new_device(i2c_adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + dvb_frontend_detach(adap->fe[0]); + ret = -ENODEV; + goto fail_attach; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dvb_frontend_detach(adap->fe[0]); + ret = -ENODEV; + goto fail_attach; + } + + /* delegate signal strength measurement to tuner */ + adap->fe[0]->ops.read_signal_strength = + adap->fe[0]->ops.tuner_ops.get_rf_strength; + + /* hook fe: need to resync the slave fifo when signal locks. */ + state->fe_read_status = adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = dvbsky_usb_read_status; + + /* hook fe: LNB off/on is control by Cypress usb chip. */ + state->fe_set_voltage = adap->fe[0]->ops.set_voltage; + adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage; + + state->i2c_client_tuner = client; + +fail_attach: + return ret; +} + +static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name) +{ + dvbsky_gpio_ctrl(d, 0x04, 1); + msleep(20); + dvbsky_gpio_ctrl(d, 0x83, 0); + dvbsky_gpio_ctrl(d, 0xc0, 1); + msleep(100); + dvbsky_gpio_ctrl(d, 0x83, 1); + dvbsky_gpio_ctrl(d, 0xc0, 0); + msleep(50); + + return WARM; +} + +static int dvbsky_init(struct dvb_usb_device *d) +{ + struct dvbsky_state *state = d_to_priv(d); + + /* use default interface */ + /* + ret = usb_set_interface(d->udev, 0, 0); + if (ret) + return ret; + */ + mutex_init(&state->stream_mutex); + + state->last_lock = 0; + + return 0; +} + +static void dvbsky_exit(struct dvb_usb_device *d) +{ + struct dvbsky_state *state = d_to_priv(d); + struct i2c_client *client; + + client = state->i2c_client_tuner; + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties dvbsky_s960_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct dvbsky_state), + + .generic_bulk_ctrl_endpoint = 0x01, + .generic_bulk_ctrl_endpoint_response = 0x81, + .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY, + + .i2c_algo = &dvbsky_i2c_algo, + .frontend_attach = dvbsky_s960_attach, + .init = dvbsky_init, + .get_rc_config = dvbsky_get_rc_config, + .streaming_ctrl = dvbsky_streaming_ctrl, + .identify_state = dvbsky_identify_state, + .exit = dvbsky_exit, + .read_mac_address = dvbsky_read_mac_addr, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096), + } + } +}; + +static const struct usb_device_id dvbsky_id_table[] = { + { DVB_USB_DEVICE(0x0572, 0x6831, + &dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) }, + { } +}; +MODULE_DEVICE_TABLE(usb, dvbsky_id_table); + +static struct usb_driver dvbsky_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = dvbsky_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .reset_resume = dvb_usbv2_reset_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, +}; + +module_usb_driver(dvbsky_usb_driver); + +MODULE_AUTHOR("Max nibble "); +MODULE_DESCRIPTION("Driver for DVBSky USB"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 67cbf633c8f03c3f4915fdd771fbf01689cd824c Mon Sep 17 00:00:00 2001 From: "nibble.max" Date: Wed, 6 Aug 2014 01:38:48 -0300 Subject: [media] rc: add a map for DVBSky devices. This is a RC5 remote controller map for DVBSky S860/960 devices. Signed-off-by: Nibble Max Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-dvbsky.c | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-dvbsky.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 0b8c54919010..abf60794223d 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-dm1105-nec.o \ rc-dntv-live-dvb-t.o \ rc-dntv-live-dvbt-pro.o \ + rc-dvbsky.o \ rc-em-terratec.o \ rc-encore-enltv2.o \ rc-encore-enltv.o \ diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c new file mode 100644 index 000000000000..c5115a1165d1 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -0,0 +1,78 @@ +/* rc-dvbsky.c - Keytable for DVBSky Remote Controllers + * + * keymap imported from ir-keymaps.c + * + * + * Copyright (c) 2010-2012 by Nibble Max + * + * 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 +/* + * This table contains the complete RC5 code, instead of just the data part + */ + +static struct rc_map_table rc5_dvbsky[] = { + { 0x0000, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_MUTE }, + { 0x000d, KEY_OK }, + { 0x000b, KEY_STOP }, + { 0x000c, KEY_EXIT }, + { 0x000e, KEY_CAMERA }, /*Snap shot*/ + { 0x000f, KEY_SUBTITLE }, /*PIP*/ + { 0x0010, KEY_VOLUMEUP }, + { 0x0011, KEY_VOLUMEDOWN }, + { 0x0012, KEY_FAVORITES }, + { 0x0013, KEY_LIST }, /*Info*/ + { 0x0016, KEY_PAUSE }, + { 0x0017, KEY_PLAY }, + { 0x001f, KEY_RECORD }, + { 0x0020, KEY_CHANNELDOWN }, + { 0x0021, KEY_CHANNELUP }, + { 0x0025, KEY_POWER2 }, + { 0x0026, KEY_REWIND }, + { 0x0027, KEY_FASTFORWARD }, + { 0x0029, KEY_LAST }, + { 0x002b, KEY_MENU }, + { 0x002c, KEY_EPG }, + { 0x002d, KEY_ZOOM }, +}; + +static struct rc_map_list rc5_dvbsky_map = { + .map = { + .scan = rc5_dvbsky, + .size = ARRAY_SIZE(rc5_dvbsky), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_DVBSKY, + } +}; + +static int __init init_rc_map_rc5_dvbsky(void) +{ + return rc_map_register(&rc5_dvbsky_map); +} + +static void __exit exit_rc_map_rc5_dvbsky(void) +{ + rc_map_unregister(&rc5_dvbsky_map); +} + +module_init(init_rc_map_rc5_dvbsky) +module_exit(exit_rc_map_rc5_dvbsky) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nibble Max "); -- cgit v1.2.3 From 1a3920e86e0291c46db8b5b81ed31a98141e9670 Mon Sep 17 00:00:00 2001 From: Guoxiong Yan Date: Sat, 30 Aug 2014 23:39:09 -0300 Subject: [media] rc: Add DT bindings for hix5hd2 Signed-off-by: Guoxiong Yan Signed-off-by: Zhangfei Gao Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/hix5hd2-ir.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/hix5hd2-ir.txt diff --git a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt new file mode 100644 index 000000000000..fb5e7606643a --- /dev/null +++ b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt @@ -0,0 +1,25 @@ +Device-Tree bindings for hix5hd2 ir IP + +Required properties: + - compatible: Should contain "hisilicon,hix5hd2-ir". + - reg: Base physical address of the controller and length of memory + mapped region. + - interrupts: interrupt-specifier for the sole interrupt generated by + the device. The interrupt specifier format depends on the interrupt + controller parent. + - clocks: clock phandle and specifier pair. + - hisilicon,power-syscon: phandle of syscon used to control power. + +Optional properties: + - linux,rc-map-name : Remote control map name. + +Example node: + + ir: ir@f8001000 { + compatible = "hisilicon,hix5hd2-ir"; + reg = <0xf8001000 0x1000>; + interrupts = <0 47 4>; + clocks = <&clock HIX5HD2_FIXED_24M>; + hisilicon,power-syscon = <&sysctrl>; + linux,rc-map-name = "rc-tivo"; + }; -- cgit v1.2.3 From a84fcdaa905862b09482544d190c94a8436e4334 Mon Sep 17 00:00:00 2001 From: Guoxiong Yan Date: Sat, 30 Aug 2014 23:39:10 -0300 Subject: [media] rc: Introduce hix5hd2 IR transmitter driver IR transmitter driver for Hisilicon hix5hd2 soc By default all protocols are disabled. For example nec decoder can be enabled by either 1. ir-keytable -p nec 2. echo nec > /sys/class/rc/rc0/protocols See see Documentation/ABI/testing/sysfs-class-rc [mchehab@osg.samsung.com: Add a fixup for the driver to compile on archs that don't provide writel_relaxed() macro] Signed-off-by: Guoxiong Yan Signed-off-by: Zhangfei Gao Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 10 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/ir-hix5hd2.c | 348 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/media/rc/ir-hix5hd2.c diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 2b0cc4a98e88..8ce08107a69d 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -164,6 +164,16 @@ config IR_ENE To compile this driver as a module, choose M here: the module will be called ene_ir. +config IR_HIX5HD2 + tristate "Hisilicon hix5hd2 IR remote control" + depends on RC_CORE + help + Say Y here if you want to use hisilicon hix5hd2 remote control. + To compile this driver as a module, choose M here: the module will be + called ir-hix5hd2. + + If you're not sure, select N here + config IR_IMON tristate "SoundGraph iMON Receiver and Display" depends on USB_ARCH_HAS_HCD diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 9f9843a1af5f..0989f940e9cf 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o # stand-alone IR receivers/transmitters obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o +obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o obj-$(CONFIG_IR_IMON) += imon.o obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c new file mode 100644 index 000000000000..94967d0e0478 --- /dev/null +++ b/drivers/media/rc/ir-hix5hd2.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Allow the driver to compile on all architectures */ +#ifndef writel_relaxed +# define writel_relaxed writel +#endif + +#define IR_ENABLE 0x00 +#define IR_CONFIG 0x04 +#define CNT_LEADS 0x08 +#define CNT_LEADE 0x0c +#define CNT_SLEADE 0x10 +#define CNT0_B 0x14 +#define CNT1_B 0x18 +#define IR_BUSY 0x1c +#define IR_DATAH 0x20 +#define IR_DATAL 0x24 +#define IR_INTM 0x28 +#define IR_INTS 0x2c +#define IR_INTC 0x30 +#define IR_START 0x34 + +/* interrupt mask */ +#define INTMS_SYMBRCV (BIT(24) | BIT(8)) +#define INTMS_TIMEOUT (BIT(25) | BIT(9)) +#define INTMS_OVERFLOW (BIT(26) | BIT(10)) +#define INT_CLR_OVERFLOW BIT(18) +#define INT_CLR_TIMEOUT BIT(17) +#define INT_CLR_RCV BIT(16) +#define INT_CLR_RCVTIMEOUT (BIT(16) | BIT(17)) + +#define IR_CLK 0x48 +#define IR_CLK_ENABLE BIT(4) +#define IR_CLK_RESET BIT(5) + +#define IR_CFG_WIDTH_MASK 0xffff +#define IR_CFG_WIDTH_SHIFT 16 +#define IR_CFG_FORMAT_MASK 0x3 +#define IR_CFG_FORMAT_SHIFT 14 +#define IR_CFG_INT_LEVEL_MASK 0x3f +#define IR_CFG_INT_LEVEL_SHIFT 8 +/* only support raw mode */ +#define IR_CFG_MODE_RAW BIT(7) +#define IR_CFG_FREQ_MASK 0x7f +#define IR_CFG_FREQ_SHIFT 0 +#define IR_CFG_INT_THRESHOLD 1 +/* symbol start from low to high, symbol stream end at high*/ +#define IR_CFG_SYMBOL_FMT 0 +#define IR_CFG_SYMBOL_MAXWIDTH 0x3e80 + +#define IR_HIX5HD2_NAME "hix5hd2-ir" + +struct hix5hd2_ir_priv { + int irq; + void *base; + struct device *dev; + struct rc_dev *rdev; + struct regmap *regmap; + struct clk *clock; + unsigned long rate; +}; + +static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) +{ + u32 val; + + regmap_read(dev->regmap, IR_CLK, &val); + if (on) { + val &= ~IR_CLK_RESET; + val |= IR_CLK_ENABLE; + } else { + val &= ~IR_CLK_ENABLE; + val |= IR_CLK_RESET; + } + regmap_write(dev->regmap, IR_CLK, val); +} + +static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) +{ + int timeout = 10000; + u32 val, rate; + + writel_relaxed(0x01, priv->base + IR_ENABLE); + while (readl_relaxed(priv->base + IR_BUSY)) { + if (timeout--) { + udelay(1); + } else { + dev_err(priv->dev, "IR_BUSY timeout\n"); + return -ETIMEDOUT; + } + } + + /* Now only support raw mode, with symbol start from low to high */ + rate = DIV_ROUND_CLOSEST(priv->rate, 1000000); + val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT; + val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT; + val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK + << IR_CFG_INT_LEVEL_SHIFT; + val |= IR_CFG_MODE_RAW; + val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT; + writel_relaxed(val, priv->base + IR_CONFIG); + + writel_relaxed(0x00, priv->base + IR_INTM); + /* write arbitrary value to start */ + writel_relaxed(0x01, priv->base + IR_START); + return 0; +} + +static int hix5hd2_ir_open(struct rc_dev *rdev) +{ + struct hix5hd2_ir_priv *priv = rdev->priv; + + hix5hd2_ir_enable(priv, true); + return hix5hd2_ir_config(priv); +} + +static void hix5hd2_ir_close(struct rc_dev *rdev) +{ + struct hix5hd2_ir_priv *priv = rdev->priv; + + hix5hd2_ir_enable(priv, false); +} + +static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data) +{ + u32 symb_num, symb_val, symb_time; + u32 data_l, data_h; + u32 irq_sr, i; + struct hix5hd2_ir_priv *priv = data; + + irq_sr = readl_relaxed(priv->base + IR_INTS); + if (irq_sr & INTMS_OVERFLOW) { + /* + * we must read IR_DATAL first, then we can clean up + * IR_INTS availably since logic would not clear + * fifo when overflow, drv do the job + */ + ir_raw_event_reset(priv->rdev); + symb_num = readl_relaxed(priv->base + IR_DATAH); + for (i = 0; i < symb_num; i++) + readl_relaxed(priv->base + IR_DATAL); + + writel_relaxed(INT_CLR_OVERFLOW, priv->base + IR_INTC); + dev_info(priv->dev, "overflow, level=%d\n", + IR_CFG_INT_THRESHOLD); + } + + if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) { + DEFINE_IR_RAW_EVENT(ev); + + symb_num = readl_relaxed(priv->base + IR_DATAH); + for (i = 0; i < symb_num; i++) { + symb_val = readl_relaxed(priv->base + IR_DATAL); + data_l = ((symb_val & 0xffff) * 10); + data_h = ((symb_val >> 16) & 0xffff) * 10; + symb_time = (data_l + data_h) / 10; + + ev.duration = US_TO_NS(data_l); + ev.pulse = true; + ir_raw_event_store(priv->rdev, &ev); + + if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) { + ev.duration = US_TO_NS(data_h); + ev.pulse = false; + ir_raw_event_store(priv->rdev, &ev); + } else { + ir_raw_event_set_idle(priv->rdev, true); + } + } + + if (irq_sr & INTMS_SYMBRCV) + writel_relaxed(INT_CLR_RCV, priv->base + IR_INTC); + if (irq_sr & INTMS_TIMEOUT) + writel_relaxed(INT_CLR_TIMEOUT, priv->base + IR_INTC); + } + + /* Empty software fifo */ + ir_raw_event_handle(priv->rdev); + return IRQ_HANDLED; +} + +static int hix5hd2_ir_probe(struct platform_device *pdev) +{ + struct rc_dev *rdev; + struct device *dev = &pdev->dev; + struct resource *res; + struct hix5hd2_ir_priv *priv; + struct device_node *node = pdev->dev.of_node; + const char *map_name; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = syscon_regmap_lookup_by_phandle(node, + "hisilicon,power-syscon"); + if (IS_ERR(priv->regmap)) { + dev_err(dev, "no power-reg\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(dev, "irq can not get\n"); + return priv->irq; + } + + rdev = rc_allocate_device(); + if (!rdev) + return -ENOMEM; + + priv->clock = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clock)) { + dev_err(dev, "clock not found\n"); + ret = PTR_ERR(priv->clock); + goto err; + } + clk_prepare_enable(priv->clock); + priv->rate = clk_get_rate(priv->clock); + + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protocols = RC_BIT_ALL; + rdev->priv = priv; + rdev->open = hix5hd2_ir_open; + rdev->close = hix5hd2_ir_close; + rdev->driver_name = IR_HIX5HD2_NAME; + map_name = of_get_property(node, "linux,rc-map-name", NULL); + rdev->map_name = map_name ?: RC_MAP_EMPTY; + rdev->input_name = IR_HIX5HD2_NAME; + rdev->input_phys = IR_HIX5HD2_NAME "/input0"; + rdev->input_id.bustype = BUS_HOST; + rdev->input_id.vendor = 0x0001; + rdev->input_id.product = 0x0001; + rdev->input_id.version = 0x0100; + rdev->rx_resolution = US_TO_NS(10); + rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10); + + ret = rc_register_device(rdev); + if (ret < 0) + goto clkerr; + + if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt, + IRQF_NO_SUSPEND, pdev->name, priv) < 0) { + dev_err(dev, "IRQ %d register failed\n", priv->irq); + ret = -EINVAL; + goto regerr; + } + + priv->rdev = rdev; + priv->dev = dev; + platform_set_drvdata(pdev, priv); + + return ret; + +regerr: + rc_unregister_device(rdev); + rdev = NULL; +clkerr: + clk_disable_unprepare(priv->clock); +err: + rc_free_device(rdev); + dev_err(dev, "Unable to register device (%d)\n", ret); + return ret; +} + +static int hix5hd2_ir_remove(struct platform_device *pdev) +{ + struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev); + + clk_disable_unprepare(priv->clock); + rc_unregister_device(priv->rdev); + return 0; +} + +#ifdef CONFIG_PM +static int hix5hd2_ir_suspend(struct device *dev) +{ + struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); + + clk_disable_unprepare(priv->clock); + hix5hd2_ir_enable(priv, false); + + return 0; +} + +static int hix5hd2_ir_resume(struct device *dev) +{ + struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev); + + hix5hd2_ir_enable(priv, true); + clk_prepare_enable(priv->clock); + + writel_relaxed(0x01, priv->base + IR_ENABLE); + writel_relaxed(0x00, priv->base + IR_INTM); + writel_relaxed(0xff, priv->base + IR_INTC); + writel_relaxed(0x01, priv->base + IR_START); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend, + hix5hd2_ir_resume); + +static struct of_device_id hix5hd2_ir_table[] = { + { .compatible = "hisilicon,hix5hd2-ir", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hix5hd2_ir_table); + +static struct platform_driver hix5hd2_ir_driver = { + .driver = { + .name = IR_HIX5HD2_NAME, + .of_match_table = hix5hd2_ir_table, + .pm = &hix5hd2_ir_pm_ops, + }, + .probe = hix5hd2_ir_probe, + .remove = hix5hd2_ir_remove, +}; + +module_platform_driver(hix5hd2_ir_driver); + +MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms"); +MODULE_AUTHOR("Guoxiong Yan "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:hix5hd2-ir"); -- cgit v1.2.3 From 89d7ce5a0f159ffa99d0521b4336b922acdc7ac5 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 22 Sep 2014 19:22:26 -0300 Subject: [media] media: st-rc: move to using reset_control_get_optional This patch fixes a compilation error while building with the random kernel configuration. drivers/media/rc/st_rc.c: In function 'st_rc_probe': drivers/media/rc/st_rc.c:281:2: error: implicit declaration of function 'reset_control_get' [-Werror=implicit-function-declaration] rc_dev->rstc = reset_control_get(dev, NULL); drivers/media/rc/st_rc.c:281:15: warning: assignment makes pointer from integer without a cast [enabled by default] rc_dev->rstc = reset_control_get(dev, NULL); Reported-by: Jim Davis Signed-off-by: Srinivas Kandagatla Acked-by: Maxime Coquelin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 5c151351afa4..e0f13125bf06 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -278,7 +278,7 @@ static int st_rc_probe(struct platform_device *pdev) rc_dev->rx_base = rc_dev->base; - rc_dev->rstc = reset_control_get(dev, NULL); + rc_dev->rstc = reset_control_get_optional(dev, NULL); if (IS_ERR(rc_dev->rstc)) rc_dev->rstc = NULL; -- cgit v1.2.3 From cdd9a6316bfb85176aba83e9532fbc46c9588378 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 22 Sep 2014 19:22:38 -0300 Subject: [media] media: st-rc: move pm ops setup out of conditional compilation This patch moves setting of pm_ops out of the CONFIG_PM_SLEEP condition. Setting pm ops under CONFIG_PM_SLEEP does not make any sense. This patch also remove unnecessary also remove CONFIG_PM condition for pm member in st_rc_driver structure. Signed-off-by: Srinivas Kandagatla Acked-by: Maxime Coquelin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index e0f13125bf06..03bbb096cb9b 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -376,9 +376,10 @@ static int st_rc_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume); #endif +static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume); + #ifdef CONFIG_OF static struct of_device_id st_rc_match[] = { { .compatible = "st,comms-irb", }, @@ -393,9 +394,7 @@ static struct platform_driver st_rc_driver = { .name = IR_ST_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(st_rc_match), -#ifdef CONFIG_PM .pm = &st_rc_pm_ops, -#endif }, .probe = st_rc_probe, .remove = st_rc_remove, -- cgit v1.2.3 From da8e77f5e945ee92a6225c18f545630e07fc41bc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 22 Sep 2014 19:22:48 -0300 Subject: [media] media: st-rc: Remove .owner field for driver There is no need to init .owner field. Based on the patch from Peter Griffin "mmc: remove .owner field for drivers using module_platform_driver" This patch removes the superflous .owner field for drivers which use the module_platform_driver API, as this is overriden in platform_driver_register anyway." Signed-off-by: Srinivas Kandagatla Acked-by: Maxime Coquelin Acked-by: Peter Griffin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 03bbb096cb9b..e309441a266d 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -392,7 +392,6 @@ MODULE_DEVICE_TABLE(of, st_rc_match); static struct platform_driver st_rc_driver = { .driver = { .name = IR_ST_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st_rc_match), .pm = &st_rc_pm_ops, }, -- cgit v1.2.3 From 0f531e735651555568816b6cf7631816003dc1d2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 22 Sep 2014 14:50:35 -0300 Subject: [media] tda18271-common: Convert _tda_printk to return void No caller or macro uses the return value so make it void. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda18271-common.c | 19 ++++++++----------- drivers/media/tuners/tda18271-priv.h | 4 ++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 18c77afe2e4f..86e5e3110118 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -714,12 +714,11 @@ fail: return ret; } -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...) +void _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...) { struct va_format vaf; va_list args; - int rtn; va_start(args, fmt); @@ -727,15 +726,13 @@ int _tda_printk(struct tda18271_priv *state, const char *level, vaf.va = &args; if (state) - rtn = printk("%s%s: [%d-%04x|%c] %pV", - level, func, i2c_adapter_id(state->i2c_props.adap), - state->i2c_props.addr, - (state->role == TDA18271_MASTER) ? 'M' : 'S', - &vaf); + printk("%s%s: [%d-%04x|%c] %pV", + level, func, i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr, + (state->role == TDA18271_MASTER) ? 'M' : 'S', + &vaf); else - rtn = printk("%s%s: %pV", level, func, &vaf); + printk("%s%s: %pV", level, func, &vaf); va_end(args); - - return rtn; } diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index 454c152ccaa0..b36a7b754772 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h @@ -139,8 +139,8 @@ extern int tda18271_debug; #define DBG_CAL 16 __attribute__((format(printf, 4, 5))) -int _tda_printk(struct tda18271_priv *state, const char *level, - const char *func, const char *fmt, ...); +void _tda_printk(struct tda18271_priv *state, const char *level, + const char *func, const char *fmt, ...); #define tda_printk(st, lvl, fmt, arg...) \ _tda_printk(st, lvl, __func__, fmt, ##arg) -- cgit v1.2.3 From aff0c42a78ed2b6410a083dce59bb6c9fe85da27 Mon Sep 17 00:00:00 2001 From: Akihiro Tsukada Date: Mon, 8 Sep 2014 14:20:40 -0300 Subject: [media] mxl301rf: add driver for MaxLinear MxL301RF OFDM tuner This patch adds driver for mxl301rf OFDM tuner chips. It is used as an ISDB-T tuner in earthsoft pt3 cards. Note that this driver does not initilize the chip, because the initilization sequence / register setting is not disclosed. Thus, the driver assumes that the chips are initilized externally by its parent board driver before tuner_ops->init() are called, like in PT3 driver where the bridge chip contains the init sequence in its private memory and provides a command to trigger the sequence. Signed-off-by: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 7 + drivers/media/tuners/Makefile | 1 + drivers/media/tuners/mxl301rf.c | 349 ++++++++++++++++++++++++++++++++++++++++ drivers/media/tuners/mxl301rf.h | 26 +++ 4 files changed, 383 insertions(+) create mode 100644 drivers/media/tuners/mxl301rf.c create mode 100644 drivers/media/tuners/mxl301rf.h diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 69a9fa5dd076..b04356b62d01 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -260,4 +260,11 @@ config MEDIA_TUNER_R820T default m if !MEDIA_SUBDRV_AUTOSELECT help Rafael Micro R820T silicon tuner driver. + +config MEDIA_TUNER_MXL301RF + tristate "MaxLinear MxL301RF tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + MaxLinear MxL301RF OFDM tuner driver. endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 7eede5cd9906..5c41a33d92dd 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -39,6 +39,7 @@ 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_R820T) += r820t.o +obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c new file mode 100644 index 000000000000..1575a5db776a --- /dev/null +++ b/drivers/media/tuners/mxl301rf.c @@ -0,0 +1,349 @@ +/* + * MaxLinear MxL301RF OFDM tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +/* + * NOTICE: + * This driver is incomplete and lacks init/config of the chips, + * as the necessary info is not disclosed. + * Other features like get_if_frequency() are missing as well. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) properly init and configure the chip + * via I2C *before* calling this driver's init() function. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include +#include "mxl301rf.h" + +struct mxl301rf_state { + struct mxl301rf_config cfg; + struct i2c_client *i2c; +}; + +static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c) +{ + return container_of(c, struct mxl301rf_state, cfg); +} + +static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(state->i2c, buf, len); + if (ret >= 0 && ret < len) + ret = -EIO; + return (ret == len) ? 0 : ret; +} + +static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + + return raw_write(state, buf, 2); +} + +static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val) +{ + u8 wbuf[2] = { 0xfb, reg }; + int ret; + + ret = raw_write(state, wbuf, sizeof(wbuf)); + if (ret == 0) + ret = i2c_master_recv(state->i2c, val, 1); + if (ret >= 0 && ret < 1) + ret = -EIO; + return (ret == 1) ? 0 : ret; +} + +/* tuner_ops */ + +/* get RSSI and update propery cache, set to *out in % */ +static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out) +{ + struct mxl301rf_state *state; + int ret; + u8 rf_in1, rf_in2, rf_off1, rf_off2; + u16 rf_in, rf_off; + s64 level; + struct dtv_fe_stats *rssi; + + rssi = &fe->dtv_property_cache.strength; + rssi->len = 1; + rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + *out = 0; + + state = fe->tuner_priv; + ret = reg_write(state, 0x14, 0x01); + if (ret < 0) + return ret; + usleep_range(1000, 2000); + + ret = reg_read(state, 0x18, &rf_in1); + if (ret == 0) + ret = reg_read(state, 0x19, &rf_in2); + if (ret == 0) + ret = reg_read(state, 0xd6, &rf_off1); + if (ret == 0) + ret = reg_read(state, 0xd7, &rf_off2); + if (ret != 0) + return ret; + + rf_in = (rf_in2 & 0x07) << 8 | rf_in1; + rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3); + level = rf_in - rf_off - (113 << 3); /* x8 dBm */ + level = level * 1000 / 8; + rssi->stat[0].svalue = level; + rssi->stat[0].scale = FE_SCALE_DECIBEL; + /* *out = (level - min) * 100 / (max - min) */ + *out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2); + return 0; +} + +/* spur shift parameters */ +struct shf { + u32 freq; /* Channel center frequency */ + u32 ofst_th; /* Offset frequency threshold */ + u8 shf_val; /* Spur shift value */ + u8 shf_dir; /* Spur shift direction */ +}; + +static const struct shf shf_tab[] = { + { 64500, 500, 0x92, 0x07 }, + { 191500, 300, 0xe2, 0x07 }, + { 205500, 500, 0x2c, 0x04 }, + { 212500, 500, 0x1e, 0x04 }, + { 226500, 500, 0xd4, 0x07 }, + { 99143, 500, 0x9c, 0x07 }, + { 173143, 500, 0xd4, 0x07 }, + { 191143, 300, 0xd4, 0x07 }, + { 207143, 500, 0xce, 0x07 }, + { 225143, 500, 0xce, 0x07 }, + { 243143, 500, 0xd4, 0x07 }, + { 261143, 500, 0xd4, 0x07 }, + { 291143, 500, 0xd4, 0x07 }, + { 339143, 500, 0x2c, 0x04 }, + { 117143, 500, 0x7a, 0x07 }, + { 135143, 300, 0x7a, 0x07 }, + { 153143, 500, 0x01, 0x07 } +}; + +struct reg_val { + u8 reg; + u8 val; +} __attribute__ ((__packed__)); + +static const struct reg_val set_idac[] = { + { 0x0d, 0x00 }, + { 0x0c, 0x67 }, + { 0x6f, 0x89 }, + { 0x70, 0x0c }, + { 0x6f, 0x8a }, + { 0x70, 0x0e }, + { 0x6f, 0x8b }, + { 0x70, 0x1c }, +}; + +static int mxl301rf_set_params(struct dvb_frontend *fe) +{ + struct reg_val tune0[] = { + { 0x13, 0x00 }, /* abort tuning */ + { 0x3b, 0xc0 }, + { 0x3b, 0x80 }, + { 0x10, 0x95 }, /* BW */ + { 0x1a, 0x05 }, + { 0x61, 0x00 }, /* spur shift value (placeholder) */ + { 0x62, 0xa0 } /* spur shift direction (placeholder) */ + }; + + struct reg_val tune1[] = { + { 0x11, 0x40 }, /* RF frequency L (placeholder) */ + { 0x12, 0x0e }, /* RF frequency H (placeholder) */ + { 0x13, 0x01 } /* start tune */ + }; + + struct mxl301rf_state *state; + u32 freq; + u16 f; + u32 tmp, div; + int i, ret; + + state = fe->tuner_priv; + freq = fe->dtv_property_cache.frequency; + + /* spur shift function (for analog) */ + for (i = 0; i < ARRAY_SIZE(shf_tab); i++) { + if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 && + freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) { + tune0[5].val = shf_tab[i].shf_val; + tune0[6].val = 0xa0 | shf_tab[i].shf_dir; + break; + } + } + ret = raw_write(state, (u8 *) tune0, sizeof(tune0)); + if (ret < 0) + goto failed; + usleep_range(3000, 4000); + + /* convert freq to 10.6 fixed point float [MHz] */ + f = freq / 1000000; + tmp = freq % 1000000; + div = 1000000; + for (i = 0; i < 6; i++) { + f <<= 1; + div >>= 1; + if (tmp > div) { + tmp -= div; + f |= 1; + } + } + if (tmp > 7812) + f++; + tune1[0].val = f & 0xff; + tune1[1].val = f >> 8; + ret = raw_write(state, (u8 *) tune1, sizeof(tune1)); + if (ret < 0) + goto failed; + msleep(31); + + ret = reg_write(state, 0x1a, 0x0d); + if (ret < 0) + goto failed; + ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac)); + if (ret < 0) + goto failed; + return 0; + +failed: + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static const struct reg_val standby_data[] = { + { 0x01, 0x00 }, + { 0x13, 0x00 } +}; + +static int mxl301rf_sleep(struct dvb_frontend *fe) +{ + struct mxl301rf_state *state; + int ret; + + state = fe->tuner_priv; + ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data)); + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + + +/* init sequence is not public. + * the parent must have init'ed the device. + * just wake up here. + */ +static int mxl301rf_init(struct dvb_frontend *fe) +{ + struct mxl301rf_state *state; + int ret; + + state = fe->tuner_priv; + + ret = reg_write(state, 0x01, 0x01); + if (ret < 0) { + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; + } + return 0; +} + +/* I2C driver functions */ + +static const struct dvb_tuner_ops mxl301rf_ops = { + .info = { + .name = "MaxLinear MxL301RF", + + .frequency_min = 93000000, + .frequency_max = 803142857, + }, + + .init = mxl301rf_init, + .sleep = mxl301rf_sleep, + + .set_params = mxl301rf_set_params, + .get_rf_strength = mxl301rf_get_rf_strength, +}; + + +static int mxl301rf_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxl301rf_state *state; + struct mxl301rf_config *cfg; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->i2c = client; + cfg = client->dev.platform_data; + + memcpy(&state->cfg, cfg, sizeof(state->cfg)); + fe = cfg->fe; + fe->tuner_priv = state; + memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops)); + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "MaxLinear MxL301RF attached.\n"); + return 0; +} + +static int mxl301rf_remove(struct i2c_client *client) +{ + struct mxl301rf_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + state->cfg.fe->tuner_priv = NULL; + kfree(state); + return 0; +} + + +static const struct i2c_device_id mxl301rf_id[] = { + {"mxl301rf", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mxl301rf_id); + +static struct i2c_driver mxl301rf_driver = { + .driver = { + .name = "mxl301rf", + }, + .probe = mxl301rf_probe, + .remove = mxl301rf_remove, + .id_table = mxl301rf_id, +}; + +module_i2c_driver(mxl301rf_driver); + +MODULE_DESCRIPTION("MaxLinear MXL301RF tuner"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h new file mode 100644 index 000000000000..19e68405f00d --- /dev/null +++ b/drivers/media/tuners/mxl301rf.h @@ -0,0 +1,26 @@ +/* + * MaxLinear MxL301RF OFDM tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +#ifndef MXL301RF_H +#define MXL301RF_H + +#include "dvb_frontend.h" + +struct mxl301rf_config { + struct dvb_frontend *fe; +}; + +#endif /* MXL301RF_H */ -- cgit v1.2.3 From 7608f575b81599ba8e73c27b7ca1fa3993dee585 Mon Sep 17 00:00:00 2001 From: Akihiro Tsukada Date: Mon, 8 Sep 2014 14:20:41 -0300 Subject: [media] qm1d1c0042: add driver for Sharp QM1D1C0042 ISDB-S tuner This patch adds driver for qm1d1c0042 tuner chips. It is used as an ISDB-S tuner in earthsoft pt3 cards. Signed-off-by: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 7 + drivers/media/tuners/Makefile | 1 + drivers/media/tuners/qm1d1c0042.c | 445 ++++++++++++++++++++++++++++++++++++++ drivers/media/tuners/qm1d1c0042.h | 37 ++++ 4 files changed, 490 insertions(+) create mode 100644 drivers/media/tuners/qm1d1c0042.c create mode 100644 drivers/media/tuners/qm1d1c0042.h diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index b04356b62d01..f039dc2a21cf 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -267,4 +267,11 @@ config MEDIA_TUNER_MXL301RF default m if !MEDIA_SUBDRV_AUTOSELECT help MaxLinear MxL301RF OFDM tuner driver. + +config MEDIA_TUNER_QM1D1C0042 + tristate "Sharp QM1D1C0042 tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Sharp QM1D1C0042 trellis coded 8PSK tuner driver. endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 5c41a33d92dd..49fcf8033848 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o +obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c new file mode 100644 index 000000000000..585594b9c4f8 --- /dev/null +++ b/drivers/media/tuners/qm1d1c0042.c @@ -0,0 +1,445 @@ +/* + * Sharp QM1D1C0042 8PSK tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +/* + * NOTICE: + * As the disclosed information on the chip is very limited, + * this driver lacks some features, including chip config like IF freq. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) know the relevant info and + * configure the chip via I2C if necessary. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include +#include "qm1d1c0042.h" + +#define QM1D1C0042_NUM_REGS 0x20 + +static const u8 reg_initval[QM1D1C0042_NUM_REGS] = { + 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86, + 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00 +}; + +static const struct qm1d1c0042_config default_cfg = { + .xtal_freq = 16000, + .lpf = 1, + .fast_srch = 0, + .lpf_wait = 20, + .fast_srch_wait = 4, + .normal_srch_wait = 15, +}; + +struct qm1d1c0042_state { + struct qm1d1c0042_config cfg; + struct i2c_client *i2c; + u8 regs[QM1D1C0042_NUM_REGS]; +}; + +static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c) +{ + return container_of(c, struct qm1d1c0042_state, cfg); +} + +static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val) +{ + u8 wbuf[2] = { reg, val }; + int ret; + + ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf)); + if (ret >= 0 && ret < sizeof(wbuf)) + ret = -EIO; + return (ret == sizeof(wbuf)) ? 0 : ret; +} + +static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = { + { + .addr = state->i2c->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, + { + .addr = state->i2c->addr, + .flags = I2C_M_RD, + .buf = val, + .len = 1, + }, + }; + int ret; + + ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret >= 0 && ret < ARRAY_SIZE(msgs)) + ret = -EIO; + return (ret == ARRAY_SIZE(msgs)) ? 0 : ret; +} + + +static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast) +{ + if (fast) + state->regs[0x03] |= 0x01; /* set fast search mode */ + else + state->regs[0x03] &= ~0x01 & 0xff; + + return reg_write(state, 0x03, state->regs[0x03]); +} + +static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state) +{ + int ret; + + state->regs[0x01] |= 1 << 3; /* BB_Reg_enable */ + state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */ + state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */ + ret = reg_write(state, 0x01, state->regs[0x01]); + if (ret == 0) + ret = reg_write(state, 0x05, state->regs[0x05]); + + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, state->cfg.fe->dvb->num, state->cfg.fe->id); + return ret; +} + +/* tuner_ops */ + +static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct qm1d1c0042_state *state; + struct qm1d1c0042_config *cfg; + + state = fe->tuner_priv; + cfg = priv_cfg; + + if (cfg->fe) + state->cfg.fe = cfg->fe; + + if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT) + dev_warn(&state->i2c->dev, + "(%s) changing xtal_freq not supported. ", __func__); + state->cfg.xtal_freq = default_cfg.xtal_freq; + + state->cfg.lpf = cfg->lpf; + state->cfg.fast_srch = cfg->fast_srch; + + if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.lpf_wait = cfg->lpf_wait; + else + state->cfg.lpf_wait = default_cfg.lpf_wait; + + if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.fast_srch_wait = cfg->fast_srch_wait; + else + state->cfg.fast_srch_wait = default_cfg.fast_srch_wait; + + if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT) + state->cfg.normal_srch_wait = cfg->normal_srch_wait; + else + state->cfg.normal_srch_wait = default_cfg.normal_srch_wait; + return 0; +} + +/* divisor, vco_band parameters */ +/* {maxfreq, param1(band?), param2(div?) */ +static const u32 conv_table[9][3] = { + { 2151000, 1, 7 }, + { 1950000, 1, 6 }, + { 1800000, 1, 5 }, + { 1600000, 1, 4 }, + { 1450000, 1, 3 }, + { 1250000, 1, 2 }, + { 1200000, 0, 7 }, + { 975000, 0, 6 }, + { 950000, 0, 0 } +}; + +static int qm1d1c0042_set_params(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + u32 freq; + int i, ret; + u8 val, mask; + u32 a, sd; + s32 b; + + state = fe->tuner_priv; + freq = fe->dtv_property_cache.frequency; + + state->regs[0x08] &= 0xf0; + state->regs[0x08] |= 0x09; + + state->regs[0x13] &= 0x9f; + state->regs[0x13] |= 0x20; + + /* div2/vco_band */ + val = state->regs[0x02] & 0x0f; + for (i = 0; i < 8; i++) + if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) { + val |= conv_table[i][1] << 7; + val |= conv_table[i][2] << 4; + break; + } + ret = reg_write(state, 0x02, val); + if (ret < 0) + return ret; + + a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq; + + state->regs[0x06] &= 0x40; + state->regs[0x06] |= (a - 12) / 4; + ret = reg_write(state, 0x06, state->regs[0x06]); + if (ret < 0) + return ret; + + state->regs[0x07] &= 0xf0; + state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f; + ret = reg_write(state, 0x07, state->regs[0x07]); + if (ret < 0) + return ret; + + /* LPF */ + val = state->regs[0x08]; + if (state->cfg.lpf) { + /* LPF_CLK, LPF_FC */ + val &= 0xf0; + val |= 0x02; + } + ret = reg_write(state, 0x08, val); + if (ret < 0) + return ret; + + /* + * b = (freq / state->cfg.xtal_freq - a) << 20; + * sd = b (b >= 0) + * 1<<22 + b (b < 0) + */ + b = (((s64) freq) << 20) / state->cfg.xtal_freq - (((s64) a) << 20); + if (b >= 0) + sd = b; + else + sd = (1 << 22) + b; + + state->regs[0x09] &= 0xc0; + state->regs[0x09] |= (sd >> 16) & 0x3f; + state->regs[0x0a] = (sd >> 8) & 0xff; + state->regs[0x0b] = sd & 0xff; + ret = reg_write(state, 0x09, state->regs[0x09]); + if (ret == 0) + ret = reg_write(state, 0x0a, state->regs[0x0a]); + if (ret == 0) + ret = reg_write(state, 0x0b, state->regs[0x0b]); + if (ret != 0) + return ret; + + if (!state->cfg.lpf) { + /* CSEL_Offset */ + ret = reg_write(state, 0x13, state->regs[0x13]); + if (ret < 0) + return ret; + } + + /* VCO_TM, LPF_TM */ + mask = state->cfg.lpf ? 0x3f : 0x7f; + val = state->regs[0x0c] & mask; + ret = reg_write(state, 0x0c, val); + if (ret < 0) + return ret; + usleep_range(2000, 3000); + val = state->regs[0x0c] | ~mask; + ret = reg_write(state, 0x0c, val); + if (ret < 0) + return ret; + + if (state->cfg.lpf) + msleep(state->cfg.lpf_wait); + else if (state->regs[0x03] & 0x01) + msleep(state->cfg.fast_srch_wait); + else + msleep(state->cfg.normal_srch_wait); + + if (state->cfg.lpf) { + /* LPF_FC */ + ret = reg_write(state, 0x08, 0x09); + if (ret < 0) + return ret; + + /* CSEL_Offset */ + ret = reg_write(state, 0x13, state->regs[0x13]); + if (ret < 0) + return ret; + } + return 0; +} + +static int qm1d1c0042_sleep(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + int ret; + + state = fe->tuner_priv; + state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */ + state->regs[0x01] |= 1 << 0; /* STDBY */ + state->regs[0x05] |= 1 << 3; /* pfd_rst STANDBY */ + ret = reg_write(state, 0x05, state->regs[0x05]); + if (ret == 0) + ret = reg_write(state, 0x01, state->regs[0x01]); + if (ret < 0) + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static int qm1d1c0042_init(struct dvb_frontend *fe) +{ + struct qm1d1c0042_state *state; + u8 val; + int i, ret; + + state = fe->tuner_priv; + memcpy(state->regs, reg_initval, sizeof(reg_initval)); + + reg_write(state, 0x01, 0x0c); + reg_write(state, 0x01, 0x0c); + + ret = reg_write(state, 0x01, 0x0c); /* soft reset on */ + if (ret < 0) + goto failed; + usleep_range(2000, 3000); + + val = state->regs[0x01] | 0x10; + ret = reg_write(state, 0x01, val); /* soft reset off */ + if (ret < 0) + goto failed; + + /* check ID */ + ret = reg_read(state, 0x00, &val); + if (ret < 0 || val != 0x48) + goto failed; + usleep_range(2000, 3000); + + state->regs[0x0c] |= 0x40; + ret = reg_write(state, 0x0c, state->regs[0x0c]); + if (ret < 0) + goto failed; + msleep(state->cfg.lpf_wait); + + /* set all writable registers */ + for (i = 1; i <= 0x0c ; i++) { + ret = reg_write(state, i, state->regs[i]); + if (ret < 0) + goto failed; + } + for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) { + ret = reg_write(state, i, state->regs[i]); + if (ret < 0) + goto failed; + } + + ret = qm1d1c0042_wakeup(state); + if (ret < 0) + goto failed; + + ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch); + if (ret < 0) + goto failed; + + return ret; + +failed: + dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +/* I2C driver functions */ + +static const struct dvb_tuner_ops qm1d1c0042_ops = { + .info = { + .name = "Sharp QM1D1C0042", + + .frequency_min = 950000, + .frequency_max = 2150000, + }, + + .init = qm1d1c0042_init, + .sleep = qm1d1c0042_sleep, + .set_config = qm1d1c0042_set_config, + .set_params = qm1d1c0042_set_params, +}; + + +static int qm1d1c0042_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qm1d1c0042_state *state; + struct qm1d1c0042_config *cfg; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->i2c = client; + + cfg = client->dev.platform_data; + fe = cfg->fe; + fe->tuner_priv = state; + qm1d1c0042_set_config(fe, cfg); + memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops)); + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n"); + return 0; +} + +static int qm1d1c0042_remove(struct i2c_client *client) +{ + struct qm1d1c0042_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + state->cfg.fe->tuner_priv = NULL; + kfree(state); + return 0; +} + + +static const struct i2c_device_id qm1d1c0042_id[] = { + {"qm1d1c0042", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id); + +static struct i2c_driver qm1d1c0042_driver = { + .driver = { + .name = "qm1d1c0042", + }, + .probe = qm1d1c0042_probe, + .remove = qm1d1c0042_remove, + .id_table = qm1d1c0042_id, +}; + +module_i2c_driver(qm1d1c0042_driver); + +MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h new file mode 100644 index 000000000000..4f5c18816c44 --- /dev/null +++ b/drivers/media/tuners/qm1d1c0042.h @@ -0,0 +1,37 @@ +/* + * Sharp QM1D1C0042 8PSK tuner driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +#ifndef QM1D1C0042_H +#define QM1D1C0042_H + +#include "dvb_frontend.h" + + +struct qm1d1c0042_config { + struct dvb_frontend *fe; + + u32 xtal_freq; /* [kHz] */ /* currently ignored */ + bool lpf; /* enable LPF */ + bool fast_srch; /* enable fast search mode, no LPF */ + u32 lpf_wait; /* wait in tuning with LPF enabled. [ms] */ + u32 fast_srch_wait; /* with fast-search mode, no LPF. [ms] */ + u32 normal_srch_wait; /* with no LPF/fast-search mode. [ms] */ +}; +/* special values indicating to use the default in qm1d1c0042_config */ +#define QM1D1C0042_CFG_XTAL_DFLT 0 +#define QM1D1C0042_CFG_WAIT_DFLT 0 + +#endif /* QM1D1C0042_H */ -- cgit v1.2.3 From f5d82a75e666a6cc66453285cb3ce28c5d02397a Mon Sep 17 00:00:00 2001 From: Akihiro Tsukada Date: Mon, 8 Sep 2014 14:20:42 -0300 Subject: [media] tc90522: add driver for Toshiba TC90522 quad demodulator This patch adds driver for tc90522 demodulator chips. The chip contains 4 demod modules that run in parallel and are independently controllable via separate I2C addresses. Two of the modules are for ISDB-T and the rest for ISDB-S. It is used in earthsoft pt3 cards. Note that this driver does not init the chip, because the initilization sequence / register setting is not disclosed. Thus, the driver assumes that the chips are initilized externally by its parent board driver before fe->ops->init() are called. Earthsoft PT3 PCIe card, for example, contains the init sequence in its private memory and provides a command to trigger the sequence. Signed-off-by: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 8 + drivers/media/dvb-frontends/Makefile | 1 + drivers/media/dvb-frontends/tc90522.c | 839 ++++++++++++++++++++++++++++++++++ drivers/media/dvb-frontends/tc90522.h | 42 ++ 4 files changed, 890 insertions(+) create mode 100644 drivers/media/dvb-frontends/tc90522.c create mode 100644 drivers/media/dvb-frontends/tc90522.h diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 704403f892d5..5a134547e325 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -648,6 +648,14 @@ config DVB_MB86A20S A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. Say Y when you want to support this frontend. +config DVB_TC90522 + tristate "Toshiba TC90522" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator. + Say Y when you want to support this frontend. + comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 1e19a74d1f60..ba59df63d050 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -115,3 +115,4 @@ obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o obj-$(CONFIG_DVB_AF9033) += af9033.o obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o +obj-$(CONFIG_DVB_TC90522) += tc90522.o diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c new file mode 100644 index 000000000000..f4760dd998c3 --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.c @@ -0,0 +1,839 @@ +/* + * Toshiba TC90522 Demodulator + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +/* + * NOTICE: + * This driver is incomplete and lacks init/config of the chips, + * as the necessary info is not disclosed. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) properly init and configure the chip + * via I2C *before* calling this driver's init() function. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include +#include +#include "dvb_math.h" +#include "tc90522.h" + +#define TC90522_I2C_THRU_REG 0xfe + +#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1) + +struct tc90522_state { + struct tc90522_config cfg; + struct dvb_frontend fe; + struct i2c_client *i2c_client; + struct i2c_adapter tuner_i2c; + + bool lna; +}; + +struct reg_val { + u8 reg; + u8 val; +}; + +static int +reg_write(struct tc90522_state *state, const struct reg_val *regs, int num) +{ + int i, ret; + struct i2c_msg msg; + + ret = 0; + msg.addr = state->i2c_client->addr; + msg.flags = 0; + msg.len = 2; + for (i = 0; i < num; i++) { + msg.buf = (u8 *)®s[i]; + ret = i2c_transfer(state->i2c_client->adapter, &msg, 1); + if (ret == 0) + ret = -EIO; + if (ret < 0) + return ret; + } + return 0; +} + +static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = { + { + .addr = state->i2c_client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, + { + .addr = state->i2c_client->addr, + .flags = I2C_M_RD, + .buf = val, + .len = len, + }, + }; + int ret; + + ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret == ARRAY_SIZE(msgs)) + ret = 0; + else if (ret >= 0) + ret = -EIO; + return ret; +} + +static struct tc90522_state *cfg_to_state(struct tc90522_config *c) +{ + return container_of(c, struct tc90522_state, cfg); +} + + +static int tc90522s_set_tsid(struct dvb_frontend *fe) +{ + struct reg_val set_tsid[] = { + { 0x8f, 00 }, + { 0x90, 00 } + }; + + set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8; + set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff; + return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid)); +} + +static int tc90522t_set_layers(struct dvb_frontend *fe) +{ + struct reg_val rv; + u8 laysel; + + laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07; + laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2; + rv.reg = 0x71; + rv.val = laysel; + return reg_write(fe->demodulator_priv, &rv, 1); +} + +/* frontend ops */ + +static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tc90522_state *state; + int ret; + u8 reg; + + state = fe->demodulator_priv; + ret = reg_read(state, 0xc3, ®, 1); + if (ret < 0) + return ret; + + *status = 0; + if (reg & 0x80) /* input level under min ? */ + return 0; + *status |= FE_HAS_SIGNAL; + + if (reg & 0x60) /* carrier? */ + return 0; + *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC; + + if (reg & 0x10) + return 0; + if (reg_read(state, 0xc5, ®, 1) < 0 || !(reg & 0x03)) + return 0; + *status |= FE_HAS_LOCK; + return 0; +} + +static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tc90522_state *state; + int ret; + u8 reg; + + state = fe->demodulator_priv; + ret = reg_read(state, 0x96, ®, 1); + if (ret < 0) + return ret; + + *status = 0; + if (reg & 0xe0) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI + | FE_HAS_SYNC | FE_HAS_LOCK; + return 0; + } + + ret = reg_read(state, 0x80, ®, 1); + if (ret < 0) + return ret; + + if (reg & 0xf0) + return 0; + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + + if (reg & 0x0c) + return 0; + *status |= FE_HAS_SYNC | FE_HAS_VITERBI; + + if (reg & 0x02) + return 0; + *status |= FE_HAS_LOCK; + return 0; +} + +static const fe_code_rate_t fec_conv_sat[] = { + FEC_NONE, /* unused */ + FEC_1_2, /* for BPSK */ + FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */ + FEC_2_3, /* for 8PSK. (trellis code) */ +}; + +static int tc90522s_get_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + struct dtv_frontend_properties *c; + struct dtv_fe_stats *stats; + int ret, i; + int layers; + u8 val[10]; + u32 cndat; + + state = fe->demodulator_priv; + c = &fe->dtv_property_cache; + c->delivery_system = SYS_ISDBS; + + layers = 0; + ret = reg_read(state, 0xe8, val, 3); + if (ret == 0) { + int slots; + u8 v; + + /* high/single layer */ + v = (val[0] & 0x70) >> 4; + c->modulation = (v == 7) ? PSK_8 : QPSK; + c->fec_inner = fec_conv_sat[v]; + c->layer[0].fec = c->fec_inner; + c->layer[0].modulation = c->modulation; + c->layer[0].segment_count = val[1] & 0x3f; /* slots */ + + /* low layer */ + v = (val[0] & 0x07); + c->layer[1].fec = fec_conv_sat[v]; + if (v == 0) /* no low layer */ + c->layer[1].segment_count = 0; + else + c->layer[1].segment_count = val[2] & 0x3f; /* slots */ + /* actually, BPSK if v==1, but not defined in fe_modulation_t */ + c->layer[1].modulation = QPSK; + layers = (v > 0) ? 2 : 1; + + slots = c->layer[0].segment_count + c->layer[1].segment_count; + c->symbol_rate = 28860000 * slots / 48; + } + + /* statistics */ + + stats = &c->strength; + stats->len = 0; + /* let the connected tuner set RSSI property cache */ + if (fe->ops.tuner_ops.get_rf_strength) { + u16 dummy; + + fe->ops.tuner_ops.get_rf_strength(fe, &dummy); + } + + stats = &c->cnr; + stats->len = 1; + stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + cndat = 0; + ret = reg_read(state, 0xbc, val, 2); + if (ret == 0) + cndat = val[0] << 8 | val[1]; + if (cndat >= 3000) { + u32 p, p4; + s64 cn; + + cndat -= 3000; /* cndat: 4.12 fixed point float */ + /* + * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3 + * + 88977 * P^2 - 89565 * P + 58857 + * (P = sqrt(cndat) / 64) + */ + /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed point float */ + /* cn = cnr << 3 */ + p = int_sqrt(cndat << 16); + p4 = cndat * cndat; + cn = (-16346LL * p4 * p / 10) >> 35; + cn += (14341LL * p4) >> 21; + cn -= (50259LL * cndat * p) >> 23; + cn += (88977LL * cndat) >> 9; + cn -= (89565LL * p) >> 11; + cn += 58857 << 3; + stats->stat[0].svalue = cn >> 3; + stats->stat[0].scale = FE_SCALE_DECIBEL; + } + + /* per-layer post viterbi BER (or PER? config dependent?) */ + stats = &c->post_bit_error; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + ret = reg_read(state, 0xeb, val, 10); + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = val[i * 5] << 16 + | val[i * 5 + 1] << 8 | val[i * 5 + 2]; + } + } + stats = &c->post_bit_count; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = + val[i * 5 + 3] << 8 | val[i * 5 + 4]; + stats->stat[i].uvalue *= 204 * 8; + } + } + + return 0; +} + + +static const fe_transmit_mode_t tm_conv[] = { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_4K, + TRANSMISSION_MODE_8K, + 0 +}; + +static const fe_code_rate_t fec_conv_ter[] = { + FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0 +}; + +static const fe_modulation_t mod_conv[] = { + DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0 +}; + +static int tc90522t_get_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + struct dtv_frontend_properties *c; + struct dtv_fe_stats *stats; + int ret, i; + int layers; + u8 val[15], mode; + u32 cndat; + + state = fe->demodulator_priv; + c = &fe->dtv_property_cache; + c->delivery_system = SYS_ISDBT; + c->bandwidth_hz = 6000000; + mode = 1; + ret = reg_read(state, 0xb0, val, 1); + if (ret == 0) { + mode = (val[0] & 0xc0) >> 2; + c->transmission_mode = tm_conv[mode]; + c->guard_interval = (val[0] & 0x30) >> 4; + } + + ret = reg_read(state, 0xb2, val, 6); + layers = 0; + if (ret == 0) { + u8 v; + + c->isdbt_partial_reception = val[0] & 0x01; + c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01; + + /* layer A */ + v = (val[2] & 0x78) >> 3; + if (v == 0x0f) + c->layer[0].segment_count = 0; + else { + layers++; + c->layer[0].segment_count = v; + c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2]; + c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5]; + v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7; + c->layer[0].interleaving = v; + } + + /* layer B */ + v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6; + if (v == 0x0f) + c->layer[1].segment_count = 0; + else { + layers++; + c->layer[1].segment_count = v; + c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5]; + c->layer[1].modulation = mod_conv[(val[2] & 0x07)]; + c->layer[1].interleaving = (val[3] & 0x1c) >> 2; + } + + /* layer C */ + v = (val[5] & 0x1e) >> 1; + if (v == 0x0f) + c->layer[2].segment_count = 0; + else { + layers++; + c->layer[2].segment_count = v; + c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)]; + c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3]; + c->layer[2].interleaving = (val[5] & 0xe0) >> 5; + } + } + + /* statistics */ + + stats = &c->strength; + stats->len = 0; + /* let the connected tuner set RSSI property cache */ + if (fe->ops.tuner_ops.get_rf_strength) { + u16 dummy; + + fe->ops.tuner_ops.get_rf_strength(fe, &dummy); + } + + stats = &c->cnr; + stats->len = 1; + stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + cndat = 0; + ret = reg_read(state, 0x8b, val, 3); + if (ret == 0) + cndat = val[0] << 16 | val[1] << 8 | val[2]; + if (cndat != 0) { + u32 p, tmp; + s64 cn; + + /* + * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5 + * (P = 10log10(5505024/cndat)) + */ + /* cn = cnr << 3 (61.3 fixed point float */ + /* p = 10log10(5505024/cndat) << 24 (8.24 fixed point float)*/ + p = intlog10(5505024) - intlog10(cndat); + p *= 10; + + cn = 24772; + cn += ((43827LL * p) / 10) >> 24; + tmp = p >> 8; + cn += ((3184LL * tmp * tmp) / 10) >> 32; + tmp = p >> 13; + cn -= ((128LL * tmp * tmp * tmp) / 10) >> 33; + tmp = p >> 18; + cn += ((192LL * tmp * tmp * tmp * tmp) / 1000) >> 24; + + stats->stat[0].svalue = cn >> 3; + stats->stat[0].scale = FE_SCALE_DECIBEL; + } + + /* per-layer post viterbi BER (or PER? config dependent?) */ + stats = &c->post_bit_error; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + ret = reg_read(state, 0x9d, val, 15); + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = val[i * 3] << 16 + | val[i * 3 + 1] << 8 | val[i * 3 + 2]; + } + } + stats = &c->post_bit_count; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = + val[9 + i * 2] << 8 | val[9 + i * 2 + 1]; + stats->stat[i].uvalue *= 204 * 8; + } + } + + return 0; +} + +static const struct reg_val reset_sat = { 0x03, 0x01 }; +static const struct reg_val reset_ter = { 0x01, 0x40 }; + +static int tc90522_set_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + state = fe->demodulator_priv; + + if (fe->ops.tuner_ops.set_params) + ret = fe->ops.tuner_ops.set_params(fe); + else + ret = -ENODEV; + if (ret < 0) + goto failed; + + if (fe->ops.delsys[0] == SYS_ISDBS) { + ret = tc90522s_set_tsid(fe); + if (ret < 0) + goto failed; + ret = reg_write(state, &reset_sat, 1); + } else { + ret = tc90522t_set_layers(fe); + if (ret < 0) + goto failed; + ret = reg_write(state, &reset_ter, 1); + } + if (ret < 0) + goto failed; + + return 0; + +failed: + dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static int tc90522_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) +{ + if (fe->ops.delsys[0] == SYS_ISDBS) { + settings->min_delay_ms = 250; + settings->step_size = 1000; + settings->max_drift = settings->step_size * 2; + } else { + settings->min_delay_ms = 400; + settings->step_size = 142857; + settings->max_drift = settings->step_size; + } + return 0; +} + +static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on) +{ + struct reg_val agc_sat[] = { + { 0x0a, 0x00 }, + { 0x10, 0x30 }, + { 0x11, 0x00 }, + { 0x03, 0x01 }, + }; + struct reg_val agc_ter[] = { + { 0x25, 0x00 }, + { 0x23, 0x4c }, + { 0x01, 0x40 }, + }; + struct tc90522_state *state; + struct reg_val *rv; + int num; + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) { + agc_sat[0].val = on ? 0xff : 0x00; + agc_sat[1].val |= 0x80; + agc_sat[1].val |= on ? 0x01 : 0x00; + agc_sat[2].val |= on ? 0x40 : 0x00; + rv = agc_sat; + num = ARRAY_SIZE(agc_sat); + } else { + agc_ter[0].val = on ? 0x40 : 0x00; + agc_ter[1].val |= on ? 0x00 : 0x01; + rv = agc_ter; + num = ARRAY_SIZE(agc_ter); + } + return reg_write(state, rv, num); +} + +static const struct reg_val sleep_sat = { 0x17, 0x01 }; +static const struct reg_val sleep_ter = { 0x03, 0x90 }; + +static int tc90522_sleep(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = reg_write(state, &sleep_sat, 1); + else { + ret = reg_write(state, &sleep_ter, 1); + if (ret == 0 && fe->ops.set_lna && + fe->dtv_property_cache.lna == LNA_AUTO) { + fe->dtv_property_cache.lna = 0; + ret = fe->ops.set_lna(fe); + fe->dtv_property_cache.lna = LNA_AUTO; + } + } + if (ret < 0) + dev_warn(&state->tuner_i2c.dev, + "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static const struct reg_val wakeup_sat = { 0x17, 0x00 }; +static const struct reg_val wakeup_ter = { 0x03, 0x80 }; + +static int tc90522_init(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + /* + * Because the init sequence is not public, + * the parent device/driver should have init'ed the device before. + * just wake up the device here. + */ + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = reg_write(state, &wakeup_sat, 1); + else { + ret = reg_write(state, &wakeup_ter, 1); + if (ret == 0 && fe->ops.set_lna && + fe->dtv_property_cache.lna == LNA_AUTO) { + fe->dtv_property_cache.lna = 1; + ret = fe->ops.set_lna(fe); + fe->dtv_property_cache.lna = LNA_AUTO; + } + } + if (ret < 0) { + dev_warn(&state->tuner_i2c.dev, + "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; + } + + /* prefer 'all-layers' to 'none' as a default */ + if (fe->dtv_property_cache.isdbt_layer_enabled == 0) + fe->dtv_property_cache.isdbt_layer_enabled = 7; + return tc90522_set_if_agc(fe, true); +} + + +/* + * tuner I2C adapter functions + */ + +static int +tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct tc90522_state *state; + struct i2c_msg *new_msgs; + int i, j; + int ret, rd_num; + u8 wbuf[256]; + u8 *p, *bufend; + + if (num <= 0) + return -EINVAL; + + rd_num = 0; + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RD) + rd_num++; + new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL); + if (!new_msgs) + return -ENOMEM; + + state = i2c_get_adapdata(adap); + p = wbuf; + bufend = wbuf + sizeof(wbuf); + for (i = 0, j = 0; i < num; i++, j++) { + new_msgs[j].addr = state->i2c_client->addr; + new_msgs[j].flags = msgs[i].flags; + + if (msgs[i].flags & I2C_M_RD) { + new_msgs[j].flags &= ~I2C_M_RD; + if (p + 2 > bufend) + break; + p[0] = TC90522_I2C_THRU_REG; + p[1] = msgs[i].addr << 1 | 0x01; + new_msgs[j].buf = p; + new_msgs[j].len = 2; + p += 2; + j++; + new_msgs[j].addr = state->i2c_client->addr; + new_msgs[j].flags = msgs[i].flags; + new_msgs[j].buf = msgs[i].buf; + new_msgs[j].len = msgs[i].len; + continue; + } + + if (p + msgs[i].len + 2 > bufend) + break; + p[0] = TC90522_I2C_THRU_REG; + p[1] = msgs[i].addr << 1; + memcpy(p + 2, msgs[i].buf, msgs[i].len); + new_msgs[j].buf = p; + new_msgs[j].len = msgs[i].len + 2; + p += new_msgs[j].len; + } + + if (i < num) + ret = -ENOMEM; + else + ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j); + if (ret >= 0 && ret < j) + ret = -EIO; + kfree(new_msgs); + return (ret == j) ? num : ret; +} + +u32 tc90522_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm tc90522_tuner_i2c_algo = { + .master_xfer = &tc90522_master_xfer, + .functionality = &tc90522_functionality, +}; + + +/* + * I2C driver functions + */ + +static const struct dvb_frontend_ops tc90522_ops_sat = { + .delsys = { SYS_ISDBS }, + .info = { + .name = "Toshiba TC90522 ISDB-S module", + .frequency_min = 950000, + .frequency_max = 2150000, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + }, + + .init = tc90522_init, + .sleep = tc90522_sleep, + .set_frontend = tc90522_set_frontend, + .get_tune_settings = tc90522_get_tune_settings, + + .get_frontend = tc90522s_get_frontend, + .read_status = tc90522s_read_status, +}; + +static const struct dvb_frontend_ops tc90522_ops_ter = { + .delsys = { SYS_ISDBT }, + .info = { + .name = "Toshiba TC90522 ISDB-T module", + .frequency_min = 470000000, + .frequency_max = 770000000, + .frequency_stepsize = 142857, + .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, + }, + + .init = tc90522_init, + .sleep = tc90522_sleep, + .set_frontend = tc90522_set_frontend, + .get_tune_settings = tc90522_get_tune_settings, + + .get_frontend = tc90522t_get_frontend, + .read_status = tc90522t_read_status, +}; + + +static int tc90522_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tc90522_state *state; + struct tc90522_config *cfg; + const struct dvb_frontend_ops *ops; + struct i2c_adapter *adap; + int ret; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->i2c_client = client; + + cfg = client->dev.platform_data; + memcpy(&state->cfg, cfg, sizeof(state->cfg)); + cfg->fe = state->cfg.fe = &state->fe; + ops = id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter; + memcpy(&state->fe.ops, ops, sizeof(*ops)); + state->fe.demodulator_priv = state; + + adap = &state->tuner_i2c; + adap->owner = THIS_MODULE; + adap->algo = &tc90522_tuner_i2c_algo; + adap->dev.parent = &client->dev; + strlcpy(adap->name, "tc90522_sub", sizeof(adap->name)); + i2c_set_adapdata(adap, state); + ret = i2c_add_adapter(adap); + if (ret < 0) + goto err; + cfg->tuner_i2c = state->cfg.tuner_i2c = adap; + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "Toshiba TC90522 attached.\n"); + return 0; + +err: + kfree(state); + return ret; +} + +static int tc90522_remove(struct i2c_client *client) +{ + struct tc90522_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + i2c_del_adapter(&state->tuner_i2c); + kfree(state); + return 0; +} + + +static const struct i2c_device_id tc90522_id[] = { + { TC90522_I2C_DEV_SAT, 0 }, + { TC90522_I2C_DEV_TER, 1 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, tc90522_id); + +static struct i2c_driver tc90522_driver = { + .driver = { + .name = "tc90522", + }, + .probe = tc90522_probe, + .remove = tc90522_remove, + .id_table = tc90522_id, +}; + +module_i2c_driver(tc90522_driver); + +MODULE_DESCRIPTION("Toshiba TC90522 frontend"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h new file mode 100644 index 000000000000..b1cbddfa6ee6 --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.h @@ -0,0 +1,42 @@ +/* + * Toshiba TC90522 Demodulator + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +/* + * The demod has 4 input (2xISDB-T and 2xISDB-S), + * and provides independent sub modules for each input. + * As the sub modules work in parallel and have the separate i2c addr's, + * this driver treats each sub module as one demod device. + */ + +#ifndef TC90522_H +#define TC90522_H + +#include +#include "dvb_frontend.h" + +/* I2C device types */ +#define TC90522_I2C_DEV_SAT "tc90522sat" +#define TC90522_I2C_DEV_TER "tc90522ter" + +struct tc90522_config { + /* [OUT] frontend returned by driver */ + struct dvb_frontend *fe; + + /* [OUT] tuner I2C adapter returned by driver */ + struct i2c_adapter *tuner_i2c; +}; + +#endif /* TC90522_H */ -- cgit v1.2.3 From f5a98f37a535a43b3a27c6a63b07f23d248e4b31 Mon Sep 17 00:00:00 2001 From: Akihiro Tsukada Date: Mon, 8 Sep 2014 14:20:43 -0300 Subject: [media] pt3: add support for Earthsoft PT3 ISDB-S/T receiver card This patch adds support for PT3 PCIe cards. PT3 has an FPGA PCIe bridge chip, a TC90522 demod chip and a VA4M6JC2103 tuner module which contains two QM1D1C0042 chips for ISDB-S and two MxL301RF's for ISDB-T. It can receive and deliver 4 (2x ISDB-S, 2x ISDB-T) streams simultaneously, and a kthread is used per stream to poll incoming data, because PT3 does not have interrupts. As an antenna input for each delivery system is split in the tuner module and shared between the corresponding two tuner chips, LNB/LNA controls that the FPGA chip provides are (naturally) shared as well. The tuner chips also share the power line in the tuner module, which is controlled on/off by a GPIO pin of the demod chip. As with the demod chip and the ISDB-T tuner chip, the init sequences/register settings for those chips are not disclosed and stored in a private memory of the FPGA, PT3 driver executes the init of those chips on behalf of their drivers. Signed-off-by: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/pt3/Kconfig | 10 + drivers/media/pci/pt3/Makefile | 8 + drivers/media/pci/pt3/pt3.c | 877 ++++++++++++++++++++++++++++++++++++++++ drivers/media/pci/pt3/pt3.h | 186 +++++++++ drivers/media/pci/pt3/pt3_dma.c | 225 +++++++++++ drivers/media/pci/pt3/pt3_i2c.c | 240 +++++++++++ 8 files changed, 1548 insertions(+) create mode 100644 drivers/media/pci/pt3/Kconfig create mode 100644 drivers/media/pci/pt3/Makefile create mode 100644 drivers/media/pci/pt3/pt3.c create mode 100644 drivers/media/pci/pt3/pt3.h create mode 100644 drivers/media/pci/pt3/pt3_dma.c create mode 100644 drivers/media/pci/pt3/pt3_i2c.c diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 933280740176..f8cec8e8cf82 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -42,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig" source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/dm1105/Kconfig" source "drivers/media/pci/pt1/Kconfig" +source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/mantis/Kconfig" source "drivers/media/pci/ngene/Kconfig" source "drivers/media/pci/ddbridge/Kconfig" diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 73d9c0f11127..a12926e4b51f 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -7,6 +7,7 @@ obj-y += ttpci/ \ pluto2/ \ dm1105/ \ pt1/ \ + pt3/ \ mantis/ \ ngene/ \ ddbridge/ \ diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig new file mode 100644 index 000000000000..16c208ae0079 --- /dev/null +++ b/drivers/media/pci/pt3/Kconfig @@ -0,0 +1,10 @@ +config DVB_PT3 + tristate "Earthsoft PT3 cards" + depends on DVB_CORE && PCI && I2C + select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT + help + Support for Earthsoft PT3 PCIe cards. + + Say Y or M if you own such a device and want to use it. diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile new file mode 100644 index 000000000000..396f146b1c18 --- /dev/null +++ b/drivers/media/pci/pt3/Makefile @@ -0,0 +1,8 @@ + +earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o + +obj-$(CONFIG_DVB_PT3) += earth-pt3.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c new file mode 100644 index 000000000000..206ede0719b0 --- /dev/null +++ b/drivers/media/pci/pt3/pt3.c @@ -0,0 +1,877 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "pt3.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static bool one_adapter; +module_param(one_adapter, bool, 0444); +MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter."); + +static int num_bufs = 4; +module_param(num_bufs, int, 0444); +MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE."); + + +static const struct i2c_algorithm pt3_i2c_algo = { + .master_xfer = &pt3_i2c_master_xfer, + .functionality = &pt3_i2c_functionality, +}; + +static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = { + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11), + }, + .tuner_info = { + I2C_BOARD_INFO("qm1d1c0042", 0x63), + }, + .tuner_cfg.qm1d1c0042 = { + .lpf = 1, + }, + .init_freq = 1049480 - 300, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10), + }, + .tuner_info = { + I2C_BOARD_INFO("mxl301rf", 0x62), + }, + .init_freq = 515142857, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13), + }, + .tuner_info = { + I2C_BOARD_INFO("qm1d1c0042", 0x60), + }, + .tuner_cfg.qm1d1c0042 = { + .lpf = 1, + }, + .init_freq = 1049480 + 300, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12), + }, + .tuner_info = { + I2C_BOARD_INFO("mxl301rf", 0x61), + }, + .init_freq = 521142857, + }, +}; + + +struct reg_val { + u8 reg; + u8 val; +}; + +static int +pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num) +{ + struct i2c_msg msg; + int i, ret; + + ret = 0; + msg.addr = adap->i2c_demod->addr; + msg.flags = 0; + msg.len = 2; + for (i = 0; i < num; i++) { + msg.buf = (u8 *)&data[i]; + ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1); + if (ret == 0) + ret = -EREMOTE; + if (ret < 0) + return ret; + } + return 0; +} + +static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on) +{ + iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W); +} + +static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe) +{ + struct pt3_board *pt3; + int i; + + if (one_adapter) { + pt3 = fe->dvb->priv; + for (i = 0; i < PT3_NUM_FE; i++) + if (pt3->adaps[i]->fe == fe) + return pt3->adaps[i]; + } + return container_of(fe->dvb, struct pt3_adapter, dvb_adap); +} + +/* + * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103). + * it seems that they share the power lines and Amp power line and + * adaps[3] controls those powers. + */ +static int +pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on) +{ + struct reg_val rv = { 0x1e, 0x99 }; + + if (tuner_on) + rv.val |= 0x40; + if (amp_on) + rv.val |= 0x04; + return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1); +} + +static int pt3_set_lna(struct dvb_frontend *fe) +{ + struct pt3_adapter *adap; + struct pt3_board *pt3; + u32 val; + int ret; + + /* LNA is shared btw. 2 TERR-tuners */ + + adap = pt3_find_adapter(fe); + val = fe->dtv_property_cache.lna; + if (val == LNA_AUTO || val == adap->cur_lna) + return 0; + + pt3 = adap->dvb_adap.priv; + if (mutex_lock_interruptible(&pt3->lock)) + return -ERESTARTSYS; + if (val) + pt3->lna_on_cnt++; + else + pt3->lna_on_cnt--; + + if (val && pt3->lna_on_cnt <= 1) { + pt3->lna_on_cnt = 1; + ret = pt3_set_tuner_power(pt3, true, true); + } else if (!val && pt3->lna_on_cnt <= 0) { + pt3->lna_on_cnt = 0; + ret = pt3_set_tuner_power(pt3, true, false); + } else + ret = 0; + mutex_unlock(&pt3->lock); + adap->cur_lna = (val != 0); + return ret; +} + +static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + struct pt3_adapter *adap; + struct pt3_board *pt3; + bool on; + + /* LNB power is shared btw. 2 SAT-tuners */ + + adap = pt3_find_adapter(fe); + on = (volt != SEC_VOLTAGE_OFF); + if (on == adap->cur_lnb) + return 0; + adap->cur_lnb = on; + pt3 = adap->dvb_adap.priv; + if (mutex_lock_interruptible(&pt3->lock)) + return -ERESTARTSYS; + if (on) + pt3->lnb_on_cnt++; + else + pt3->lnb_on_cnt--; + + if (on && pt3->lnb_on_cnt <= 1) { + pt3->lnb_on_cnt = 1; + pt3_lnb_ctrl(pt3, true); + } else if (!on && pt3->lnb_on_cnt <= 0) { + pt3->lnb_on_cnt = 0; + pt3_lnb_ctrl(pt3, false); + } + mutex_unlock(&pt3->lock); + return 0; +} + +/* register values used in pt3_fe_init() */ + +static const struct reg_val init0_sat[] = { + { 0x03, 0x01 }, + { 0x1e, 0x10 }, +}; +static const struct reg_val init0_ter[] = { + { 0x01, 0x40 }, + { 0x1c, 0x10 }, +}; +static const struct reg_val cfg_sat[] = { + { 0x1c, 0x15 }, + { 0x1f, 0x04 }, +}; +static const struct reg_val cfg_ter[] = { + { 0x1d, 0x01 }, +}; + +/* + * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once. + * + * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF), + * the i2c sequences for init'ing them are not public and hidden in a ROM, + * and include the board specific configurations as well. + * They are stored in a lump and cannot be taken out / accessed separately, + * thus cannot be moved to the FE/tuner driver. + */ +static int pt3_fe_init(struct pt3_board *pt3) +{ + int i, ret; + struct dvb_frontend *fe; + + pt3_i2c_reset(pt3); + ret = pt3_init_all_demods(pt3); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to init demod chips."); + return ret; + } + + /* additional config? */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = pt3_demod_write(pt3->adaps[i], + init0_sat, ARRAY_SIZE(init0_sat)); + else + ret = pt3_demod_write(pt3->adaps[i], + init0_ter, ARRAY_SIZE(init0_ter)); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "demod[%d] faild in init sequence0.", i); + return ret; + } + ret = fe->ops.init(fe); + if (ret < 0) + return ret; + } + + usleep_range(2000, 4000); + ret = pt3_set_tuner_power(pt3, true, false); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to control tuner module."); + return ret; + } + + /* output pin configuration */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = pt3_demod_write(pt3->adaps[i], + cfg_sat, ARRAY_SIZE(cfg_sat)); + else + ret = pt3_demod_write(pt3->adaps[i], + cfg_ter, ARRAY_SIZE(cfg_ter)); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "demod[%d] faild in init sequence1.", i); + return ret; + } + } + usleep_range(4000, 6000); + + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.delsys[0] != SYS_ISDBS) + continue; + /* init and wake-up ISDB-S tuners */ + ret = fe->ops.tuner_ops.init(fe); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "Failed to init SAT-tuner[%d].", i); + return ret; + } + } + ret = pt3_init_all_mxl301rf(pt3); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners."); + return ret; + } + + ret = pt3_set_tuner_power(pt3, true, true); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to control tuner module."); + return ret; + } + + /* Wake up all tuners and make an initial tuning, + * in order to avoid interference among the tuners in the module, + * according to the doc from the manufacturer. + */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + ret = 0; + if (fe->ops.delsys[0] == SYS_ISDBT) + ret = fe->ops.tuner_ops.init(fe); + /* set only when called from pt3_probe(), not resume() */ + if (ret == 0 && fe->dtv_property_cache.frequency == 0) { + fe->dtv_property_cache.frequency = + adap_conf[i].init_freq; + ret = fe->ops.tuner_ops.set_params(fe); + } + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "Failed in initial tuning of tuner[%d].", i); + return ret; + } + } + + /* and sleep again, waiting to be opened by users. */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.tuner_ops.sleep) + ret = fe->ops.tuner_ops.sleep(fe); + if (ret < 0) + break; + if (fe->ops.sleep) + ret = fe->ops.sleep(fe); + if (ret < 0) + break; + if (fe->ops.delsys[0] == SYS_ISDBS) + fe->ops.set_voltage = &pt3_set_voltage; + else + fe->ops.set_lna = &pt3_set_lna; + } + if (i < PT3_NUM_FE) { + dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i); + return ret; + } + return 0; +} + + +static int pt3_attach_fe(struct pt3_board *pt3, int i) +{ + struct i2c_board_info info; + struct tc90522_config cfg; + struct i2c_client *cl; + struct dvb_adapter *dvb_adap; + int ret; + + info = adap_conf[i].demod_info; + cfg = adap_conf[i].demod_cfg; + cfg.tuner_i2c = NULL; + info.platform_data = &cfg; + + ret = -ENODEV; + request_module("tc90522"); + cl = i2c_new_device(&pt3->i2c_adap, &info); + if (!cl || !cl->dev.driver) + return -ENODEV; + pt3->adaps[i]->i2c_demod = cl; + if (!try_module_get(cl->dev.driver->owner)) + goto err_demod; + + if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) { + struct qm1d1c0042_config tcfg; + + tcfg = adap_conf[i].tuner_cfg.qm1d1c0042; + tcfg.fe = cfg.fe; + info = adap_conf[i].tuner_info; + info.platform_data = &tcfg; + request_module("qm1d1c0042"); + cl = i2c_new_device(cfg.tuner_i2c, &info); + } else { + struct mxl301rf_config tcfg; + + tcfg = adap_conf[i].tuner_cfg.mxl301rf; + tcfg.fe = cfg.fe; + info = adap_conf[i].tuner_info; + info.platform_data = &tcfg; + request_module("mxl301rf"); + cl = i2c_new_device(cfg.tuner_i2c, &info); + } + if (!cl || !cl->dev.driver) + goto err_demod; + pt3->adaps[i]->i2c_tuner = cl; + if (!try_module_get(cl->dev.driver->owner)) + goto err_tuner; + + dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; + ret = dvb_register_frontend(dvb_adap, cfg.fe); + if (ret < 0) + goto err_tuner; + pt3->adaps[i]->fe = cfg.fe; + return 0; + +err_tuner: + i2c_unregister_device(pt3->adaps[i]->i2c_tuner); + if (pt3->adaps[i]->i2c_tuner->dev.driver->owner && + module_is_live(pt3->adaps[i]->i2c_tuner->dev.driver->owner)) + module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); +err_demod: + i2c_unregister_device(pt3->adaps[i]->i2c_demod); + if (pt3->adaps[i]->i2c_demod->dev.driver->owner && + module_is_live(pt3->adaps[i]->i2c_demod->dev.driver->owner)) + module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); + return ret; +} + + +static int pt3_fetch_thread(void *data) +{ + struct pt3_adapter *adap = data; + ktime_t delay; + bool was_frozen; + +#define PT3_INITIAL_BUF_DROPS 4 +#define PT3_FETCH_DELAY 10 +#define PT3_FETCH_DELAY_DELTA 2 + + pt3_init_dmabuf(adap); + adap->num_discard = PT3_INITIAL_BUF_DROPS; + + dev_dbg(adap->dvb_adap.device, + "PT3: [%s] started.\n", adap->thread->comm); + set_freezable(); + while (!kthread_freezable_should_stop(&was_frozen)) { + if (was_frozen) + adap->num_discard = PT3_INITIAL_BUF_DROPS; + + pt3_proc_dma(adap); + + delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC); + set_current_state(TASK_UNINTERRUPTIBLE); + freezable_schedule_hrtimeout_range(&delay, + PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC, + HRTIMER_MODE_REL); + } + dev_dbg(adap->dvb_adap.device, + "PT3: [%s] exited.\n", adap->thread->comm); + adap->thread = NULL; + return 0; +} + +static int pt3_start_streaming(struct pt3_adapter *adap) +{ + struct task_struct *thread; + + /* start fetching thread */ + thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i", + adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + if (IS_ERR(thread)) { + int ret = PTR_ERR(thread); + + dev_warn(adap->dvb_adap.device, + "PT3 (adap:%d, dmx:%d): failed to start kthread.\n", + adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + return ret; + } + adap->thread = thread; + + return pt3_start_dma(adap); +} + +static int pt3_stop_streaming(struct pt3_adapter *adap) +{ + int ret; + + ret = pt3_stop_dma(adap); + if (ret) + dev_warn(adap->dvb_adap.device, + "PT3: failed to stop streaming of adap:%d/FE:%d\n", + adap->dvb_adap.num, adap->fe->id); + + /* kill the fetching thread */ + ret = kthread_stop(adap->thread); + return ret; +} + +static int pt3_start_feed(struct dvb_demux_feed *feed) +{ + struct pt3_adapter *adap; + + if (signal_pending(current)) + return -EINTR; + + adap = container_of(feed->demux, struct pt3_adapter, demux); + adap->num_feeds++; + if (adap->thread) + return 0; + if (adap->num_feeds != 1) { + dev_warn(adap->dvb_adap.device, + "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n", + __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + adap->num_feeds = 1; + } + + return pt3_start_streaming(adap); + +} + +static int pt3_stop_feed(struct dvb_demux_feed *feed) +{ + struct pt3_adapter *adap; + + adap = container_of(feed->demux, struct pt3_adapter, demux); + + adap->num_feeds--; + if (adap->num_feeds > 0 || !adap->thread) + return 0; + adap->num_feeds = 0; + + return pt3_stop_streaming(adap); +} + + +static int pt3_alloc_adapter(struct pt3_board *pt3, int index) +{ + int ret; + struct pt3_adapter *adap; + struct dvb_adapter *da; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) { + dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n"); + return -ENOMEM; + } + pt3->adaps[index] = adap; + adap->adap_idx = index; + + if (index == 0 || !one_adapter) { + ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB", + THIS_MODULE, &pt3->pdev->dev, adapter_nr); + if (ret < 0) { + dev_err(&pt3->pdev->dev, + "failed to register adapter dev.\n"); + goto err_mem; + } + da = &adap->dvb_adap; + } else + da = &pt3->adaps[0]->dvb_adap; + + adap->dvb_adap.priv = pt3; + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.feednum = 256; + adap->demux.filternum = 256; + adap->demux.start_feed = pt3_start_feed; + adap->demux.stop_feed = pt3_stop_feed; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n"); + goto err_adap; + } + + adap->dmxdev.filternum = 256; + adap->dmxdev.demux = &adap->demux.dmx; + ret = dvb_dmxdev_init(&adap->dmxdev, da); + if (ret < 0) { + dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n"); + goto err_demux; + } + + ret = pt3_alloc_dmabuf(adap); + if (ret) { + dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n"); + goto err_dmabuf; + } + + return 0; + +err_dmabuf: + pt3_free_dmabuf(adap); + dvb_dmxdev_release(&adap->dmxdev); +err_demux: + dvb_dmx_release(&adap->demux); +err_adap: + if (index == 0 || !one_adapter) + dvb_unregister_adapter(da); +err_mem: + kfree(adap); + pt3->adaps[index] = NULL; + return ret; +} + +static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) +{ + struct pt3_adapter *adap; + struct dmx_demux *dmx; + + adap = pt3->adaps[index]; + if (adap == NULL) + return; + + /* stop demux kthread */ + if (adap->thread) + pt3_stop_streaming(adap); + + dmx = &adap->demux.dmx; + dmx->close(dmx); + if (adap->fe) { + adap->fe->callback = NULL; + if (adap->fe->frontend_priv) + dvb_unregister_frontend(adap->fe); + if (adap->i2c_tuner) { + module_put(adap->i2c_tuner->dev.driver->owner); + i2c_unregister_device(adap->i2c_tuner); + } + if (adap->i2c_demod) { + module_put(adap->i2c_demod->dev.driver->owner); + i2c_unregister_device(adap->i2c_demod); + } + } + pt3_free_dmabuf(adap); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + if (index == 0 || !one_adapter) + dvb_unregister_adapter(&adap->dvb_adap); + kfree(adap); + pt3->adaps[index] = NULL; +} + +#ifdef CONFIG_PM_SLEEP + +static int pt3_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pt3_board *pt3 = pci_get_drvdata(pdev); + int i; + struct pt3_adapter *adap; + + for (i = 0; i < PT3_NUM_FE; i++) { + adap = pt3->adaps[i]; + if (adap->num_feeds > 0) + pt3_stop_dma(adap); + dvb_frontend_suspend(adap->fe); + pt3_free_dmabuf(adap); + } + + pt3_lnb_ctrl(pt3, false); + pt3_set_tuner_power(pt3, false, false); + return 0; +} + +static int pt3_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pt3_board *pt3 = pci_get_drvdata(pdev); + int i, ret; + struct pt3_adapter *adap; + + ret = pt3_fe_init(pt3); + if (ret) + return ret; + + if (pt3->lna_on_cnt > 0) + pt3_set_tuner_power(pt3, true, true); + if (pt3->lnb_on_cnt > 0) + pt3_lnb_ctrl(pt3, true); + + for (i = 0; i < PT3_NUM_FE; i++) { + adap = pt3->adaps[i]; + dvb_frontend_resume(adap->fe); + ret = pt3_alloc_dmabuf(adap); + if (ret) { + dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n"); + continue; + } + if (adap->num_feeds > 0) + pt3_start_dma(adap); + } + + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + + +static void pt3_remove(struct pci_dev *pdev) +{ + struct pt3_board *pt3; + int i; + + pt3 = pci_get_drvdata(pdev); + for (i = PT3_NUM_FE - 1; i >= 0; i--) + pt3_cleanup_adapter(pt3, i); + i2c_del_adapter(&pt3->i2c_adap); + kfree(pt3->i2c_buf); + pci_iounmap(pt3->pdev, pt3->regs[0]); + pci_iounmap(pt3->pdev, pt3->regs[1]); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(pt3); +} + +static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 rev; + u32 ver; + int i, ret; + struct pt3_board *pt3; + struct i2c_adapter *i2c; + + if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1) + return -ENODEV; + + ret = pci_enable_device(pdev); + if (ret < 0) + return -ENODEV; + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_disable_device; + + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + if (ret == 0) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + else { + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret == 0) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + else { + dev_err(&pdev->dev, "Failed to set DMA mask.\n"); + goto err_release_regions; + } + dev_info(&pdev->dev, "Use 32bit DMA.\n"); + } + + pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL); + if (!pt3) { + dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n"); + ret = -ENOMEM; + goto err_release_regions; + } + pci_set_drvdata(pdev, pt3); + pt3->pdev = pdev; + mutex_init(&pt3->lock); + pt3->regs[0] = pci_ioremap_bar(pdev, 0); + pt3->regs[1] = pci_ioremap_bar(pdev, 2); + if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) { + dev_err(&pdev->dev, "Failed to ioremap.\n"); + ret = -ENOMEM; + goto err_kfree; + } + + ver = ioread32(pt3->regs[0] + REG_VERSION); + if ((ver >> 16) != 0x0301) { + dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported", + ver >> 24, (ver & 0x00ff0000) >> 16); + ret = -ENODEV; + goto err_iounmap; + } + + pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS); + + pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL); + if (pt3->i2c_buf == NULL) { + dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n"); + ret = -ENOMEM; + goto err_iounmap; + } + i2c = &pt3->i2c_adap; + i2c->owner = THIS_MODULE; + i2c->algo = &pt3_i2c_algo; + i2c->algo_data = NULL; + i2c->dev.parent = &pdev->dev; + strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name)); + i2c_set_adapdata(i2c, pt3); + ret = i2c_add_adapter(i2c); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to add i2c adapter.\n"); + goto err_i2cbuf; + } + + for (i = 0; i < PT3_NUM_FE; i++) { + ret = pt3_alloc_adapter(pt3, i); + if (ret < 0) + break; + + ret = pt3_attach_fe(pt3, i); + if (ret < 0) + break; + } + if (i < PT3_NUM_FE) { + dev_err(&pdev->dev, "Failed to create FE%d.\n", i); + goto err_cleanup_adapters; + } + + ret = pt3_fe_init(pt3); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to init frontends.\n"); + i = PT3_NUM_FE - 1; + goto err_cleanup_adapters; + } + + dev_info(&pdev->dev, + "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n", + ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff); + return 0; + +err_cleanup_adapters: + while (i >= 0) + pt3_cleanup_adapter(pt3, i--); + i2c_del_adapter(i2c); +err_i2cbuf: + kfree(pt3->i2c_buf); +err_iounmap: + if (pt3->regs[0]) + pci_iounmap(pdev, pt3->regs[0]); + if (pt3->regs[1]) + pci_iounmap(pdev, pt3->regs[1]); +err_kfree: + kfree(pt3); +err_release_regions: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); + return ret; + +} + +static const struct pci_device_id pt3_id_table[] = { + { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) }, + { }, +}; +MODULE_DEVICE_TABLE(pci, pt3_id_table); + +SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); + +static struct pci_driver pt3_driver = { + .name = DRV_NAME, + .probe = pt3_probe, + .remove = pt3_remove, + .id_table = pt3_id_table, + + .driver.pm = &pt3_pm_ops, +}; + +module_pci_driver(pt3_driver); + +MODULE_DESCRIPTION("Earthsoft PT3 Driver"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h new file mode 100644 index 000000000000..1b3f2ad25db3 --- /dev/null +++ b/drivers/media/pci/pt3/pt3.h @@ -0,0 +1,186 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ + +#ifndef PT3_H +#define PT3_H + +#include +#include + +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dmxdev.h" + +#include "tc90522.h" +#include "mxl301rf.h" +#include "qm1d1c0042.h" + +#define DRV_NAME KBUILD_MODNAME + +#define PT3_NUM_FE 4 + +/* + * register index of the FPGA chip + */ +#define REG_VERSION 0x00 +#define REG_BUS 0x04 +#define REG_SYSTEM_W 0x08 +#define REG_SYSTEM_R 0x0c +#define REG_I2C_W 0x10 +#define REG_I2C_R 0x14 +#define REG_RAM_W 0x18 +#define REG_RAM_R 0x1c +#define REG_DMA_BASE 0x40 /* regs for FE[i] = REG_DMA_BASE + 0x18 * i */ +#define OFST_DMA_DESC_L 0x00 +#define OFST_DMA_DESC_H 0x04 +#define OFST_DMA_CTL 0x08 +#define OFST_TS_CTL 0x0c +#define OFST_STATUS 0x10 +#define OFST_TS_ERR 0x14 + +/* + * internal buffer for I2C + */ +#define PT3_I2C_MAX 4091 +struct pt3_i2cbuf { + u8 data[PT3_I2C_MAX]; + u8 tmp; + u32 num_cmds; +}; + +/* + * DMA things + */ +#define TS_PACKET_SZ 188 +/* DMA transfers must not cross 4GiB, so use one page / transfer */ +#define DATA_XFER_SZ 4096 +#define DATA_BUF_XFERS 47 +/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */ +#define DATA_BUF_SZ (DATA_BUF_XFERS * DATA_XFER_SZ) +#define MAX_DATA_BUFS 16 +#define MIN_DATA_BUFS 2 + +#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc)) +#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS) +#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE) + +/* DMA transfer description. + * device is passed a pointer to this struct, dma-reads it, + * and gets the DMA buffer ring for storing TS data. + */ +struct xfer_desc { + u32 addr_l; /* bus address of target data buffer */ + u32 addr_h; + u32 size; + u32 next_l; /* bus adddress of the next xfer_desc */ + u32 next_h; +}; + +/* A DMA mapping of a page containing xfer_desc's */ +struct xfer_desc_buffer { + dma_addr_t b_addr; + struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */ +}; + +/* A DMA mapping of a data buffer */ +struct dma_data_buffer { + dma_addr_t b_addr; + u8 *data; /* size: u8[PAGE_SIZE] */ +}; + +/* + * device things + */ +struct pt3_adap_config { + struct i2c_board_info demod_info; + struct tc90522_config demod_cfg; + + struct i2c_board_info tuner_info; + union tuner_config { + struct qm1d1c0042_config qm1d1c0042; + struct mxl301rf_config mxl301rf; + } tuner_cfg; + u32 init_freq; +}; + +struct pt3_adapter { + struct dvb_adapter dvb_adap; /* dvb_adap.priv => struct pt3_board */ + int adap_idx; + + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend *fe; + struct i2c_client *i2c_demod; + struct i2c_client *i2c_tuner; + + /* data fetch thread */ + struct task_struct *thread; + int num_feeds; + + bool cur_lna; + bool cur_lnb; /* current LNB power status (on/off) */ + + /* items below are for DMA */ + struct dma_data_buffer buffer[MAX_DATA_BUFS]; + int buf_idx; + int buf_ofs; + int num_bufs; /* == pt3_board->num_bufs */ + int num_discard; /* how many access units to discard initially */ + + struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS]; + int num_desc_bufs; /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */ +}; + + +struct pt3_board { + struct pci_dev *pdev; + void __iomem *regs[2]; + /* regs[0]: registers, regs[1]: internal memory, used for I2C */ + + struct mutex lock; + + /* LNB power shared among sat-FEs */ + int lnb_on_cnt; /* LNB power on count */ + + /* LNA shared among terr-FEs */ + int lna_on_cnt; /* booster enabled count */ + + int num_bufs; /* number of DMA buffers allocated/mapped per FE */ + + struct i2c_adapter i2c_adap; + struct pt3_i2cbuf *i2c_buf; + + struct pt3_adapter *adaps[PT3_NUM_FE]; +}; + + +/* + * prototypes + */ +extern int pt3_alloc_dmabuf(struct pt3_adapter *adap); +extern void pt3_init_dmabuf(struct pt3_adapter *adap); +extern void pt3_free_dmabuf(struct pt3_adapter *adap); +extern int pt3_start_dma(struct pt3_adapter *adap); +extern int pt3_stop_dma(struct pt3_adapter *adap); +extern int pt3_proc_dma(struct pt3_adapter *adap); + +extern int pt3_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num); +extern u32 pt3_i2c_functionality(struct i2c_adapter *adap); +extern void pt3_i2c_reset(struct pt3_board *pt3); +extern int pt3_init_all_demods(struct pt3_board *pt3); +extern int pt3_init_all_mxl301rf(struct pt3_board *pt3); +#endif /* PT3_H */ diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c new file mode 100644 index 000000000000..f0ce90437fac --- /dev/null +++ b/drivers/media/pci/pt3/pt3_dma.c @@ -0,0 +1,225 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ +#include +#include +#include + +#include "pt3.h" + +#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128) +#define PT3_BUF_CANARY (0x74) + +static u32 get_dma_base(int idx) +{ + int i; + + i = (idx == 1 || idx == 2) ? 3 - idx : idx; + return REG_DMA_BASE + 0x18 * i; +} + +int pt3_stop_dma(struct pt3_adapter *adap) +{ + struct pt3_board *pt3 = adap->dvb_adap.priv; + u32 base; + u32 stat; + int retry; + + base = get_dma_base(adap->adap_idx); + stat = ioread32(pt3->regs[0] + base + OFST_STATUS); + if (!(stat & 0x01)) + return 0; + + iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); + for (retry = 0; retry < 5; retry++) { + stat = ioread32(pt3->regs[0] + base + OFST_STATUS); + if (!(stat & 0x01)) + return 0; + msleep(50); + } + return -EIO; +} + +int pt3_start_dma(struct pt3_adapter *adap) +{ + struct pt3_board *pt3 = adap->dvb_adap.priv; + u32 base = get_dma_base(adap->adap_idx); + + iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); + iowrite32(lower_32_bits(adap->desc_buf[0].b_addr), + pt3->regs[0] + base + OFST_DMA_DESC_L); + iowrite32(upper_32_bits(adap->desc_buf[0].b_addr), + pt3->regs[0] + base + OFST_DMA_DESC_H); + iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL); + return 0; +} + + +static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs) +{ + *ofs += PT3_ACCESS_UNIT; + if (*ofs >= DATA_BUF_SZ) { + *ofs -= DATA_BUF_SZ; + (*idx)++; + if (*idx == adap->num_bufs) + *idx = 0; + } + return &adap->buffer[*idx].data[*ofs]; +} + +int pt3_proc_dma(struct pt3_adapter *adap) +{ + int idx, ofs; + + idx = adap->buf_idx; + ofs = adap->buf_ofs; + + if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY) + return 0; + + while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) { + u8 *p; + + p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs]; + if (adap->num_discard > 0) + adap->num_discard--; + else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) { + dvb_dmx_swfilter_packets(&adap->demux, p, + (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ); + dvb_dmx_swfilter_packets(&adap->demux, + adap->buffer[idx].data, ofs / TS_PACKET_SZ); + } else + dvb_dmx_swfilter_packets(&adap->demux, p, + PT3_ACCESS_UNIT / TS_PACKET_SZ); + + *p = PT3_BUF_CANARY; + adap->buf_idx = idx; + adap->buf_ofs = ofs; + } + return 0; +} + +void pt3_init_dmabuf(struct pt3_adapter *adap) +{ + int idx, ofs; + u8 *p; + + idx = 0; + ofs = 0; + p = adap->buffer[0].data; + /* mark the whole buffers as "not written yet" */ + while (idx < adap->num_bufs) { + p[ofs] = PT3_BUF_CANARY; + ofs += PT3_ACCESS_UNIT; + if (ofs >= DATA_BUF_SZ) { + ofs -= DATA_BUF_SZ; + idx++; + p = adap->buffer[idx].data; + } + } + adap->buf_idx = 0; + adap->buf_ofs = 0; +} + +void pt3_free_dmabuf(struct pt3_adapter *adap) +{ + struct pt3_board *pt3; + int i; + + pt3 = adap->dvb_adap.priv; + for (i = 0; i < adap->num_bufs; i++) + dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ, + adap->buffer[i].data, adap->buffer[i].b_addr); + adap->num_bufs = 0; + + for (i = 0; i < adap->num_desc_bufs; i++) + dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE, + adap->desc_buf[i].descs, adap->desc_buf[i].b_addr); + adap->num_desc_bufs = 0; +} + + +int pt3_alloc_dmabuf(struct pt3_adapter *adap) +{ + struct pt3_board *pt3; + void *p; + int i, j; + int idx, ofs; + int num_desc_bufs; + dma_addr_t data_addr, desc_addr; + struct xfer_desc *d; + + pt3 = adap->dvb_adap.priv; + adap->num_bufs = 0; + adap->num_desc_bufs = 0; + for (i = 0; i < pt3->num_bufs; i++) { + p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ, + &adap->buffer[i].b_addr, GFP_KERNEL); + if (p == NULL) + goto failed; + adap->buffer[i].data = p; + adap->num_bufs++; + } + pt3_init_dmabuf(adap); + + /* build circular-linked pointers (xfer_desc) to the data buffers*/ + idx = 0; + ofs = 0; + num_desc_bufs = + DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE); + for (i = 0; i < num_desc_bufs; i++) { + p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE, + &desc_addr, GFP_KERNEL); + if (p == NULL) + goto failed; + adap->num_desc_bufs++; + adap->desc_buf[i].descs = p; + adap->desc_buf[i].b_addr = desc_addr; + + if (i > 0) { + d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1]; + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + } + for (j = 0; j < DESCS_IN_PAGE; j++) { + data_addr = adap->buffer[idx].b_addr + ofs; + d = &adap->desc_buf[i].descs[j]; + d->addr_l = lower_32_bits(data_addr); + d->addr_h = upper_32_bits(data_addr); + d->size = DATA_XFER_SZ; + + desc_addr += sizeof(struct xfer_desc); + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + + ofs += DATA_XFER_SZ; + if (ofs >= DATA_BUF_SZ) { + ofs -= DATA_BUF_SZ; + idx++; + if (idx >= adap->num_bufs) { + desc_addr = adap->desc_buf[0].b_addr; + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + return 0; + } + } + } + } + return 0; + +failed: + pt3_free_dmabuf(adap); + return -ENOMEM; +} diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c new file mode 100644 index 000000000000..ec6a8a2e4744 --- /dev/null +++ b/drivers/media/pci/pt3/pt3_i2c.c @@ -0,0 +1,240 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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. + */ +#include +#include +#include +#include +#include + +#include "pt3.h" + +#define PT3_I2C_BASE 2048 +#define PT3_CMD_ADDR_NORMAL 0 +#define PT3_CMD_ADDR_INIT_DEMOD 4096 +#define PT3_CMD_ADDR_INIT_TUNER (4096 + 2042) + +/* masks for I2C status register */ +#define STAT_SEQ_RUNNING 0x1 +#define STAT_SEQ_ERROR 0x6 +#define STAT_NO_SEQ 0x8 + +#define PT3_I2C_RUN (1 << 16) +#define PT3_I2C_RESET (1 << 17) + +enum ctl_cmd { + I_END, + I_ADDRESS, + I_CLOCK_L, + I_CLOCK_H, + I_DATA_L, + I_DATA_H, + I_RESET, + I_SLEEP, + I_DATA_L_NOP = 0x08, + I_DATA_H_NOP = 0x0c, + I_DATA_H_READ = 0x0d, + I_DATA_H_ACK0 = 0x0e, + I_DATA_H_ACK1 = 0x0f, +}; + + +static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd) +{ + int buf_idx; + + if ((cbuf->num_cmds % 2) == 0) + cbuf->tmp = cmd; + else { + cbuf->tmp |= cmd << 4; + buf_idx = cbuf->num_cmds / 2; + if (buf_idx < ARRAY_SIZE(cbuf->data)) + cbuf->data[buf_idx] = cbuf->tmp; + } + cbuf->num_cmds++; +} + +static void put_end(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_END); + if (cbuf->num_cmds % 2) + cmdbuf_add(cbuf, I_END); +} + +static void put_start(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_DATA_H); + cmdbuf_add(cbuf, I_CLOCK_H); + cmdbuf_add(cbuf, I_DATA_L); + cmdbuf_add(cbuf, I_CLOCK_L); +} + +static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val) +{ + u8 mask; + + mask = 0x80; + for (mask = 0x80; mask > 0; mask >>= 1) + cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP); + cmdbuf_add(cbuf, I_DATA_H_ACK0); +} + +static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size) +{ + int i, j; + + for (i = 0; i < size; i++) { + for (j = 0; j < 8; j++) + cmdbuf_add(cbuf, I_DATA_H_READ); + cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP); + } +} + +static void put_stop(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_DATA_L); + cmdbuf_add(cbuf, I_CLOCK_H); + cmdbuf_add(cbuf, I_DATA_H); +} + + +/* translates msgs to internal commands for bit-banging */ +static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num) +{ + int i, j; + bool rd; + + cbuf->num_cmds = 0; + for (i = 0; i < num; i++) { + rd = !!(msgs[i].flags & I2C_M_RD); + put_start(cbuf); + put_byte_write(cbuf, msgs[i].addr << 1 | rd); + if (rd) + put_byte_read(cbuf, msgs[i].len); + else + for (j = 0; j < msgs[i].len; j++) + put_byte_write(cbuf, msgs[i].buf[j]); + } + if (num > 0) { + put_stop(cbuf); + put_end(cbuf); + } +} + +static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait) +{ + int i; + u32 v; + + for (i = 0; i < max_wait; i++) { + v = ioread32(pt3->regs[0] + REG_I2C_R); + if (!(v & STAT_SEQ_RUNNING)) + break; + usleep_range(500, 750); + } + if (i >= max_wait) + return -EIO; + if (result) + *result = v; + return 0; +} + +/* send [pre-]translated i2c msgs stored at addr */ +static int send_i2c_cmd(struct pt3_board *pt3, u32 addr) +{ + u32 ret; + + /* make sure that previous transactions had finished */ + if (wait_i2c_result(pt3, NULL, 50)) { + dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n", + __func__); + return -EIO; + } + + iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W); + usleep_range(200, 300); + /* wait for the current transaction to finish */ + if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) { + dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__); + return -EIO; + } + return 0; +} + + +/* init commands for each demod are combined into one transaction + * and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD. + */ +int pt3_init_all_demods(struct pt3_board *pt3) +{ + ioread32(pt3->regs[0] + REG_I2C_R); + return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD); +} + +/* init commands for two ISDB-T tuners are hidden in ROM. */ +int pt3_init_all_mxl301rf(struct pt3_board *pt3) +{ + usleep_range(1000, 2000); + return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER); +} + +void pt3_i2c_reset(struct pt3_board *pt3) +{ + iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W); +} + +/* + * I2C algorithm + */ +int +pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct pt3_board *pt3; + struct pt3_i2cbuf *cbuf; + int i; + void __iomem *p; + + pt3 = i2c_get_adapdata(adap); + cbuf = pt3->i2c_buf; + + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RECV_LEN) { + dev_warn(&pt3->pdev->dev, + "(%s) I2C_M_RECV_LEN not supported.\n", + __func__); + return -EINVAL; + } + + translate(cbuf, msgs, num); + memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2, + cbuf->data, cbuf->num_cmds); + + if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0) + return -EIO; + + p = pt3->regs[1] + PT3_I2C_BASE; + for (i = 0; i < num; i++) + if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) { + memcpy_fromio(msgs[i].buf, p, msgs[i].len); + p += msgs[i].len; + } + + return num; +} + +u32 pt3_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} -- cgit v1.2.3 From 70dc53633760de48b2d244da8a7b477c628eee05 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 17:01:02 -0300 Subject: [media] tc90522: declare tc90522_functionality as static drivers/media/dvb-frontends/tc90522.c:706:5: warning: symbol 'tc90522_functionality' was not declared. Should it be static? drivers/media/dvb-frontends/tc90522.c:706:5: warning: no previous prototype for 'tc90522_functionality' [-Wmissing-prototypes] u32 tc90522_functionality(struct i2c_adapter *adap) ^ Cc: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/tc90522.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index f4760dd998c3..cdd9808c322c 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -703,7 +703,7 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) return (ret == j) ? num : ret; } -u32 tc90522_functionality(struct i2c_adapter *adap) +static u32 tc90522_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C; } -- cgit v1.2.3 From 49310ed0ab8da344dece4a543bfcdd14490ccfa0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 17:05:02 -0300 Subject: [media] pt3: make pt3_pm_ops() static drivers/media/pci/pt3/pt3.c:862:1: warning: symbol 'pt3_pm_ops' was not declared. Should it be static? Cc: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pt3/pt3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 206ede0719b0..90f86ce7a001 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -859,7 +859,7 @@ static const struct pci_device_id pt3_id_table[] = { }; MODULE_DEVICE_TABLE(pci, pt3_id_table); -SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); +static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); static struct pci_driver pt3_driver = { .name = DRV_NAME, -- cgit v1.2.3 From b0b12e63f999c91690f3f95bd585cf7812a251d9 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:13 -0300 Subject: [media] cx23885: add i2c client handling into dvb_unregister and state Prepare cx23885 driver for handling I2C client that is needed for certain demodulators and tuners (for example Si2168 and Si2157). I2C client for tuner and demod stored in state and unregistering of the I2C devices added into dvb_unregister. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 23 ++++++++++++++++------- drivers/media/pci/cx23885/cx23885.h | 3 +++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 332e6facc095..3e72c95a1d59 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1688,15 +1688,24 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { struct vb2_dvb_frontend *fe0; + struct i2c_client *client; + + /* remove I2C client for tuner */ + client = port->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = port->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } - /* FIXME: in an error condition where the we have - * an expected number of frontends (attach problem) - * then this might not clean up correctly, if 1 - * is invalid. - * This comment only applies to future boards IF they - * implement MFE support. - */ fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + if (fe0 && fe0->dvb.frontend) vb2_dvb_unregister_bus(&port->frontends); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 39a89855d1d5..458d180cf96d 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -293,6 +293,9 @@ struct cx23885_tsport { /* Workaround for a temp dvb_frontend that the tuner can attached to */ struct dvb_frontend analog_fe; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + int (*set_frontend)(struct dvb_frontend *fe); }; -- cgit v1.2.3 From 5cd3b6b40d3a08394a9e973c597a284153eac0b5 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:14 -0300 Subject: [media] cx23855: add frontend set voltage function into state Setting the LNB voltage requires setting some GPIOs on the cx23885 with some boards before calling the actual set_voltage function in the demod driver. Add a function pointer into state for that case. Signed-off-by: Olli Salonen Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 458d180cf96d..0d5888214fb6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -297,6 +297,8 @@ struct cx23885_tsport { struct i2c_client *i2c_client_tuner; int (*set_frontend)(struct dvb_frontend *fe); + int (*fe_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); }; struct cx23885_kernel_ir { -- cgit v1.2.3 From 294422662215188ace50ae14318ac025a56843d8 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:15 -0300 Subject: [media] cx23855: add support for DVBSky T9580 DVB-C/T2/S2 tuner DVBSky T9580 is a dual tuner card with one DVB-T2/C tuner and one DVB-S2 tuner. It contains the following components: - PCIe bridge: Conexant CX23885 - Demod for terrestrial/cable: Silicon Labs Si2168-A30 - Tuner for terrestrial/cable: Silicon Labs Si2158-A20 - Demod for sat: Montage DS3103 - Tuner for sat: Montage TS2022 This patch depends on Max Nibble's patch for m88ds3103 (see patchwork 25312: https://patchwork.linuxtv.org/patch/25312/ ). 3 firmwares are needed: - Si2168-A30 demod and Si2158-A20 tuner: same as TechnoTrend CT2-4400, https://www.mail-archive.com/linux-media@vger.kernel.org/msg76944.html - Montage DS3103 demod: same as PCTV 461e, Antti has it on his LinuxTV project page: http://palosaari.fi/linux/v4l-dvb/firmware/M88DS3103/ IR receiver is not supported. Values in cx23885_gpio_setup, cx23885_card_setup and dvbsky_t9580_set_voltage as well as the EEPROM read function are taken from the manufacturer provided semi-open source driver. The drivers in question are Linux GPL'd media tree drivers for cx23885 modified by Max Nibble (nibble.max@gmail.com) with proprietary tuner/demod drivers. Max is aware of this patch and has approved my use of the values in this patch. Signed-off-by: Olli Salonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 4 + drivers/media/pci/cx23885/cx23885-cards.c | 26 +++++ drivers/media/pci/cx23885/cx23885-dvb.c | 160 ++++++++++++++++++++++++++++++ drivers/media/pci/cx23885/cx23885.h | 1 + 4 files changed, 191 insertions(+) diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index a883ea4968be..f613314b360b 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -31,12 +31,16 @@ config VIDEO_CX23885 select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 21e500b0a220..88c257d1161b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -675,6 +675,11 @@ struct cx23885_board cx23885_boards[] = { .amux = CX25840_AUDIO7, } }, }, + [CX23885_BOARD_DVBSKY_T9580] = { + .name = "DVBSky T9580", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -930,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdb98, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2, + }, { + .subvendor = 0x4254, + .subdevice = 0x9580, + .card = CX23885_BOARD_DVBSKY_T9580, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1524,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x00040004); mdelay(60); break; + case CX23885_BOARD_DVBSKY_T9580: + /* enable GPIO3-18 pins */ + cx_write(MC417_CTL, 0x00000037); + cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1); + cx23885_gpio_clear(dev, GPIO_2 | GPIO_11); + mdelay(100); + cx23885_gpio_set(dev, GPIO_2 | GPIO_11); + break; } } @@ -1847,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_DVBSKY_T9580: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0x8; /* Serial bus */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: @@ -1909,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_AVERMEDIA_HC81R: case CX23885_BOARD_TBS_6980: case CX23885_BOARD_TBS_6981: + case CX23885_BOARD_DVBSKY_T9580: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 3e72c95a1d59..13734b8c7917 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -69,6 +69,10 @@ #include "a8293.h" #include "mb86a20s.h" #include "si2165.h" +#include "si2168.h" +#include "si2157.h" +#include "m88ds3103.h" +#include "m88ts2022.h" static unsigned int debug; @@ -583,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); + + switch (voltage) { + case SEC_VOLTAGE_13: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + case SEC_VOLTAGE_18: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_set(dev, GPIO_0); + break; + case SEC_VOLTAGE_OFF: + cx23885_gpio_clear(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + } + + /* call the frontend set_voltage function */ + port->fe_set_voltage(fe, voltage); + + return 0; +} + static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; @@ -747,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = { .ref_freq_Hz = 16000000, }; +static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .lnb_en_pol = 1, + .lnb_hv_pol = 0, + .agc = 0x99, +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -896,6 +942,13 @@ static int dvb_register(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; struct vb2_dvb_frontend *fe0, *fe1 = NULL; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + struct m88ts2022_config m88ts2022_config; + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; int mfe_shared = 0; /* bus not shared by default */ int ret; @@ -1533,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_DVBSKY_T9580: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + switch (port->nr) { + /* port b - satellite */ + case 1: + /* attach frontend */ + fe0->dvb.frontend = dvb_attach(m88ds3103_attach, + &dvbsky_t9580_m88ds3103_config, + &i2c_bus2->i2c_adap, &adapter); + if (fe0->dvb.frontend == NULL) + break; + + /* attach tuner */ + m88ts2022_config.fe = fe0->dvb.frontend; + m88ts2022_config.clock = 27000000; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &m88ts2022_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + goto frontend_detach; + } + + /* delegate signal strength measurement to tuner */ + fe0->dvb.frontend->ops.read_signal_strength = + fe0->dvb.frontend->ops.tuner_ops.get_rf_strength; + + /* + * for setting the voltage we need to set GPIOs on + * the card. + */ + port->fe_set_voltage = + fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = + dvbsky_t9580_set_voltage; + + port->i2c_client_tuner = client_tuner; + + break; + /* port c - terrestrial/cable */ + case 2: + /* attach frontend */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &fe0->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (client_demod == NULL || + client_demod->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + si2157_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1607,6 +1751,22 @@ static int dvb_register(struct cx23885_tsport *port) memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); break; } + case CX23885_BOARD_DVBSKY_T9580: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr > 2) + break; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n", + port->nr, eeprom + 0xc0 + (port->nr-1) * 8); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + + (port->nr-1) * 8, 6); + break; + } } return ret; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0d5888214fb6..6c35e6115969 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -92,6 +92,7 @@ #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44 +#define CX23885_BOARD_DVBSKY_T9580 45 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v1.2.3 From 5dcf5bf6d9dd81cdf66aab94f62bee354a7d1238 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Sun, 21 Sep 2014 07:53:18 -0300 Subject: [media] af9035: Add possibility to define which I2C adapter to use Some I2C tuner drivers require that the I2C device of the tuner is added to the I2C adapter of the demodulator (Si2168+Si2157 for example). Add possibility to tell af9035_add_i2c_dev which I2C adapter should be used. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 440ecb459b9c..c50d27d4a57f 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -194,12 +194,11 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val, } static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr, - void *platform_data) + void *platform_data, struct i2c_adapter *adapter) { int ret, num; struct state *state = d_to_priv(d); struct i2c_client *client; - struct i2c_adapter *adapter = &d->i2c_adap; struct i2c_board_info board_info = { .addr = addr, .platform_data = platform_data, @@ -1091,7 +1090,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) state->af9033_config[adap->id].fe = &adap->fe[0]; state->af9033_config[adap->id].ops = &state->ops; ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id], - &state->af9033_config[adap->id]); + &state->af9033_config[adap->id], &d->i2c_adap); if (ret) goto err; @@ -1382,7 +1381,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) ret = af9035_add_i2c_dev(d, "it913x", state->af9033_i2c_addr[adap->id] >> 1, - &it913x_config); + &it913x_config, &d->i2c_adap); if (ret) goto err; @@ -1407,7 +1406,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) ret = af9035_add_i2c_dev(d, "it913x", state->af9033_i2c_addr[adap->id] >> 1, - &it913x_config); + &it913x_config, &d->i2c_adap); if (ret) goto err; -- cgit v1.2.3 From 5b5560842a7ee002d208a20866f88fafd63198eb Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Sun, 21 Sep 2014 07:53:19 -0300 Subject: [media] af9035: Add support for IT930x USB bridge Add support for IT930x USB bridge and IT9303 reference design. It is a DVB-T/T2/C tuner with the following components: - IT9303 USB bridge - Si2168-B40 demodulator - Si2147-A30 tuner The IT9303 requires firmware that can be downloaded here: http://trsqr.net/olli/linux/firmwares/it930x/ The Si2168-B40 requires firmware, but the one that is used by PCTV 292e can be used. http://palosaari.fi/linux/v4l-dvb/firmware/Si2168/Si2168-B40/ The Si2147-A30 tuner does not require firmware loading. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb-usb-ids.h | 1 + drivers/media/usb/dvb-usb-v2/af9035.c | 324 ++++++++++++++++++++++++++++++++-- drivers/media/usb/dvb-usb-v2/af9035.h | 6 + 3 files changed, 314 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index d484a5158496..e07a84e7bc56 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -144,6 +144,7 @@ #define USB_PID_ITETECH_IT9135 0x9135 #define USB_PID_ITETECH_IT9135_9005 0x9005 #define USB_PID_ITETECH_IT9135_9006 0x9006 +#define USB_PID_ITETECH_IT9303 0x9306 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index c50d27d4a57f..00758c83eec7 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -290,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, return -EAGAIN; /* - * I2C sub header is 5 bytes long. Meaning of those bytes are: + * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are: * 0: data len * 1: I2C addr << 1 * 2: reg addr len @@ -317,6 +317,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, * bus. I2C subsystem does not allow register multiple devices to same * bus, having same slave address. Due to that we reuse demod address, * shifted by one bit, on that case. + * + * For IT930x we use a different command and the sub header is + * different as well: + * 0: data len + * 1: I2C bus (0x03 seems to be only value used) + * 2: I2C addr << 1 */ #define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \ (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD)) @@ -348,13 +354,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len, buf, msg[1].len, msg[1].buf }; + if (state->chip_type == 0x9306) { + req.cmd = CMD_GENERIC_I2C_RD; + req.wlen = 3 + msg[0].len; + } req.mbox |= ((msg[0].addr & 0x80) >> 3); + buf[0] = msg[1].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); + if (state->chip_type == 0x9306) { + buf[1] = 0x03; /* I2C bus */ + buf[2] = msg[0].addr << 1; + memcpy(&buf[3], msg[0].buf, msg[0].len); + } else { + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + } ret = af9035_ctrl_msg(d, &req); } } else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) { @@ -380,13 +397,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len, buf, 0, NULL }; + if (state->chip_type == 0x9306) { + req.cmd = CMD_GENERIC_I2C_WR; + req.wlen = 3 + msg[0].len; + } + req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[0].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ - memcpy(&buf[5], msg[0].buf, msg[0].len); + if (state->chip_type == 0x9306) { + buf[1] = 0x03; /* I2C bus */ + buf[2] = msg[0].addr << 1; + memcpy(&buf[3], msg[0].buf, msg[0].len); + } else { + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + memcpy(&buf[5], msg[0].buf, msg[0].len); + } ret = af9035_ctrl_msg(d, &req); } } else if (AF9035_IS_I2C_XFER_READ(msg, num)) { @@ -397,13 +425,23 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, /* I2C read */ u8 buf[5]; struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), - buf, msg[0].len, msg[0].buf }; + buf, msg[0].len, msg[0].buf }; + + if (state->chip_type == 0x9306) { + req.cmd = CMD_GENERIC_I2C_RD; + req.wlen = 3; + } req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[0].len; - buf[1] = msg[0].addr << 1; - buf[2] = 0x00; /* reg addr len */ - buf[3] = 0x00; /* reg addr MSB */ - buf[4] = 0x00; /* reg addr LSB */ + if (state->chip_type == 0x9306) { + buf[1] = 0x03; /* I2C bus */ + buf[2] = msg[0].addr << 1; + } else { + buf[1] = msg[0].addr << 1; + buf[2] = 0x00; /* reg addr len */ + buf[3] = 0x00; /* reg addr MSB */ + buf[4] = 0x00; /* reg addr LSB */ + } ret = af9035_ctrl_msg(d, &req); } } else { @@ -465,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) else *name = AF9035_FIRMWARE_IT9135_V1; state->eeprom_addr = EEPROM_BASE_IT9135; + } else if (state->chip_type == 0x9306) { + *name = AF9035_FIRMWARE_IT9303; + state->eeprom_addr = EEPROM_BASE_IT9135; } else { *name = AF9035_FIRMWARE_AF9035; state->eeprom_addr = EEPROM_BASE_AF9035; @@ -674,7 +715,8 @@ static int af9035_download_firmware(struct dvb_usb_device *d, if (!tmp) tmp = 0x3a; - if (state->chip_type == 0x9135) { + if ((state->chip_type == 0x9135) || + (state->chip_type == 0x9306)) { ret = af9035_wr_reg(d, 0x004bfb, tmp); if (ret < 0) goto err; @@ -766,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device *d) dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__); goto skip_eeprom; } + } else if (state->chip_type == 0x9306) { + /* + * IT930x is an USB bridge, only single demod-single tuner + * configurations seen so far. + */ + return 0; } + + /* check if there is dual tuners */ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp); if (ret < 0) @@ -1111,6 +1161,41 @@ err: return ret; } +static int it930x_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; + struct si2168_config si2168_config; + struct i2c_adapter *adapter; + + dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id); + + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &adap->fe[0]; + si2168_config.ts_mode = SI2168_TS_SERIAL; + + state->af9033_config[adap->id].fe = &adap->fe[0]; + state->af9033_config[adap->id].ops = &state->ops; + ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config, + &d->i2c_adap); + if (ret) + goto err; + + if (adap->fe[0] == NULL) { + ret = -ENODEV; + goto err; + } + state->i2c_adapter_demod = adapter; + + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + static int af9035_frontend_detach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1430,6 +1515,93 @@ err: return ret; } +static int it930x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + struct si2157_config si2157_config; + + dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); + + /* I2C master bus 2 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f6a7, 0x07); + if (ret < 0) + goto err; + + /* I2C master bus 1,3 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f103, 0x07); + if (ret < 0) + goto err; + + /* set gpio11 low */ + ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01); + if (ret < 0) + goto err; + + /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */ + ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01); + if (ret < 0) + goto err; + + msleep(200); + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01); + if (ret < 0) + goto err; + + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = adap->fe[0]; + ret = af9035_add_i2c_dev(d, "si2157", 0x63, + &si2157_config, state->i2c_adapter_demod); + + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + + +static int it930x_tuner_detach(struct dvb_usb_adapter *adap) +{ + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + + dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id); + + if (adap->id == 1) { + if (state->i2c_client[3]) + af9035_del_i2c_dev(d); + } else if (adap->id == 0) { + if (state->i2c_client[1]) + af9035_del_i2c_dev(d); + } + + return 0; +} + + static int af9035_tuner_detach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1503,6 +1675,89 @@ err: return ret; } +static int it930x_init(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + int ret, i; + u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4; + u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; + struct reg_val_mask tab[] = { + { 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */ + { 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */ + { 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */ + { 0x00f41a, 0x01, 0x01 }, /* dvbt_en */ + { 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */ + { 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */ + { 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */ + { 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */ + { 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */ + { 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */ + { 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */ + { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0c, packet_size, 0xff}, + { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0d, packet_size, 0xff }, + { 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */ + { 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */ + { 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */ + { 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */ + { 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */ + + /* suspend gpio1 for TS-C */ + { 0x00d8b0, 0x01, 0xff }, /* gpio1 */ + { 0x00d8b1, 0x01, 0xff }, /* gpio1 */ + { 0x00d8af, 0x00, 0xff }, /* gpio1 */ + + /* suspend gpio7 for TS-D */ + { 0x00d8c4, 0x01, 0xff }, /* gpio7 */ + { 0x00d8c5, 0x01, 0xff }, /* gpio7 */ + { 0x00d8c3, 0x00, 0xff }, /* gpio7 */ + + /* suspend gpio13 for TS-B */ + { 0x00d8dc, 0x01, 0xff }, /* gpio13 */ + { 0x00d8dd, 0x01, 0xff }, /* gpio13 */ + { 0x00d8db, 0x00, 0xff }, /* gpio13 */ + + /* suspend gpio14 for TS-E */ + { 0x00d8e4, 0x01, 0xff }, /* gpio14 */ + { 0x00d8e5, 0x01, 0xff }, /* gpio14 */ + { 0x00d8e3, 0x00, 0xff }, /* gpio14 */ + + /* suspend gpio15 for TS-A */ + { 0x00d8e8, 0x01, 0xff }, /* gpio15 */ + { 0x00d8e9, 0x01, 0xff }, /* gpio15 */ + { 0x00d8e7, 0x00, 0xff }, /* gpio15 */ + + { 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */ + { 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */ + { 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */ + { 0x00da4c, 0x01, 0xff }, /* ts0_en */ + { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */ + }; + + dev_dbg(&d->udev->dev, + "%s: USB speed=%d frame_size=%04x packet_size=%02x\n", + __func__, d->udev->speed, frame_size, packet_size); + + /* init endpoints */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9035_wr_reg_mask(d, tab[i].reg, + tab[i].val, tab[i].mask); + + if (ret < 0) + goto err; + } + + return 0; +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + + #if IS_ENABLED(CONFIG_RC_CORE) static int af9035_rc_query(struct dvb_usb_device *d) { @@ -1706,6 +1961,37 @@ static const struct dvb_usb_device_properties af9035_props = { }, }; +static const struct dvb_usb_device_properties it930x_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, + .download_firmware = af9035_download_firmware, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config, + .frontend_attach = it930x_frontend_attach, + .frontend_detach = af9035_frontend_detach, + .tuner_attach = it930x_tuner_attach, + .tuner_detach = it930x_tuner_detach, + .init = it930x_init, + .get_stream_config = af9035_get_stream_config, + + .get_adapter_count = af9035_get_adapter_count, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188), + }, + }, +}; + static const struct usb_device_id af9035_id_table[] = { /* AF9035 devices */ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, @@ -1759,6 +2045,9 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2", RC_MAP_IT913X_V1) }, + /* IT930x devices */ + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, + &it930x_props, "ITE 9303 Generic", 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)", @@ -1795,3 +2084,4 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035); MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1); MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2); +MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index edb3871c50ea..416a97f05ec8 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -31,6 +31,8 @@ #include "tda18218.h" #include "fc2580.h" #include "it913x.h" +#include "si2168.h" +#include "si2157.h" struct reg_val { u32 reg; @@ -66,6 +68,7 @@ struct state { struct af9033_ops ops; #define AF9035_I2C_CLIENT_MAX 4 struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX]; + struct i2c_adapter *i2c_adapter_demod; }; static const u32 clock_lut_af9035[] = { @@ -99,6 +102,7 @@ static const u32 clock_lut_it9135[] = { #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw" #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw" #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw" +#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw" /* * eeprom is memory mapped as read only. Writing that memory mapped address @@ -140,5 +144,7 @@ static const u32 clock_lut_it9135[] = { #define CMD_FW_DL_BEGIN 0x24 #define CMD_FW_DL_END 0x25 #define CMD_FW_SCATTER_WR 0x29 +#define CMD_GENERIC_I2C_RD 0x2a +#define CMD_GENERIC_I2C_WR 0x2b #endif -- cgit v1.2.3 From 46cebe017afd03614b17c70ed5ed2734ec3796f7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 22:29:41 -0300 Subject: [media] qm1d1c0042: fix compilation on 32 bits drivers/built-in.o: In function `qm1d1c0042_set_params': >> qm1d1c0042.c:(.text+0x2519730): undefined reference to `__divdi3' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/qm1d1c0042.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c index 585594b9c4f8..18bc745ed108 100644 --- a/drivers/media/tuners/qm1d1c0042.c +++ b/drivers/media/tuners/qm1d1c0042.c @@ -28,6 +28,7 @@ */ #include +#include #include "qm1d1c0042.h" #define QM1D1C0042_NUM_REGS 0x20 @@ -234,7 +235,9 @@ static int qm1d1c0042_set_params(struct dvb_frontend *fe) * sd = b (b >= 0) * 1<<22 + b (b < 0) */ - b = (((s64) freq) << 20) / state->cfg.xtal_freq - (((s64) a) << 20); + b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq) + - (((s64) a) << 20); + if (b >= 0) sd = b; else -- cgit v1.2.3 From 2ea12442e3e5df6107ba4f948c7e6f7c99b3b373 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 22:38:37 -0300 Subject: [media] tc90522: fix compilation on 32 bits drivers/built-in.o: In function `tc90522t_get_frontend': >> tc90522.c:(.text+0x260b64c): undefined reference to `__divdi3' >> tc90522.c:(.text+0x260b685): undefined reference to `__divdi3' >> tc90522.c:(.text+0x260b6bb): undefined reference to `__divdi3' >> tc90522.c:(.text+0x260b713): undefined reference to `__divdi3' drivers/built-in.o:tc90522.c:(.text+0x260bb64): more undefined references to `__divdi3' follow Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/tc90522.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index cdd9808c322c..d9905fb52f84 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -28,6 +28,7 @@ */ #include +#include #include #include "dvb_math.h" #include "tc90522.h" @@ -275,7 +276,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe) /* cn = cnr << 3 */ p = int_sqrt(cndat << 16); p4 = cndat * cndat; - cn = (-16346LL * p4 * p / 10) >> 35; + cn = div64_s64(-16346LL * p4 * p, 10) >> 35; cn += (14341LL * p4) >> 21; cn -= (50259LL * cndat * p) >> 23; cn += (88977LL * cndat) >> 9; @@ -434,13 +435,13 @@ static int tc90522t_get_frontend(struct dvb_frontend *fe) p *= 10; cn = 24772; - cn += ((43827LL * p) / 10) >> 24; + cn += div64_s64(43827LL * p, 10) >> 24; tmp = p >> 8; - cn += ((3184LL * tmp * tmp) / 10) >> 32; + cn += div64_s64(3184LL * tmp * tmp, 10) >> 32; tmp = p >> 13; - cn -= ((128LL * tmp * tmp * tmp) / 10) >> 33; + cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33; tmp = p >> 18; - cn += ((192LL * tmp * tmp * tmp * tmp) / 1000) >> 24; + cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24; stats->stat[0].svalue = cn >> 3; stats->stat[0].scale = FE_SCALE_DECIBEL; -- cgit v1.2.3 From 197a47f2d51022c613bc7bf40953a0fa3497b9c5 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 20 Aug 2014 16:12:54 -0300 Subject: [media] rcar_vin: fix error message in rcar_vin_get_formats() The dev_err() call is supposed to output x in decimal but one of the format specifiers is "%x" instead of "%u" (most probably due to a typo). Signed-off-by: Sergei Shtylyov Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/rcar_vin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index b122c2cf5b85..20defcb8b31b 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -981,7 +981,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, if (shift == 3) { dev_err(dev, - "Failed to configure the client below %ux%x\n", + "Failed to configure the client below %ux%u\n", mf.width, mf.height); return -EIO; } -- cgit v1.2.3 From 5d6de11c331d61dd27cf02f54243ebd1fcfbbfb3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Sep 2014 09:23:36 -0300 Subject: [media] mx2-camera: potential negative underflow bug My static checker complains: drivers/media/platform/soc_camera/mx2_camera.c:1070 mx2_emmaprp_resize() warn: no lower bound on 'num' The heuristic is that it's looking for values which the user can influence and we put an upper bound on them but we (perhaps accidentally) allow negative numbers. I am not very familiar with this code but I have looked at it and think there might be a bug. Making the variable unsigned seems like a safe option either way and this silences the static checker warning. The call tree is: -> subdev_do_ioctl() -> mx2_camera_set_fmt() -> mx2_emmaprp_resize() The check: if (num > RESIZE_NUM_MAX) can underflow and then we use "num" on the else path. Signed-off-by: Dan Carpenter Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx2_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 2d57c1d272b8..2347612a4cc1 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1002,7 +1002,7 @@ static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, struct v4l2_mbus_framefmt *mf_in, struct v4l2_pix_format *pix_out, bool apply) { - int num, den; + unsigned int num, den; unsigned long m; int i, dir; -- cgit v1.2.3 From c710f591a6f209220bd0649153e1fbc78bc09db9 Mon Sep 17 00:00:00 2001 From: Kazunori Kobayashi Date: Thu, 11 Sep 2014 03:09:38 -0300 Subject: [media] soc_camera: Support VIDIOC_EXPBUF ioctl This patch allows for exporting a dmabuf descriptor from soc_camera drivers. Signed-off-by: Kazunori Kobayashi Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index ee8cdc95a9f9..8e61b976da19 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -437,6 +437,22 @@ static int soc_camera_prepare_buf(struct file *file, void *priv, return vb2_prepare_buf(&icd->vb2_vidq, b); } +static int soc_camera_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *p) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + if (icd->streamer != file) + return -EBUSY; + + /* videobuf2 only */ + if (ici->ops->init_videobuf) + return -EINVAL; + else + return vb2_expbuf(&icd->vb2_vidq, p); +} + /* Always entered with .host_lock held */ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { @@ -2083,6 +2099,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_dqbuf = soc_camera_dqbuf, .vidioc_create_bufs = soc_camera_create_bufs, .vidioc_prepare_buf = soc_camera_prepare_buf, + .vidioc_expbuf = soc_camera_expbuf, .vidioc_streamon = soc_camera_streamon, .vidioc_streamoff = soc_camera_streamoff, .vidioc_cropcap = soc_camera_cropcap, -- cgit v1.2.3 From 327eeb3a1a335f2580e72878191ca7a5236797bc Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Tue, 23 Sep 2014 13:53:09 -0300 Subject: [media] si2168: add FE_CAN_MULTISTREAM into caps PLP selection was implemented for Si2168 last month (patchwork 25387). However, FE_CAN_MULTISTREAM was not added to dvb_frontend_ops of si2168. This patch adds FE_CAN_MULTISTREAM, which indicates that multiple PLP are supported. Signed-off-by: Olli Salonen Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index a0797fd95129..1cd93be281ed 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -622,7 +622,8 @@ static const struct dvb_frontend_ops si2168_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 }, .get_tune_settings = si2168_get_tune_settings, -- cgit v1.2.3 From 00684dab287956573122815bfdc04cb4b4561033 Mon Sep 17 00:00:00 2001 From: Zhaowei Yuan Date: Wed, 3 Sep 2014 23:28:06 -0300 Subject: [media] s5p_mfc: correct the loop condition It should take ctx->dst_fmt->num_planes as the loop condition for CAPTURE. Signed-off-by: Zhaowei Yuan Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index fe4d21ccfd49..9e47b969853b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -990,7 +990,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (ctx->capture_state == QUEUE_BUFS_MMAPED) return 0; - for (i = 0; i <= ctx->src_fmt->num_planes ; i++) { + for (i = 0; i < ctx->dst_fmt->num_planes; i++) { if (IS_ERR_OR_NULL(ERR_PTR( vb2_dma_contig_plane_dma_addr(vb, i)))) { mfc_err("Plane mem not allocated\n"); -- cgit v1.2.3 From 9aee8b80a8facefb29ad0077fdbcca116f25f6e6 Mon Sep 17 00:00:00 2001 From: Zhaowei Yuan Date: Wed, 3 Sep 2014 23:28:43 -0300 Subject: [media] s5p_mfc: unify variable naming style Variable frame_size represents the size of plane luminance here, not just frame size, its naming style should be unified as frame_size_ch and frame_size_mv. Signed-off-by: Zhaowei Yuan Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 f88290556e2a..96ac14e2fc6e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -378,7 +378,7 @@ static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, /* Set decoding frame buffer */ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) { - unsigned int frame_size, i; + unsigned int frame_size_lu, i; unsigned int frame_size_ch, frame_size_mv; struct s5p_mfc_dev *dev = ctx->dev; unsigned int dpb; @@ -466,10 +466,10 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) ctx->codec_mode); return -EINVAL; } - frame_size = ctx->luma_size; + frame_size_lu = ctx->luma_size; frame_size_ch = ctx->chroma_size; frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, + mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch, frame_size_mv); for (i = 0; i < ctx->total_dpb_count; i++) { /* Bank2 */ @@ -497,7 +497,7 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Not enough memory has been allocated\n"); return -ENOMEM; } - s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE); s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); -- cgit v1.2.3 From e2c3be2aff3358e485ed307cc3ad11a9c58c086f Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Thu, 11 Sep 2014 10:27:20 -0300 Subject: [media] s5p-mfc: Fix sparse errors in the MFC driver The following error: "error: incompatible types in conditional expression (different base types)" was reported multiple times for the s5p-mfc driver. This error was caused by two macro definitions - s5p_mfc_hw_call (in s5p_mfc_common.h) and WRITEL (in s5p_mfc_opr_v6.c). In the former case the macro assumed that all ops return a value, but some ops return void. The solution to this problem was the addition of a s5p_mfc_hw_call_void macro. In the latter case the macro used the ?: construction to check whether the address is non zero. This is not necessary after the driver left the development and debugging cycle, so the READL and WRITEL macros were removed. Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 46 +-- drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 6 + drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 16 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 20 +- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 26 +- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 471 ++++++++++++------------ 6 files changed, 293 insertions(+), 292 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d180440ac43e..01e17f47b590 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -150,10 +150,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) if (!ctx) continue; ctx->state = MFCINST_ERROR; - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, - &ctx->vq_dst); - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, - &ctx->vq_src); + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, + &ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, + &ctx->src_queue, &ctx->vq_src); clear_work_bit(ctx); wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); } @@ -327,12 +327,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, if (res_change == S5P_FIMV_RES_INCREASE || res_change == S5P_FIMV_RES_DECREASE) { ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); return; } if (ctx->dpb_flush_flag) @@ -400,7 +400,7 @@ leave_handle_frame: if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->pb_count) clear_work_bit(ctx); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -409,7 +409,7 @@ leave_handle_frame: if (test_bit(0, &dev->enter_suspend)) wake_up_dev(dev, reason, err); else - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ @@ -435,10 +435,10 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, ctx->state = MFCINST_ERROR; /* Mark all dst buffers as having an error */ spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, &ctx->vq_dst); /* Mark all src buffers as having an error */ - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue, &ctx->vq_src); spin_unlock_irqrestore(&dev->irqlock, flags); wake_up_ctx(ctx, reason, err); @@ -452,7 +452,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, } if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); s5p_mfc_clock_off(); wake_up_dev(dev, reason, err); return; @@ -476,7 +476,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, dev); - s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx); ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, dev); @@ -503,12 +503,12 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->head_processed = 1; } } - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -523,7 +523,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (ctx == NULL) return; dev = ctx->dev; - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -550,7 +550,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -591,7 +591,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -628,12 +628,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) if (ctx->c_ops->post_frame_start) { if (ctx->c_ops->post_frame_start(ctx)) mfc_err("post_frame_start() failed\n"); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } @@ -663,7 +663,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) case S5P_MFC_R2H_CMD_WAKEUP_RET: if (ctx) clear_work_bit(ctx); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); @@ -685,12 +685,12 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) default: mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); } mfc_debug_leave(); return IRQ_HANDLED; irq_cleanup_hw: - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -699,7 +699,7 @@ irq_cleanup_hw: s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); mfc_debug(2, "Exit via irq_cleanup_hw\n"); return IRQ_HANDLED; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 01816ffb384b..3e41ca1293ed 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -698,6 +698,12 @@ struct mfc_control { #define s5p_mfc_hw_call(f, op, args...) \ ((f && f->op) ? f->op(args) : -ENODEV) +#define s5p_mfc_hw_call_void(f, op, args...) \ +do { \ + if (f && f->op) \ + f->op(args); \ +} while (0) + #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 23d247d535a0..3c10e31d017b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -294,7 +294,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_on(); s5p_mfc_reset(dev); - s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev); s5p_mfc_clock_off(); } @@ -397,7 +397,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ @@ -411,9 +411,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) err_free_desc_buf: if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx); err_free_inst_buf: - s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx); err: return ret; } @@ -423,17 +423,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occurred */ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) mfc_err("Err returning instance\n"); /* Free resources */ - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); - s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx); if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; ctx->state = MFCINST_FREE; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 9e47b969853b..7bfbc38dc20a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -543,7 +543,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); if (ret) goto out; - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx); ctx->dst_bufs_cnt = 0; } else if (ctx->capture_state == QUEUE_FREE) { WARN_ON(ctx->dst_bufs_cnt != 0); @@ -571,7 +571,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } else { @@ -846,7 +846,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, 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); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { mfc_err("EOS: marking last buffer of stream"); buf = list_entry(ctx->src_queue.prev, @@ -1044,7 +1044,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); return 0; } @@ -1065,8 +1065,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) } if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, - &ctx->vq_dst); + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, + &ctx->dst_queue, &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; ctx->dpb_flush_flag = 1; @@ -1076,7 +1076,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state = MFCINST_FLUSH; set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0)) mfc_err("Err flushing buffers\n"); @@ -1084,8 +1084,8 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, - &ctx->vq_src); + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, + &ctx->src_queue, &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; spin_unlock_irqrestore(&dev->irqlock, flags); @@ -1124,7 +1124,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_dec_qops = { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 41f3b7f512fa..4ebfcd647b72 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -767,7 +767,7 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; @@ -800,7 +800,7 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) ctx->state = MFCINST_RUNNING; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_enc_dpb_count, dev); @@ -825,15 +825,15 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr, - src_c_addr); + s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx, + src_y_addr, src_c_addr); spin_unlock_irqrestore(&dev->irqlock, flags); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -858,7 +858,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { - s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, + s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx, &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); @@ -1124,7 +1124,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->width, pix_fmt_mp->height, ctx->img_width, ctx->img_height); - s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); + s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx); pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; @@ -1701,7 +1701,7 @@ static int vidioc_encoder_cmd(struct file *file, void *priv, 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); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } else { mfc_debug(2, "EOS: marking last buffer of stream\n"); buf = list_entry(ctx->src_queue.prev, @@ -1945,7 +1945,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); return 0; } @@ -1966,14 +1966,14 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state = MFCINST_FINISHED; spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, - &ctx->vq_dst); + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, + &ctx->dst_queue, &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { cleanup_ref_queue(ctx); - s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue, &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; @@ -2014,7 +2014,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_enc_qops = { 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 c1c12f8d8f68..e9d1eaf72682 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -43,11 +43,6 @@ } while (0) #endif /* S5P_MFC_DEBUG_REGWRITE */ -#define READL(reg) \ - (WARN_ON_ONCE(!(reg)) ? 0 : readl(reg)) -#define WRITEL(data, reg) \ - (WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg))) - #define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2) /* Allocate temporary buffers for decoding */ @@ -416,10 +411,10 @@ static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" "buf_size: 0x%08x (%d)\n", ctx->inst_no, buf_addr, strm_size, strm_size); - WRITEL(strm_size, mfc_regs->d_stream_data_size); - WRITEL(buf_addr, mfc_regs->d_cpb_buffer_addr); - WRITEL(buf_size->cpb, mfc_regs->d_cpb_buffer_size); - WRITEL(start_num_byte, mfc_regs->d_cpb_buffer_offset); + writel(strm_size, mfc_regs->d_stream_data_size); + writel(buf_addr, mfc_regs->d_cpb_buffer_addr); + writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size); + writel(start_num_byte, mfc_regs->d_cpb_buffer_offset); mfc_debug_leave(); return 0; @@ -443,17 +438,17 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); - WRITEL(ctx->total_dpb_count, mfc_regs->d_num_dpb); - WRITEL(ctx->luma_size, mfc_regs->d_first_plane_dpb_size); - WRITEL(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size); + writel(ctx->total_dpb_count, mfc_regs->d_num_dpb); + writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size); + writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size); - WRITEL(buf_addr1, mfc_regs->d_scratch_buffer_addr); - WRITEL(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); + writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); + writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); if (IS_MFCV8(dev)) { - WRITEL(ctx->img_width, + writel(ctx->img_width, mfc_regs->d_first_plane_dpb_stride_size); - WRITEL(ctx->img_width, + writel(ctx->img_width, mfc_regs->d_second_plane_dpb_stride_size); } @@ -462,8 +457,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ - WRITEL(ctx->mv_size, mfc_regs->d_mv_buffer_size); - WRITEL(ctx->mv_count, mfc_regs->d_num_mv); + writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); + writel(ctx->mv_count, mfc_regs->d_num_mv); } frame_size = ctx->luma_size; @@ -476,11 +471,11 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) /* Bank2 */ mfc_debug(2, "Luma %d: %x\n", i, ctx->dst_bufs[i].cookie.raw.luma); - WRITEL(ctx->dst_bufs[i].cookie.raw.luma, + writel(ctx->dst_bufs[i].cookie.raw.luma, mfc_regs->d_first_plane_dpb + i * 4); mfc_debug(2, "\tChroma %d: %x\n", i, ctx->dst_bufs[i].cookie.raw.chroma); - WRITEL(ctx->dst_bufs[i].cookie.raw.chroma, + writel(ctx->dst_bufs[i].cookie.raw.chroma, mfc_regs->d_second_plane_dpb + i * 4); } if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || @@ -494,7 +489,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "\tBuf1: %x, size: %d\n", buf_addr1, buf_size1); - WRITEL(buf_addr1, mfc_regs->d_mv_buffer + i * 4); + writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4); buf_addr1 += frame_size_mv; buf_size1 -= frame_size_mv; } @@ -507,8 +502,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) return -ENOMEM; } - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_INIT_BUFS_V6, NULL); mfc_debug(2, "After setting buffers.\n"); @@ -522,8 +517,8 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - WRITEL(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */ - WRITEL(size, mfc_regs->e_stream_buffer_size); + writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */ + writel(size, mfc_regs->e_stream_buffer_size); mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n", addr, size); @@ -537,8 +532,8 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - WRITEL(y_addr, mfc_regs->e_source_first_plane_addr); - WRITEL(c_addr, mfc_regs->e_source_second_plane_addr); + writel(y_addr, mfc_regs->e_source_first_plane_addr); + writel(c_addr, mfc_regs->e_source_second_plane_addr); mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr); mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr); @@ -551,11 +546,11 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; unsigned long enc_recon_y_addr, enc_recon_c_addr; - *y_addr = READL(mfc_regs->e_encoded_source_first_plane_addr); - *c_addr = READL(mfc_regs->e_encoded_source_second_plane_addr); + *y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr); + *c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr); - enc_recon_y_addr = READL(mfc_regs->e_recon_luma_dpb_addr); - enc_recon_c_addr = READL(mfc_regs->e_recon_chroma_dpb_addr); + enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr); + enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr); mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr); mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr); @@ -577,24 +572,24 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); for (i = 0; i < ctx->pb_count; i++) { - WRITEL(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); buf_addr1 += ctx->luma_dpb_size; - WRITEL(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); buf_addr1 += ctx->chroma_dpb_size; - WRITEL(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); buf_addr1 += ctx->me_buffer_size; buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + ctx->me_buffer_size); } - WRITEL(buf_addr1, mfc_regs->e_scratch_buffer_addr); - WRITEL(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size); + writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); + writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size); buf_addr1 += ctx->scratch_buf_size; buf_size1 -= ctx->scratch_buf_size; - WRITEL(buf_addr1, mfc_regs->e_tmv_buffer0); + writel(buf_addr1, mfc_regs->e_tmv_buffer0); buf_addr1 += ctx->tmv_buffer_size >> 1; - WRITEL(buf_addr1, mfc_regs->e_tmv_buffer1); + writel(buf_addr1, mfc_regs->e_tmv_buffer1); buf_addr1 += ctx->tmv_buffer_size >> 1; buf_size1 -= ctx->tmv_buffer_size; @@ -605,8 +600,8 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) return -ENOMEM; } - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_INIT_BUFS_V6, NULL); mfc_debug_leave(); @@ -621,15 +616,15 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) /* multi-slice control */ /* multi-slice MB number or bit size */ - WRITEL(ctx->slice_mode, mfc_regs->e_mslice_mode); + writel(ctx->slice_mode, mfc_regs->e_mslice_mode); if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { - WRITEL(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); + writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); } else if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { - WRITEL(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); + writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); } else { - WRITEL(0x0, mfc_regs->e_mslice_size_mb); - WRITEL(0x0, mfc_regs->e_mslice_size_bits); + writel(0x0, mfc_regs->e_mslice_size_mb); + writel(0x0, mfc_regs->e_mslice_size_bits); } return 0; @@ -645,21 +640,21 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) mfc_debug_enter(); /* width */ - WRITEL(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */ + writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */ /* height */ - WRITEL(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */ + writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */ /* cropped width */ - WRITEL(ctx->img_width, mfc_regs->e_cropped_frame_width); + writel(ctx->img_width, mfc_regs->e_cropped_frame_width); /* cropped height */ - WRITEL(ctx->img_height, mfc_regs->e_cropped_frame_height); + writel(ctx->img_height, mfc_regs->e_cropped_frame_height); /* cropped offset */ - WRITEL(0x0, mfc_regs->e_frame_crop_offset); + writel(0x0, mfc_regs->e_frame_crop_offset); /* pictype : IDR period */ reg = 0; reg |= p->gop_size & 0xFFFF; - WRITEL(reg, mfc_regs->e_gop_config); + writel(reg, mfc_regs->e_gop_config); /* multi-slice control */ /* multi-slice MB number or bit size */ @@ -667,65 +662,65 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) reg = 0; if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { reg |= (0x1 << 3); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); ctx->slice_size.mb = p->slice_mb; } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { reg |= (0x1 << 3); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); ctx->slice_size.bits = p->slice_bit; } else { reg &= ~(0x1 << 3); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); } s5p_mfc_set_slice_mode(ctx); /* cyclic intra refresh */ - WRITEL(p->intra_refresh_mb, mfc_regs->e_ir_size); - reg = READL(mfc_regs->e_enc_options); + writel(p->intra_refresh_mb, mfc_regs->e_ir_size); + reg = readl(mfc_regs->e_enc_options); if (p->intra_refresh_mb == 0) reg &= ~(0x1 << 4); else reg |= (0x1 << 4); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg &= ~(0x1 << 9); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* memory structure cur. frame */ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { /* 0: Linear, 1: 2D tiled*/ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg &= ~(0x1 << 7); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* 0: NV12(CbCr), 1: NV21(CrCb) */ - WRITEL(0x0, mfc_regs->pixel_format); + writel(0x0, mfc_regs->pixel_format); } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { /* 0: Linear, 1: 2D tiled*/ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg &= ~(0x1 << 7); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* 0: NV12(CbCr), 1: NV21(CrCb) */ - WRITEL(0x1, mfc_regs->pixel_format); + writel(0x1, mfc_regs->pixel_format); } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { /* 0: Linear, 1: 2D tiled*/ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg |= (0x1 << 7); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* 0: NV12(CbCr), 1: NV21(CrCb) */ - WRITEL(0x0, mfc_regs->pixel_format); + writel(0x0, mfc_regs->pixel_format); } /* memory structure recon. frame */ /* 0: Linear, 1: 2D tiled */ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg |= (0x1 << 8); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* padding control & value */ - WRITEL(0x0, mfc_regs->e_padding_ctrl); + writel(0x0, mfc_regs->e_padding_ctrl); if (p->pad) { reg = 0; /** enable */ @@ -736,64 +731,64 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) reg |= ((p->pad_cb & 0xFF) << 8); /** y value */ reg |= p->pad_luma & 0xFF; - WRITEL(reg, mfc_regs->e_padding_ctrl); + writel(reg, mfc_regs->e_padding_ctrl); } /* rate control config. */ reg = 0; /* frame-level rate control */ reg |= ((p->rc_frame & 0x1) << 9); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* bit rate */ if (p->rc_frame) - WRITEL(p->rc_bitrate, + writel(p->rc_bitrate, mfc_regs->e_rc_bit_rate); else - WRITEL(1, mfc_regs->e_rc_bit_rate); + writel(1, mfc_regs->e_rc_bit_rate); /* reaction coefficient */ if (p->rc_frame) { if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ - WRITEL(1, mfc_regs->e_rc_mode); + writel(1, mfc_regs->e_rc_mode); else /* loose CBR */ - WRITEL(2, mfc_regs->e_rc_mode); + writel(2, mfc_regs->e_rc_mode); } /* seq header ctrl */ - reg = READL(mfc_regs->e_enc_options); + reg = readl(mfc_regs->e_enc_options); reg &= ~(0x1 << 2); reg |= ((p->seq_hdr_mode & 0x1) << 2); /* frame skip mode */ reg &= ~(0x3); reg |= (p->frame_skip_mode & 0x3); - WRITEL(reg, mfc_regs->e_enc_options); + writel(reg, mfc_regs->e_enc_options); /* 'DROP_CONTROL_ENABLE', disable */ - reg = READL(mfc_regs->e_rc_config); + reg = readl(mfc_regs->e_rc_config); reg &= ~(0x1 << 10); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* setting for MV range [16, 256] */ reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK); - WRITEL(reg, mfc_regs->e_mv_hor_range); + writel(reg, mfc_regs->e_mv_hor_range); reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK); - WRITEL(reg, mfc_regs->e_mv_ver_range); + writel(reg, mfc_regs->e_mv_ver_range); - WRITEL(0x0, mfc_regs->e_frame_insertion); - WRITEL(0x0, mfc_regs->e_roi_buffer_addr); - WRITEL(0x0, mfc_regs->e_param_change); - WRITEL(0x0, mfc_regs->e_rc_roi_ctrl); - WRITEL(0x0, mfc_regs->e_picture_tag); + writel(0x0, mfc_regs->e_frame_insertion); + writel(0x0, mfc_regs->e_roi_buffer_addr); + writel(0x0, mfc_regs->e_param_change); + writel(0x0, mfc_regs->e_rc_roi_ctrl); + writel(0x0, mfc_regs->e_picture_tag); - WRITEL(0x0, mfc_regs->e_bit_count_enable); - WRITEL(0x0, mfc_regs->e_max_bit_count); - WRITEL(0x0, mfc_regs->e_min_bit_count); + writel(0x0, mfc_regs->e_bit_count_enable); + writel(0x0, mfc_regs->e_max_bit_count); + writel(0x0, mfc_regs->e_min_bit_count); - WRITEL(0x0, mfc_regs->e_metadata_buffer_addr); - WRITEL(0x0, mfc_regs->e_metadata_buffer_size); + writel(0x0, mfc_regs->e_metadata_buffer_addr); + writel(0x0, mfc_regs->e_metadata_buffer_size); mfc_debug_leave(); @@ -814,10 +809,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params(ctx); /* pictype : number of B */ - reg = READL(mfc_regs->e_gop_config); + reg = readl(mfc_regs->e_gop_config); reg &= ~(0x3 << 16); reg |= ((p->num_b_frame & 0x3) << 16); - WRITEL(reg, mfc_regs->e_gop_config); + writel(reg, mfc_regs->e_gop_config); /* profile & level */ reg = 0; @@ -825,19 +820,19 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= ((p_h264->level & 0xFF) << 8); /** profile - 0 ~ 3 */ reg |= p_h264->profile & 0x3F; - WRITEL(reg, mfc_regs->e_picture_profile); + writel(reg, mfc_regs->e_picture_profile); /* rate control config. */ - reg = READL(mfc_regs->e_rc_config); + reg = readl(mfc_regs->e_rc_config); /** macroblock level rate control */ reg &= ~(0x1 << 8); reg |= ((p->rc_mb & 0x1) << 8); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /** frame QP */ reg &= ~(0x3F); reg |= p_h264->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* max & min value of QP */ reg = 0; @@ -845,16 +840,16 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= ((p_h264->rc_max_qp & 0x3F) << 8); /** min QP */ reg |= p_h264->rc_min_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_qp_bound); + writel(reg, mfc_regs->e_rc_qp_bound); /* other QPs */ - WRITEL(0x0, mfc_regs->e_fixed_picture_qp); + writel(0x0, mfc_regs->e_fixed_picture_qp); if (!p->rc_frame && !p->rc_mb) { reg = 0; reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); reg |= p_h264->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_fixed_picture_qp); + writel(reg, mfc_regs->e_fixed_picture_qp); } /* frame rate */ @@ -862,38 +857,38 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg = 0; reg |= ((p->rc_framerate_num & 0xFFFF) << 16); reg |= p->rc_framerate_denom & 0xFFFF; - WRITEL(reg, mfc_regs->e_rc_frame_rate); + writel(reg, mfc_regs->e_rc_frame_rate); } /* vbv buffer size */ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - WRITEL(p_h264->cpb_size & 0xFFFF, + writel(p_h264->cpb_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); if (p->rc_frame) - WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay); + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); } /* interlace */ reg = 0; reg |= ((p_h264->interlace & 0x1) << 3); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* height */ if (p_h264->interlace) { - WRITEL(ctx->img_height >> 1, + writel(ctx->img_height >> 1, mfc_regs->e_frame_height); /* 32 align */ /* cropped height */ - WRITEL(ctx->img_height >> 1, + writel(ctx->img_height >> 1, mfc_regs->e_cropped_frame_height); } /* loop filter ctrl */ - reg = READL(mfc_regs->e_h264_options); + reg = readl(mfc_regs->e_h264_options); reg &= ~(0x3 << 1); reg |= ((p_h264->loop_filter_mode & 0x3) << 1); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* loopfilter alpha offset */ if (p_h264->loop_filter_alpha < 0) { @@ -903,7 +898,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg = 0x00; reg |= (p_h264->loop_filter_alpha & 0xF); } - WRITEL(reg, mfc_regs->e_h264_lf_alpha_offset); + writel(reg, mfc_regs->e_h264_lf_alpha_offset); /* loopfilter beta offset */ if (p_h264->loop_filter_beta < 0) { @@ -913,28 +908,28 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg = 0x00; reg |= (p_h264->loop_filter_beta & 0xF); } - WRITEL(reg, mfc_regs->e_h264_lf_beta_offset); + writel(reg, mfc_regs->e_h264_lf_beta_offset); /* entropy coding mode */ - reg = READL(mfc_regs->e_h264_options); + reg = readl(mfc_regs->e_h264_options); reg &= ~(0x1); reg |= p_h264->entropy_mode & 0x1; - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* number of ref. picture */ - reg = READL(mfc_regs->e_h264_options); + reg = readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 7); reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* 8x8 transform enable */ - reg = READL(mfc_regs->e_h264_options); + reg = readl(mfc_regs->e_h264_options); reg &= ~(0x3 << 12); reg |= ((p_h264->_8x8_transform & 0x3) << 12); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* macroblock adaptive scaling features */ - WRITEL(0x0, mfc_regs->e_mb_rc_config); + writel(0x0, mfc_regs->e_mb_rc_config); if (p->rc_mb) { reg = 0; /** dark region */ @@ -945,95 +940,95 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= ((p_h264->rc_mb_static & 0x1) << 1); /** high activity region */ reg |= p_h264->rc_mb_activity & 0x1; - WRITEL(reg, mfc_regs->e_mb_rc_config); + writel(reg, mfc_regs->e_mb_rc_config); } /* aspect ratio VUI */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 5); reg |= ((p_h264->vui_sar & 0x1) << 5); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); - WRITEL(0x0, mfc_regs->e_aspect_ratio); - WRITEL(0x0, mfc_regs->e_extended_sar); + writel(0x0, mfc_regs->e_aspect_ratio); + writel(0x0, mfc_regs->e_extended_sar); if (p_h264->vui_sar) { /* aspect ration IDC */ reg = 0; reg |= p_h264->vui_sar_idc & 0xFF; - WRITEL(reg, mfc_regs->e_aspect_ratio); + writel(reg, mfc_regs->e_aspect_ratio); if (p_h264->vui_sar_idc == 0xFF) { /* extended SAR */ reg = 0; reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; reg |= p_h264->vui_ext_sar_height & 0xFFFF; - WRITEL(reg, mfc_regs->e_extended_sar); + writel(reg, mfc_regs->e_extended_sar); } } /* intra picture period for H.264 open GOP */ /* control */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 4); reg |= ((p_h264->open_gop & 0x1) << 4); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* value */ - WRITEL(0x0, mfc_regs->e_h264_i_period); + writel(0x0, mfc_regs->e_h264_i_period); if (p_h264->open_gop) { reg = 0; reg |= p_h264->open_gop_size & 0xFFFF; - WRITEL(reg, mfc_regs->e_h264_i_period); + writel(reg, mfc_regs->e_h264_i_period); } /* 'WEIGHTED_BI_PREDICTION' for B is disable */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x3 << 9); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 14); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* ASO */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 6); reg |= ((p_h264->aso & 0x1) << 6); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); /* hier qp enable */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 8); reg |= ((p_h264->open_gop & 0x1) << 8); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); reg = 0; if (p_h264->hier_qp && p_h264->hier_qp_layer) { reg |= (p_h264->hier_qp_type & 0x1) << 0x3; reg |= p_h264->hier_qp_layer & 0x7; - WRITEL(reg, mfc_regs->e_h264_num_t_layer); + writel(reg, mfc_regs->e_h264_num_t_layer); /* QP value for each layer */ for (i = 0; i < p_h264->hier_qp_layer && i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) { - WRITEL(p_h264->hier_qp_layer_qp[i], + writel(p_h264->hier_qp_layer_qp[i], mfc_regs->e_h264_hierarchical_qp_layer0 + i * 4); } } /* number of coding layer should be zero when hierarchical is disable */ - WRITEL(reg, mfc_regs->e_h264_num_t_layer); + writel(reg, mfc_regs->e_h264_num_t_layer); /* frame packing SEI generation */ - READL(mfc_regs->e_h264_options); + readl(mfc_regs->e_h264_options); reg &= ~(0x1 << 25); reg |= ((p_h264->sei_frame_packing & 0x1) << 25); - WRITEL(reg, mfc_regs->e_h264_options); + writel(reg, mfc_regs->e_h264_options); if (p_h264->sei_frame_packing) { reg = 0; /** current frame0 flag */ reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); /** arrangement type */ reg |= p_h264->sei_fp_arrangement_type & 0x3; - WRITEL(reg, mfc_regs->e_h264_frame_packing_sei_info); + writel(reg, mfc_regs->e_h264_frame_packing_sei_info); } if (p_h264->fmo) { @@ -1042,7 +1037,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) if (p_h264->fmo_slice_grp > 4) p_h264->fmo_slice_grp = 4; for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) - WRITEL(p_h264->fmo_run_len[i] - 1, + writel(p_h264->fmo_run_len[i] - 1, mfc_regs->e_h264_fmo_run_length_minus1_0 + i * 4); break; @@ -1054,10 +1049,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: if (p_h264->fmo_slice_grp > 2) p_h264->fmo_slice_grp = 2; - WRITEL(p_h264->fmo_chg_dir & 0x1, + writel(p_h264->fmo_chg_dir & 0x1, mfc_regs->e_h264_fmo_slice_grp_change_dir); /* the valid range is 0 ~ number of macroblocks -1 */ - WRITEL(p_h264->fmo_chg_rate, + writel(p_h264->fmo_chg_rate, mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1); break; default: @@ -1068,12 +1063,12 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) break; } - WRITEL(p_h264->fmo_map_type, + writel(p_h264->fmo_map_type, mfc_regs->e_h264_fmo_slice_grp_map_type); - WRITEL(p_h264->fmo_slice_grp - 1, + writel(p_h264->fmo_slice_grp - 1, mfc_regs->e_h264_fmo_num_slice_grp_minus1); } else { - WRITEL(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1); + writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1); } mfc_debug_leave(); @@ -1094,10 +1089,10 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params(ctx); /* pictype : number of B */ - reg = READL(mfc_regs->e_gop_config); + reg = readl(mfc_regs->e_gop_config); reg &= ~(0x3 << 16); reg |= ((p->num_b_frame & 0x3) << 16); - WRITEL(reg, mfc_regs->e_gop_config); + writel(reg, mfc_regs->e_gop_config); /* profile & level */ reg = 0; @@ -1105,19 +1100,19 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) reg |= ((p_mpeg4->level & 0xFF) << 8); /** profile - 0 ~ 1 */ reg |= p_mpeg4->profile & 0x3F; - WRITEL(reg, mfc_regs->e_picture_profile); + writel(reg, mfc_regs->e_picture_profile); /* rate control config. */ - reg = READL(mfc_regs->e_rc_config); + reg = readl(mfc_regs->e_rc_config); /** macroblock level rate control */ reg &= ~(0x1 << 8); reg |= ((p->rc_mb & 0x1) << 8); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /** frame QP */ reg &= ~(0x3F); reg |= p_mpeg4->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* max & min value of QP */ reg = 0; @@ -1125,16 +1120,16 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); /** min QP */ reg |= p_mpeg4->rc_min_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_qp_bound); + writel(reg, mfc_regs->e_rc_qp_bound); /* other QPs */ - WRITEL(0x0, mfc_regs->e_fixed_picture_qp); + writel(0x0, mfc_regs->e_fixed_picture_qp); if (!p->rc_frame && !p->rc_mb) { reg = 0; reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); reg |= p_mpeg4->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_fixed_picture_qp); + writel(reg, mfc_regs->e_fixed_picture_qp); } /* frame rate */ @@ -1142,21 +1137,21 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) reg = 0; reg |= ((p->rc_framerate_num & 0xFFFF) << 16); reg |= p->rc_framerate_denom & 0xFFFF; - WRITEL(reg, mfc_regs->e_rc_frame_rate); + writel(reg, mfc_regs->e_rc_frame_rate); } /* vbv buffer size */ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); if (p->rc_frame) - WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay); + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); } /* Disable HEC */ - WRITEL(0x0, mfc_regs->e_mpeg4_options); - WRITEL(0x0, mfc_regs->e_mpeg4_hec_period); + writel(0x0, mfc_regs->e_mpeg4_options); + writel(0x0, mfc_regs->e_mpeg4_hec_period); mfc_debug_leave(); @@ -1179,19 +1174,19 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) reg = 0; /** profile */ reg |= (0x1 << 4); - WRITEL(reg, mfc_regs->e_picture_profile); + writel(reg, mfc_regs->e_picture_profile); /* rate control config. */ - reg = READL(mfc_regs->e_rc_config); + reg = readl(mfc_regs->e_rc_config); /** macroblock level rate control */ reg &= ~(0x1 << 8); reg |= ((p->rc_mb & 0x1) << 8); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /** frame QP */ reg &= ~(0x3F); reg |= p_h263->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* max & min value of QP */ reg = 0; @@ -1199,16 +1194,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) reg |= ((p_h263->rc_max_qp & 0x3F) << 8); /** min QP */ reg |= p_h263->rc_min_qp & 0x3F; - WRITEL(reg, mfc_regs->e_rc_qp_bound); + writel(reg, mfc_regs->e_rc_qp_bound); /* other QPs */ - WRITEL(0x0, mfc_regs->e_fixed_picture_qp); + writel(0x0, mfc_regs->e_fixed_picture_qp); if (!p->rc_frame && !p->rc_mb) { reg = 0; reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); reg |= p_h263->rc_frame_qp & 0x3F; - WRITEL(reg, mfc_regs->e_fixed_picture_qp); + writel(reg, mfc_regs->e_fixed_picture_qp); } /* frame rate */ @@ -1216,16 +1211,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) reg = 0; reg |= ((p->rc_framerate_num & 0xFFFF) << 16); reg |= p->rc_framerate_denom & 0xFFFF; - WRITEL(reg, mfc_regs->e_rc_frame_rate); + writel(reg, mfc_regs->e_rc_frame_rate); } /* vbv buffer size */ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); if (p->rc_frame) - WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay); + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); } mfc_debug_leave(); @@ -1247,57 +1242,57 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params(ctx); /* pictype : number of B */ - reg = READL(mfc_regs->e_gop_config); + reg = readl(mfc_regs->e_gop_config); reg &= ~(0x3 << 16); reg |= ((p->num_b_frame & 0x3) << 16); - WRITEL(reg, mfc_regs->e_gop_config); + writel(reg, mfc_regs->e_gop_config); /* profile - 0 ~ 3 */ reg = p_vp8->profile & 0x3; - WRITEL(reg, mfc_regs->e_picture_profile); + writel(reg, mfc_regs->e_picture_profile); /* rate control config. */ - reg = READL(mfc_regs->e_rc_config); + reg = readl(mfc_regs->e_rc_config); /** macroblock level rate control */ reg &= ~(0x1 << 8); reg |= ((p->rc_mb & 0x1) << 8); - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* frame rate */ if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { reg = 0; reg |= ((p->rc_framerate_num & 0xFFFF) << 16); reg |= p->rc_framerate_denom & 0xFFFF; - WRITEL(reg, mfc_regs->e_rc_frame_rate); + writel(reg, mfc_regs->e_rc_frame_rate); } /* frame QP */ reg &= ~(0x7F); reg |= p_vp8->rc_frame_qp & 0x7F; - WRITEL(reg, mfc_regs->e_rc_config); + writel(reg, mfc_regs->e_rc_config); /* other QPs */ - WRITEL(0x0, mfc_regs->e_fixed_picture_qp); + writel(0x0, mfc_regs->e_fixed_picture_qp); if (!p->rc_frame && !p->rc_mb) { reg = 0; reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8); reg |= p_vp8->rc_frame_qp & 0x7F; - WRITEL(reg, mfc_regs->e_fixed_picture_qp); + writel(reg, mfc_regs->e_fixed_picture_qp); } /* max QP */ reg = ((p_vp8->rc_max_qp & 0x7F) << 8); /* min QP */ reg |= p_vp8->rc_min_qp & 0x7F; - WRITEL(reg, mfc_regs->e_rc_qp_bound); + writel(reg, mfc_regs->e_rc_qp_bound); /* vbv buffer size */ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); if (p->rc_frame) - WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay); + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); } /* VP8 specific params */ @@ -1319,7 +1314,7 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) } reg |= (val & 0xF) << 3; reg |= (p_vp8->num_ref & 0x2); - WRITEL(reg, mfc_regs->e_vp8_options); + writel(reg, mfc_regs->e_vp8_options); mfc_debug_leave(); @@ -1338,9 +1333,9 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, S5P_FIMV_CH_SEQ_HEADER_V6); mfc_debug(2, "BUFs: %08x %08x %08x\n", - READL(mfc_regs->d_cpb_buffer_addr), - READL(mfc_regs->d_cpb_buffer_addr), - READL(mfc_regs->d_cpb_buffer_addr)); + readl(mfc_regs->d_cpb_buffer_addr), + readl(mfc_regs->d_cpb_buffer_addr), + readl(mfc_regs->d_cpb_buffer_addr)); /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); @@ -1351,11 +1346,11 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) * set to negative value. */ if (ctx->display_delay >= 0) { reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); - WRITEL(ctx->display_delay, mfc_regs->d_display_delay); + writel(ctx->display_delay, mfc_regs->d_display_delay); } if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) { - WRITEL(reg, mfc_regs->d_dec_options); + writel(reg, mfc_regs->d_dec_options); reg = 0; } @@ -1370,22 +1365,22 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) - WRITEL(reg, mfc_regs->d_init_buffer_options); + writel(reg, mfc_regs->d_init_buffer_options); else - WRITEL(reg, mfc_regs->d_dec_options); + writel(reg, mfc_regs->d_dec_options); /* 0: NV12(CbCr), 1: NV21(CrCb) */ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) - WRITEL(0x1, mfc_regs->pixel_format); + writel(0x1, mfc_regs->pixel_format); else - WRITEL(0x0, mfc_regs->pixel_format); + writel(0x0, mfc_regs->pixel_format); /* sei parse */ - WRITEL(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable); + writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable); - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_SEQ_HEADER_V6, NULL); mfc_debug_leave(); @@ -1400,8 +1395,8 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) if (flush) { dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_H2R_CMD_FLUSH_V6, NULL); } } @@ -1413,19 +1408,19 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - WRITEL(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower); - WRITEL(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable); + writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower); + writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable); - WRITEL(ctx->inst_no, mfc_regs->instance_id); + writel(ctx->inst_no, mfc_regs->instance_id); /* Issue different commands to instance basing on whether it * is the last frame or not. */ switch (last_frame) { case 0: - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_FRAME_START_V6, NULL); break; case 1: - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_LAST_FRAME_V6, NULL); break; default: @@ -1458,12 +1453,12 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) /* Set stride lengths for v7 & above */ if (IS_MFCV7_PLUS(dev)) { - WRITEL(ctx->img_width, mfc_regs->e_source_first_plane_stride); - WRITEL(ctx->img_width, mfc_regs->e_source_second_plane_stride); + writel(ctx->img_width, mfc_regs->e_source_first_plane_stride); + writel(ctx->img_width, mfc_regs->e_source_second_plane_stride); } - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_SEQ_HEADER_V6, NULL); return 0; @@ -1479,7 +1474,7 @@ static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) if (p_h264->aso) { for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) { - WRITEL(p_h264->aso_slice_order[i], + writel(p_h264->aso_slice_order[i], mfc_regs->e_h264_aso_slice_order_0 + i * 4); } } @@ -1501,8 +1496,8 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) s5p_mfc_set_slice_mode(ctx); - WRITEL(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_FRAME_START_V6, NULL); mfc_debug(2, "--\n"); @@ -1877,15 +1872,15 @@ static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) { const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - WRITEL(0, mfc_regs->risc2host_command); - WRITEL(0, mfc_regs->risc2host_int); + writel(0, mfc_regs->risc2host_command); + writel(0, mfc_regs->risc2host_int); } static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { s5p_mfc_clock_on(); - WRITEL(data, (void *)ofs); + writel(data, (void *)ofs); s5p_mfc_clock_off(); } @@ -1895,7 +1890,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) int ret; s5p_mfc_clock_on(); - ret = READL((void *)ofs); + ret = readl((void *)ofs); s5p_mfc_clock_off(); return ret; @@ -1903,51 +1898,51 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_display_first_plane_addr); + return readl(dev->mfc_regs->d_display_first_plane_addr); } static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_decoded_first_plane_addr); + return readl(dev->mfc_regs->d_decoded_first_plane_addr); } static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_display_status); + return readl(dev->mfc_regs->d_display_status); } static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_decoded_status); + return readl(dev->mfc_regs->d_decoded_status); } static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_decoded_frame_type) & + return readl(dev->mfc_regs->d_decoded_frame_type) & S5P_FIMV_DECODE_FRAME_MASK_V6; } static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - return READL(dev->mfc_regs->d_display_frame_type) & + return readl(dev->mfc_regs->d_display_frame_type) & S5P_FIMV_DECODE_FRAME_MASK_V6; } static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_decoded_nal_size); + return readl(dev->mfc_regs->d_decoded_nal_size); } static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->risc2host_command) & + return readl(dev->mfc_regs->risc2host_command) & S5P_FIMV_RISC2HOST_CMD_MASK; } static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->error_code); + return readl(dev->mfc_regs->error_code); } static int s5p_mfc_err_dec_v6(unsigned int err) @@ -1962,63 +1957,63 @@ static int s5p_mfc_err_dspl_v6(unsigned int err) static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_display_frame_width); + return readl(dev->mfc_regs->d_display_frame_width); } static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_display_frame_height); + return readl(dev->mfc_regs->d_display_frame_height); } static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_min_num_dpb); + return readl(dev->mfc_regs->d_min_num_dpb); } static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_min_num_mv); + return readl(dev->mfc_regs->d_min_num_mv); } static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->ret_instance_id); + return readl(dev->mfc_regs->ret_instance_id); } static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->e_num_dpb); + return readl(dev->mfc_regs->e_num_dpb); } static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->e_stream_size); + return readl(dev->mfc_regs->e_stream_size); } static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->e_slice_type); + return readl(dev->mfc_regs->e_slice_type); } static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->e_picture_count); + return readl(dev->mfc_regs->e_picture_count); } static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - return READL(dev->mfc_regs->d_frame_pack_sei_avail); + return readl(dev->mfc_regs->d_frame_pack_sei_avail); } static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_mvc_num_views); + return readl(dev->mfc_regs->d_mvc_num_views); } static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) { - return READL(dev->mfc_regs->d_mvc_view_id); + return readl(dev->mfc_regs->d_mvc_view_id); } static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) -- cgit v1.2.3 From 7e8fe13dc31d413c77ef1aaf7f7a2a60eab413da Mon Sep 17 00:00:00 2001 From: ayaka Date: Thu, 18 Sep 2014 16:41:12 -0300 Subject: [media] s5p-mfc: fix enum_fmt for s5p-mfc As the s5p-mfc is a driver which use multiplanar api, so the vidioc_enum_fmt_vid serial of ioctl should only for multiplanar, non-multiplanar shouldn't be implemented at all. Signed-off-by: ayaka Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 24 +++--------------------- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 24 +++--------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 7bfbc38dc20a..77eb952a744a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -283,17 +283,13 @@ static int vidioc_querycap(struct file *file, void *priv, /* Enumerate format */ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, - bool mplane, bool out) + bool out) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; int i, j = 0; for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (mplane && formats[i].num_planes == 1) - continue; - else if (!mplane && formats[i].num_planes > 1) - continue; if (out && formats[i].type != MFC_FMT_DEC) continue; else if (!out && formats[i].type != MFC_FMT_RAW) @@ -313,28 +309,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false, false); -} - static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(file, f, true, false); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false, true); + return vidioc_enum_fmt(file, f, false); } static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(file, f, true, true); + return vidioc_enum_fmt(file, f, true); } /* Get format */ @@ -881,9 +865,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, /* v4l2_ioctl_ops */ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 4ebfcd647b72..adffdb37746b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -951,17 +951,13 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, - bool mplane, bool out) + bool out) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; int i, j = 0; for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (mplane && formats[i].num_planes == 1) - continue; - else if (!mplane && formats[i].num_planes > 1) - continue; if (out && formats[i].type != MFC_FMT_RAW) continue; else if (!out && formats[i].type != MFC_FMT_ENC) @@ -981,28 +977,16 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false, false); -} - static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(file, f, true, false); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *prov, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false, true); + return vidioc_enum_fmt(file, f, false); } static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(file, f, true, true); + return vidioc_enum_fmt(file, f, true); } static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) @@ -1733,9 +1717,7 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, -- cgit v1.2.3 From 7c672812fe230f54e86da0e56cd2917e897fe760 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 22 Sep 2014 09:52:02 -0300 Subject: [media] s5p-mfc: Use decode status instead of display status on MFCv5 Commit 90c0ae50097 changed how the frame_type of a decoded frame gets determined, by switching from the get_dec_frame_type to get_disp_frame_type operation. Unfortunately it seems that on MFC v5 the result of get_disp_frame_type is always 0 (no display) when decoding (tested with H264), resulting in no frame ever being output from the decoder. This patch reverts MFC v5 to the previous behaviour while keeping the new behaviour for v6 and up. Signed-off-by: Sjoerd Simons Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 01e17f47b590..d95769f99901 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -264,7 +264,12 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) unsigned int frame_type; dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); - frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx); + if (IS_MFCV6_PLUS(dev)) + frame_type = s5p_mfc_hw_call(dev->mfc_ops, + get_disp_frame_type, ctx); + else + frame_type = s5p_mfc_hw_call(dev->mfc_ops, + get_dec_frame_type, dev); /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { -- cgit v1.2.3 From c5d28e29833c8bc80d96cb2f46c3cf06b43a8fa4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 22 Sep 2014 13:05:56 -0300 Subject: [media] coda: Improve runtime PM support For several reasons it's good practice to leave devices in runtime PM active state while those have been probed. In this cases we also want to prevent the device from going inactive, until the firmware has been completely installed, especially when using a PM domain. Signed-off-by: Ulf Hansson Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 55 ++++++++++++------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 0997b5c677bd..ced47609f5ef 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1688,7 +1688,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) if (!fw) { v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); - return; + goto put_pm; } /* allocate auxiliary per-device code buffer for the BIT processor */ @@ -1696,50 +1696,27 @@ static void coda_fw_callback(const struct firmware *fw, void *context) dev->debugfs_root); if (ret < 0) { dev_err(&pdev->dev, "failed to allocate code buffer\n"); - return; + goto put_pm; } /* Copy the whole firmware image to the code buffer */ memcpy(dev->codebuf.vaddr, fw->data, fw->size); release_firmware(fw); - if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) { - /* - * Enabling power temporarily will cause coda_hw_init to be - * called via coda_runtime_resume by the pm domain. - */ - ret = pm_runtime_get_sync(&dev->plat_dev->dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n", - ret); - return; - } - - ret = coda_check_firmware(dev); - if (ret < 0) - return; - - pm_runtime_put_sync(&dev->plat_dev->dev); - } else { - /* - * If runtime pm is disabled or pm_domain is not set, - * initialize once manually. - */ - ret = coda_hw_init(dev); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); - return; - } - - ret = coda_check_firmware(dev); - if (ret < 0) - return; + ret = coda_hw_init(dev); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); + goto put_pm; } + ret = coda_check_firmware(dev); + if (ret < 0) + goto put_pm; + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); if (IS_ERR(dev->alloc_ctx)) { v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); - return; + goto put_pm; } dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); @@ -1771,12 +1748,15 @@ static void coda_fw_callback(const struct firmware *fw, void *context) v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", dev->vfd[0].num, dev->vfd[1].num); + pm_runtime_put_sync(&pdev->dev); return; rel_m2m: v4l2_m2m_release(dev->m2m_dev); rel_ctx: vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); +put_pm: + pm_runtime_put_sync(&pdev->dev); } static int coda_firmware_request(struct coda_dev *dev) @@ -1998,6 +1978,13 @@ static int coda_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); + /* + * Start activated so we can directly call coda_hw_init in + * coda_fw_callback regardless of whether CONFIG_PM_RUNTIME is + * enabled or whether the device is associated with a PM domain. + */ + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); return coda_firmware_request(dev); -- cgit v1.2.3 From ca5ea0c5dfe0e63298eb157d877d19dfe892353f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:08:10 -0300 Subject: [media] s5p_mfc: use static for some structs drivers/media/platform/s5p-mfc/s5p_mfc.c:1334:28: warning: symbol 'mfc_buf_size_v5' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1341:25: warning: symbol 'buf_size_v5' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1347:26: warning: symbol 'mfc_buf_align_v5' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1360:28: warning: symbol 'mfc_buf_size_v6' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1368:25: warning: symbol 'buf_size_v6' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1374:26: warning: symbol 'mfc_buf_align_v6' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1392:28: warning: symbol 'mfc_buf_size_v7' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1400:25: warning: symbol 'buf_size_v7' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1406:26: warning: symbol 'mfc_buf_align_v7' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1419:28: warning: symbol 'mfc_buf_size_v8' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1427:25: warning: symbol 'buf_size_v8' was not declared. Should it be static? drivers/media/platform/s5p-mfc/s5p_mfc.c:1433:26: warning: symbol 'mfc_buf_align_v8' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d95769f99901..165bc86c5962 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1331,20 +1331,20 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { NULL) }; -struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { +static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { .h264_ctx = MFC_H264_CTX_BUF_SIZE, .non_h264_ctx = MFC_CTX_BUF_SIZE, .dsc = DESC_BUF_SIZE, .shm = SHARED_BUF_SIZE, }; -struct s5p_mfc_buf_size buf_size_v5 = { +static struct s5p_mfc_buf_size buf_size_v5 = { .fw = MAX_FW_SIZE, .cpb = MAX_CPB_SIZE, .priv = &mfc_buf_size_v5, }; -struct s5p_mfc_buf_align mfc_buf_align_v5 = { +static struct s5p_mfc_buf_align mfc_buf_align_v5 = { .base = MFC_BASE_ALIGN_ORDER, }; @@ -1357,7 +1357,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .fw_name[0] = "s5p-mfc.fw", }; -struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .dev_ctx = MFC_CTX_BUF_SIZE_V6, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, @@ -1365,13 +1365,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, }; -struct s5p_mfc_buf_size buf_size_v6 = { +static struct s5p_mfc_buf_size buf_size_v6 = { .fw = MAX_FW_SIZE_V6, .cpb = MAX_CPB_SIZE_V6, .priv = &mfc_buf_size_v6, }; -struct s5p_mfc_buf_align mfc_buf_align_v6 = { +static struct s5p_mfc_buf_align mfc_buf_align_v6 = { .base = 0, }; @@ -1389,7 +1389,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { .fw_name[1] = "s5p-mfc-v6-v2.fw", }; -struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .dev_ctx = MFC_CTX_BUF_SIZE_V7, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7, @@ -1397,13 +1397,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7, }; -struct s5p_mfc_buf_size buf_size_v7 = { +static struct s5p_mfc_buf_size buf_size_v7 = { .fw = MAX_FW_SIZE_V7, .cpb = MAX_CPB_SIZE_V7, .priv = &mfc_buf_size_v7, }; -struct s5p_mfc_buf_align mfc_buf_align_v7 = { +static struct s5p_mfc_buf_align mfc_buf_align_v7 = { .base = 0, }; @@ -1416,7 +1416,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = { .fw_name[0] = "s5p-mfc-v7.fw", }; -struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .dev_ctx = MFC_CTX_BUF_SIZE_V8, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8, @@ -1424,13 +1424,13 @@ struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8, }; -struct s5p_mfc_buf_size buf_size_v8 = { +static struct s5p_mfc_buf_size buf_size_v8 = { .fw = MAX_FW_SIZE_V8, .cpb = MAX_CPB_SIZE_V8, .priv = &mfc_buf_size_v8, }; -struct s5p_mfc_buf_align mfc_buf_align_v8 = { +static struct s5p_mfc_buf_align mfc_buf_align_v8 = { .base = 0, }; -- cgit v1.2.3 From d7fa7b0e5ffe7f3225158ec59e7040aa6e84d45f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:25:56 -0300 Subject: [media] s5p_mfc_opr_v5: fix smatch warnings drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:266:23: warning: incorrect type in argument 2 (different modifiers) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:266:23: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:266:23: got void const volatile [noderef] * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:274:36: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:274:36: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:274:36: got void * Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 96ac14e2fc6e..6234e4d70596 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -263,7 +263,7 @@ static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { - writel(data, (ctx->shm.virt + ofs)); + writel(data, (volatile void __iomem *)(ctx->shm.virt + ofs)); wmb(); } @@ -271,7 +271,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, unsigned int ofs) { rmb(); - return readl(ctx->shm.virt + ofs); + return readl((volatile void __iomem *)(ctx->shm.virt + ofs)); } static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) -- cgit v1.2.3 From b5e4d33070a3b1efc738c3889842be447a613211 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:31:25 -0300 Subject: [media] s5p_mfc_opr_v6: fix wrong type for registers As reported by smatch, there are several warnings related to bad types for registers. Worse than that, there are too many errors, preventing smatch to warn about real issues. So, fix them: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:414:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:414:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:414:35: got void *const d_stream_data_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:415:34: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:415:34: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:415:34: got void *const d_cpb_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:416:39: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:416:39: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:416:39: got void *const d_cpb_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:417:40: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:417:40: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:417:40: got void *const d_cpb_buffer_offset drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:441:46: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:441:46: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:441:46: got void *const d_num_dpb drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:442:40: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:442:40: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:442:40: got void *const d_first_plane_dpb_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:443:42: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:443:42: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:443:42: got void *const d_second_plane_dpb_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:445:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:445:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:445:35: got void *const d_scratch_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:446:47: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:446:47: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:446:47: got void *const d_scratch_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:450:33: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:450:33: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:450:33: got void *const d_first_plane_dpb_stride_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:452:33: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:452:33: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:452:33: got void *const d_second_plane_dpb_stride_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:460:46: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:460:46: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:460:46: got void *const d_mv_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:461:47: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:461:47: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:461:47: got void *const d_num_mv drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:475:61: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:475:61: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:475:61: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:479:62: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:479:62: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:479:62: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:492:65: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:492:65: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:492:65: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:505:38: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:505:38: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:505:38: got void *const instance_id drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:520:30: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:520:30: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:520:30: got void *const e_stream_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:521:30: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:521:30: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:521:30: got void *const e_stream_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:535:32: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:535:32: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:535:32: got void *const e_source_first_plane_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:536:32: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:536:32: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:536:32: got void *const e_source_second_plane_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:549:33: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:549:33: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:549:33: got void *const e_encoded_source_first_plane_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:550:33: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:550:33: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:550:33: got void *const e_encoded_source_second_plane_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:552:42: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:552:42: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:552:42: got void *const e_recon_luma_dpb_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:553:42: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:553:42: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:553:42: got void *const e_recon_chroma_dpb_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:575:56: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:575:56: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:575:56: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:577:58: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:577:58: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:577:58: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:579:57: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:579:57: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:579:57: got void * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:585:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:585:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:585:35: got void *const e_scratch_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:586:47: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:586:47: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:586:47: got void *const e_scratch_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:590:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:590:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:590:35: got void *const e_tmv_buffer0 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:592:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:592:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:592:35: got void *const e_tmv_buffer1 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:603:38: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:603:38: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:603:38: got void *const instance_id drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:619:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:619:41: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:619:41: got void *const e_mslice_mode drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:621:52: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:621:52: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:621:52: got void *const e_mslice_size_mb drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:624:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:624:54: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:624:54: got void *const e_mslice_size_bits drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:626:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:626:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:626:37: got void *const e_mslice_size_mb drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:627:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:627:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:627:37: got void *const e_mslice_size_bits drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:643:40: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:643:40: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:643:40: got void *const e_frame_width drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:645:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:645:41: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:645:41: got void *const e_frame_height drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:648:40: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:648:40: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:648:40: got void *const e_cropped_frame_width drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:650:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:650:41: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:650:41: got void *const e_cropped_frame_height drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:652:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:652:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:652:29: got void *const e_frame_crop_offset drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:657:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:657:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:657:29: got void *const e_gop_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:665:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:665:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:665:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:669:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:669:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:669:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:673:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:673:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:673:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:679:45: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:679:45: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:679:45: got void *const e_ir_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:680:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:680:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:680:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:685:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:685:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:685:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:688:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:688:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:688:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:690:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:690:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:690:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:695:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:695:37: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:695:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:697:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:697:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:697:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:699:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:699:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:699:37: got void *const pixel_format drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:702:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:702:37: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:702:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:704:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:704:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:704:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:706:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:706:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:706:37: got void *const pixel_format drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:709:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:709:37: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:709:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:711:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:711:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:711:37: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:713:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:713:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:713:37: got void *const pixel_format drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:718:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:718:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:718:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:720:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:720:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:720:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:723:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:723:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:723:29: got void *const e_padding_ctrl drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:734:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:734:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:734:37: got void *const e_padding_ctrl drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:741:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:741:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:741:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:746:33: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:746:33: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:746:33: got void *const e_rc_bit_rate drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:748:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:748:35: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:748:35: got void *const e_rc_bit_rate drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:753:43: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:753:43: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:753:43: got void *const e_rc_mode drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:755:43: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:755:43: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:755:43: got void *const e_rc_mode drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:759:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:759:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:759:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:766:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:766:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:766:29: got void *const e_enc_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:769:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:769:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:769:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:771:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:771:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:771:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:775:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:775:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:775:29: got void *const e_mv_hor_range drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:778:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:778:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:778:29: got void *const e_mv_ver_range drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:780:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:780:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:780:29: got void *const e_frame_insertion drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:781:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:781:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:781:29: got void *const e_roi_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:782:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:782:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:782:29: got void *const e_param_change drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:783:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:783:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:783:29: got void *const e_rc_roi_ctrl drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:784:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:784:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:784:29: got void *const e_picture_tag drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:786:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:786:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:786:29: got void *const e_bit_count_enable drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:787:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:787:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:787:29: got void *const e_max_bit_count drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:788:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:788:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:788:29: got void *const e_min_bit_count drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:790:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:790:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:790:29: got void *const e_metadata_buffer_addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:791:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:791:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:791:29: got void *const e_metadata_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:812:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:812:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:812:29: got void *const e_gop_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:815:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:815:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:815:29: got void *const e_gop_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:823:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:823:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:823:29: got void *const e_picture_profile drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:826:29: warning: incorrect type in argument 1 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:826:29: expected void const volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:826:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:830:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:830:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:830:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:835:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:835:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:835:29: got void *const e_rc_config drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:843:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:843:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:843:29: got void *const e_rc_qp_bound drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:846:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:846:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:846:29: got void *const e_fixed_picture_qp drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:852:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:852:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:852:37: got void *const e_fixed_picture_qp drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:860:37: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:860:37: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:860:37: got void *const e_rc_frame_rate drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:867:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:867:41: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:867:41: got void *const e_vbv_buffer_size drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:870:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:870:54: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:870:54: got void *const e_vbv_init_delay drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:876:29: warning: incorrect type in argument 2 (different address spaces) drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:876:29: expected void volatile [noderef] *addr drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:876:29: got void *const e_h264_options drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:881:41: warning: too many warnings Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | 488 ++++++++++++------------ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 4 +- 2 files changed, 246 insertions(+), 246 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 7a7ad32ee608..de2b8c69daa5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -20,254 +20,254 @@ struct s5p_mfc_regs { /* codec common registers */ - void *risc_on; - void *risc2host_int; - void *host2risc_int; - void *risc_base_address; - void *mfc_reset; - void *host2risc_command; - void *risc2host_command; - void *mfc_bus_reset_ctrl; - void *firmware_version; - void *instance_id; - void *codec_type; - void *context_mem_addr; - void *context_mem_size; - void *pixel_format; - void *metadata_enable; - void *mfc_version; - void *dbg_info_enable; - void *dbg_buffer_addr; - void *dbg_buffer_size; - void *hed_control; - void *mfc_timeout_value; - void *hed_shared_mem_addr; - void *dis_shared_mem_addr;/* only v7 */ - void *ret_instance_id; - void *error_code; - void *dbg_buffer_output_size; - void *metadata_status; - void *metadata_addr_mb_info; - void *metadata_size_mb_info; - void *dbg_info_stage_counter; + volatile void __iomem *risc_on; + volatile void __iomem *risc2host_int; + volatile void __iomem *host2risc_int; + volatile void __iomem *risc_base_address; + volatile void __iomem *mfc_reset; + volatile void __iomem *host2risc_command; + volatile void __iomem *risc2host_command; + volatile void __iomem *mfc_bus_reset_ctrl; + volatile void __iomem *firmware_version; + volatile void __iomem *instance_id; + volatile void __iomem *codec_type; + volatile void __iomem *context_mem_addr; + volatile void __iomem *context_mem_size; + volatile void __iomem *pixel_format; + volatile void __iomem *metadata_enable; + volatile void __iomem *mfc_version; + volatile void __iomem *dbg_info_enable; + volatile void __iomem *dbg_buffer_addr; + volatile void __iomem *dbg_buffer_size; + volatile void __iomem *hed_control; + volatile void __iomem *mfc_timeout_value; + volatile void __iomem *hed_shared_mem_addr; + volatile void __iomem *dis_shared_mem_addr;/* only v7 */ + volatile void __iomem *ret_instance_id; + volatile void __iomem *error_code; + volatile void __iomem *dbg_buffer_output_size; + volatile void __iomem *metadata_status; + volatile void __iomem *metadata_addr_mb_info; + volatile void __iomem *metadata_size_mb_info; + volatile void __iomem *dbg_info_stage_counter; /* decoder registers */ - void *d_crc_ctrl; - void *d_dec_options; - void *d_display_delay; - void *d_set_frame_width; - void *d_set_frame_height; - void *d_sei_enable; - void *d_min_num_dpb; - void *d_min_first_plane_dpb_size; - void *d_min_second_plane_dpb_size; - void *d_min_third_plane_dpb_size;/* only v8 */ - void *d_min_num_mv; - void *d_mvc_num_views; - void *d_min_num_dis;/* only v7 */ - void *d_min_first_dis_size;/* only v7 */ - void *d_min_second_dis_size;/* only v7 */ - void *d_min_third_dis_size;/* only v7 */ - void *d_post_filter_luma_dpb0;/* v7 and v8 */ - void *d_post_filter_luma_dpb1;/* v7 and v8 */ - void *d_post_filter_luma_dpb2;/* only v7 */ - void *d_post_filter_chroma_dpb0;/* v7 and v8 */ - void *d_post_filter_chroma_dpb1;/* v7 and v8 */ - void *d_post_filter_chroma_dpb2;/* only v7 */ - void *d_num_dpb; - void *d_num_mv; - void *d_init_buffer_options; - void *d_first_plane_dpb_stride_size;/* only v8 */ - void *d_second_plane_dpb_stride_size;/* only v8 */ - void *d_third_plane_dpb_stride_size;/* only v8 */ - void *d_first_plane_dpb_size; - void *d_second_plane_dpb_size; - void *d_third_plane_dpb_size;/* only v8 */ - void *d_mv_buffer_size; - void *d_first_plane_dpb; - void *d_second_plane_dpb; - void *d_third_plane_dpb; - void *d_mv_buffer; - void *d_scratch_buffer_addr; - void *d_scratch_buffer_size; - void *d_metadata_buffer_addr; - void *d_metadata_buffer_size; - void *d_nal_start_options;/* v7 and v8 */ - void *d_cpb_buffer_addr; - void *d_cpb_buffer_size; - void *d_available_dpb_flag_upper; - void *d_available_dpb_flag_lower; - void *d_cpb_buffer_offset; - void *d_slice_if_enable; - void *d_picture_tag; - void *d_stream_data_size; - void *d_dynamic_dpb_flag_upper;/* v7 and v8 */ - void *d_dynamic_dpb_flag_lower;/* v7 and v8 */ - void *d_display_frame_width; - void *d_display_frame_height; - void *d_display_status; - void *d_display_first_plane_addr; - void *d_display_second_plane_addr; - void *d_display_third_plane_addr;/* only v8 */ - void *d_display_frame_type; - void *d_display_crop_info1; - void *d_display_crop_info2; - void *d_display_picture_profile; - void *d_display_luma_crc;/* v7 and v8 */ - void *d_display_chroma0_crc;/* v7 and v8 */ - void *d_display_chroma1_crc;/* only v8 */ - void *d_display_luma_crc_top;/* only v6 */ - void *d_display_chroma_crc_top;/* only v6 */ - void *d_display_luma_crc_bot;/* only v6 */ - void *d_display_chroma_crc_bot;/* only v6 */ - void *d_display_aspect_ratio; - void *d_display_extended_ar; - void *d_decoded_frame_width; - void *d_decoded_frame_height; - void *d_decoded_status; - void *d_decoded_first_plane_addr; - void *d_decoded_second_plane_addr; - void *d_decoded_third_plane_addr;/* only v8 */ - void *d_decoded_frame_type; - void *d_decoded_crop_info1; - void *d_decoded_crop_info2; - void *d_decoded_picture_profile; - void *d_decoded_nal_size; - void *d_decoded_luma_crc; - void *d_decoded_chroma0_crc; - void *d_decoded_chroma1_crc;/* only v8 */ - void *d_ret_picture_tag_top; - void *d_ret_picture_tag_bot; - void *d_ret_picture_time_top; - void *d_ret_picture_time_bot; - void *d_chroma_format; - void *d_vc1_info;/* v7 and v8 */ - void *d_mpeg4_info; - void *d_h264_info; - void *d_metadata_addr_concealed_mb; - void *d_metadata_size_concealed_mb; - void *d_metadata_addr_vc1_param; - void *d_metadata_size_vc1_param; - void *d_metadata_addr_sei_nal; - void *d_metadata_size_sei_nal; - void *d_metadata_addr_vui; - void *d_metadata_size_vui; - void *d_metadata_addr_mvcvui;/* v7 and v8 */ - void *d_metadata_size_mvcvui;/* v7 and v8 */ - void *d_mvc_view_id; - void *d_frame_pack_sei_avail; - void *d_frame_pack_arrgment_id; - void *d_frame_pack_sei_info; - void *d_frame_pack_grid_pos; - void *d_display_recovery_sei_info;/* v7 and v8 */ - void *d_decoded_recovery_sei_info;/* v7 and v8 */ - void *d_display_first_addr;/* only v7 */ - void *d_display_second_addr;/* only v7 */ - void *d_display_third_addr;/* only v7 */ - void *d_decoded_first_addr;/* only v7 */ - void *d_decoded_second_addr;/* only v7 */ - void *d_decoded_third_addr;/* only v7 */ - void *d_used_dpb_flag_upper;/* v7 and v8 */ - void *d_used_dpb_flag_lower;/* v7 and v8 */ + volatile void __iomem *d_crc_ctrl; + volatile void __iomem *d_dec_options; + volatile void __iomem *d_display_delay; + volatile void __iomem *d_set_frame_width; + volatile void __iomem *d_set_frame_height; + volatile void __iomem *d_sei_enable; + volatile void __iomem *d_min_num_dpb; + volatile void __iomem *d_min_first_plane_dpb_size; + volatile void __iomem *d_min_second_plane_dpb_size; + volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */ + volatile void __iomem *d_min_num_mv; + volatile void __iomem *d_mvc_num_views; + volatile void __iomem *d_min_num_dis;/* only v7 */ + volatile void __iomem *d_min_first_dis_size;/* only v7 */ + volatile void __iomem *d_min_second_dis_size;/* only v7 */ + volatile void __iomem *d_min_third_dis_size;/* only v7 */ + volatile void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */ + volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */ + volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */ + volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */ + volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */ + volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */ + volatile void __iomem *d_num_dpb; + volatile void __iomem *d_num_mv; + volatile void __iomem *d_init_buffer_options; + volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */ + volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */ + volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */ + volatile void __iomem *d_first_plane_dpb_size; + volatile void __iomem *d_second_plane_dpb_size; + volatile void __iomem *d_third_plane_dpb_size;/* only v8 */ + volatile void __iomem *d_mv_buffer_size; + volatile void __iomem *d_first_plane_dpb; + volatile void __iomem *d_second_plane_dpb; + volatile void __iomem *d_third_plane_dpb; + volatile void __iomem *d_mv_buffer; + volatile void __iomem *d_scratch_buffer_addr; + volatile void __iomem *d_scratch_buffer_size; + volatile void __iomem *d_metadata_buffer_addr; + volatile void __iomem *d_metadata_buffer_size; + volatile void __iomem *d_nal_start_options;/* v7 and v8 */ + volatile void __iomem *d_cpb_buffer_addr; + volatile void __iomem *d_cpb_buffer_size; + volatile void __iomem *d_available_dpb_flag_upper; + volatile void __iomem *d_available_dpb_flag_lower; + volatile void __iomem *d_cpb_buffer_offset; + volatile void __iomem *d_slice_if_enable; + volatile void __iomem *d_picture_tag; + volatile void __iomem *d_stream_data_size; + volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */ + volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */ + volatile void __iomem *d_display_frame_width; + volatile void __iomem *d_display_frame_height; + volatile void __iomem *d_display_status; + volatile void __iomem *d_display_first_plane_addr; + volatile void __iomem *d_display_second_plane_addr; + volatile void __iomem *d_display_third_plane_addr;/* only v8 */ + volatile void __iomem *d_display_frame_type; + volatile void __iomem *d_display_crop_info1; + volatile void __iomem *d_display_crop_info2; + volatile void __iomem *d_display_picture_profile; + volatile void __iomem *d_display_luma_crc;/* v7 and v8 */ + volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */ + volatile void __iomem *d_display_chroma1_crc;/* only v8 */ + volatile void __iomem *d_display_luma_crc_top;/* only v6 */ + volatile void __iomem *d_display_chroma_crc_top;/* only v6 */ + volatile void __iomem *d_display_luma_crc_bot;/* only v6 */ + volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */ + volatile void __iomem *d_display_aspect_ratio; + volatile void __iomem *d_display_extended_ar; + volatile void __iomem *d_decoded_frame_width; + volatile void __iomem *d_decoded_frame_height; + volatile void __iomem *d_decoded_status; + volatile void __iomem *d_decoded_first_plane_addr; + volatile void __iomem *d_decoded_second_plane_addr; + volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */ + volatile void __iomem *d_decoded_frame_type; + volatile void __iomem *d_decoded_crop_info1; + volatile void __iomem *d_decoded_crop_info2; + volatile void __iomem *d_decoded_picture_profile; + volatile void __iomem *d_decoded_nal_size; + volatile void __iomem *d_decoded_luma_crc; + volatile void __iomem *d_decoded_chroma0_crc; + volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */ + volatile void __iomem *d_ret_picture_tag_top; + volatile void __iomem *d_ret_picture_tag_bot; + volatile void __iomem *d_ret_picture_time_top; + volatile void __iomem *d_ret_picture_time_bot; + volatile void __iomem *d_chroma_format; + volatile void __iomem *d_vc1_info;/* v7 and v8 */ + volatile void __iomem *d_mpeg4_info; + volatile void __iomem *d_h264_info; + volatile void __iomem *d_metadata_addr_concealed_mb; + volatile void __iomem *d_metadata_size_concealed_mb; + volatile void __iomem *d_metadata_addr_vc1_param; + volatile void __iomem *d_metadata_size_vc1_param; + volatile void __iomem *d_metadata_addr_sei_nal; + volatile void __iomem *d_metadata_size_sei_nal; + volatile void __iomem *d_metadata_addr_vui; + volatile void __iomem *d_metadata_size_vui; + volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */ + volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */ + volatile void __iomem *d_mvc_view_id; + volatile void __iomem *d_frame_pack_sei_avail; + volatile void __iomem *d_frame_pack_arrgment_id; + volatile void __iomem *d_frame_pack_sei_info; + volatile void __iomem *d_frame_pack_grid_pos; + volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */ + volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */ + volatile void __iomem *d_display_first_addr;/* only v7 */ + volatile void __iomem *d_display_second_addr;/* only v7 */ + volatile void __iomem *d_display_third_addr;/* only v7 */ + volatile void __iomem *d_decoded_first_addr;/* only v7 */ + volatile void __iomem *d_decoded_second_addr;/* only v7 */ + volatile void __iomem *d_decoded_third_addr;/* only v7 */ + volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ + volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ /* encoder registers */ - void *e_frame_width; - void *e_frame_height; - void *e_cropped_frame_width; - void *e_cropped_frame_height; - void *e_frame_crop_offset; - void *e_enc_options; - void *e_picture_profile; - void *e_vbv_buffer_size; - void *e_vbv_init_delay; - void *e_fixed_picture_qp; - void *e_rc_config; - void *e_rc_qp_bound; - void *e_rc_qp_bound_pb;/* v7 and v8 */ - void *e_rc_mode; - void *e_mb_rc_config; - void *e_padding_ctrl; - void *e_air_threshold; - void *e_mv_hor_range; - void *e_mv_ver_range; - void *e_num_dpb; - void *e_luma_dpb; - void *e_chroma_dpb; - void *e_me_buffer; - void *e_scratch_buffer_addr; - void *e_scratch_buffer_size; - void *e_tmv_buffer0; - void *e_tmv_buffer1; - void *e_ir_buffer_addr;/* v7 and v8 */ - void *e_source_first_plane_addr; - void *e_source_second_plane_addr; - void *e_source_third_plane_addr;/* v7 and v8 */ - void *e_source_first_plane_stride;/* v7 and v8 */ - void *e_source_second_plane_stride;/* v7 and v8 */ - void *e_source_third_plane_stride;/* v7 and v8 */ - void *e_stream_buffer_addr; - void *e_stream_buffer_size; - void *e_roi_buffer_addr; - void *e_param_change; - void *e_ir_size; - void *e_gop_config; - void *e_mslice_mode; - void *e_mslice_size_mb; - void *e_mslice_size_bits; - void *e_frame_insertion; - void *e_rc_frame_rate; - void *e_rc_bit_rate; - void *e_rc_roi_ctrl; - void *e_picture_tag; - void *e_bit_count_enable; - void *e_max_bit_count; - void *e_min_bit_count; - void *e_metadata_buffer_addr; - void *e_metadata_buffer_size; - void *e_encoded_source_first_plane_addr; - void *e_encoded_source_second_plane_addr; - void *e_encoded_source_third_plane_addr;/* v7 and v8 */ - void *e_stream_size; - void *e_slice_type; - void *e_picture_count; - void *e_ret_picture_tag; - void *e_stream_buffer_write_pointer; /* only v6 */ - void *e_recon_luma_dpb_addr; - void *e_recon_chroma_dpb_addr; - void *e_metadata_addr_enc_slice; - void *e_metadata_size_enc_slice; - void *e_mpeg4_options; - void *e_mpeg4_hec_period; - void *e_aspect_ratio; - void *e_extended_sar; - void *e_h264_options; - void *e_h264_options_2;/* v7 and v8 */ - void *e_h264_lf_alpha_offset; - void *e_h264_lf_beta_offset; - void *e_h264_i_period; - void *e_h264_fmo_slice_grp_map_type; - void *e_h264_fmo_num_slice_grp_minus1; - void *e_h264_fmo_slice_grp_change_dir; - void *e_h264_fmo_slice_grp_change_rate_minus1; - void *e_h264_fmo_run_length_minus1_0; - void *e_h264_aso_slice_order_0; - void *e_h264_chroma_qp_offset; - void *e_h264_num_t_layer; - void *e_h264_hierarchical_qp_layer0; - void *e_h264_frame_packing_sei_info; - void *e_h264_nal_control;/* v7 and v8 */ - void *e_mvc_frame_qp_view1; - void *e_mvc_rc_bit_rate_view1; - void *e_mvc_rc_qbound_view1; - void *e_mvc_rc_mode_view1; - void *e_mvc_inter_view_prediction_on; - void *e_vp8_options;/* v7 and v8 */ - void *e_vp8_filter_options;/* v7 and v8 */ - void *e_vp8_golden_frame_option;/* v7 and v8 */ - void *e_vp8_num_t_layer;/* v7 and v8 */ - void *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ - void *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ - void *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + volatile void __iomem *e_frame_width; + volatile void __iomem *e_frame_height; + volatile void __iomem *e_cropped_frame_width; + volatile void __iomem *e_cropped_frame_height; + volatile void __iomem *e_frame_crop_offset; + volatile void __iomem *e_enc_options; + volatile void __iomem *e_picture_profile; + volatile void __iomem *e_vbv_buffer_size; + volatile void __iomem *e_vbv_init_delay; + volatile void __iomem *e_fixed_picture_qp; + volatile void __iomem *e_rc_config; + volatile void __iomem *e_rc_qp_bound; + volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */ + volatile void __iomem *e_rc_mode; + volatile void __iomem *e_mb_rc_config; + volatile void __iomem *e_padding_ctrl; + volatile void __iomem *e_air_threshold; + volatile void __iomem *e_mv_hor_range; + volatile void __iomem *e_mv_ver_range; + volatile void __iomem *e_num_dpb; + volatile void __iomem *e_luma_dpb; + volatile void __iomem *e_chroma_dpb; + volatile void __iomem *e_me_buffer; + volatile void __iomem *e_scratch_buffer_addr; + volatile void __iomem *e_scratch_buffer_size; + volatile void __iomem *e_tmv_buffer0; + volatile void __iomem *e_tmv_buffer1; + volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */ + volatile void __iomem *e_source_first_plane_addr; + volatile void __iomem *e_source_second_plane_addr; + volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */ + volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */ + volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */ + volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */ + volatile void __iomem *e_stream_buffer_addr; + volatile void __iomem *e_stream_buffer_size; + volatile void __iomem *e_roi_buffer_addr; + volatile void __iomem *e_param_change; + volatile void __iomem *e_ir_size; + volatile void __iomem *e_gop_config; + volatile void __iomem *e_mslice_mode; + volatile void __iomem *e_mslice_size_mb; + volatile void __iomem *e_mslice_size_bits; + volatile void __iomem *e_frame_insertion; + volatile void __iomem *e_rc_frame_rate; + volatile void __iomem *e_rc_bit_rate; + volatile void __iomem *e_rc_roi_ctrl; + volatile void __iomem *e_picture_tag; + volatile void __iomem *e_bit_count_enable; + volatile void __iomem *e_max_bit_count; + volatile void __iomem *e_min_bit_count; + volatile void __iomem *e_metadata_buffer_addr; + volatile void __iomem *e_metadata_buffer_size; + volatile void __iomem *e_encoded_source_first_plane_addr; + volatile void __iomem *e_encoded_source_second_plane_addr; + volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */ + volatile void __iomem *e_stream_size; + volatile void __iomem *e_slice_type; + volatile void __iomem *e_picture_count; + volatile void __iomem *e_ret_picture_tag; + volatile void __iomem *e_stream_buffer_write_pointer; /* only v6 */ + volatile void __iomem *e_recon_luma_dpb_addr; + volatile void __iomem *e_recon_chroma_dpb_addr; + volatile void __iomem *e_metadata_addr_enc_slice; + volatile void __iomem *e_metadata_size_enc_slice; + volatile void __iomem *e_mpeg4_options; + volatile void __iomem *e_mpeg4_hec_period; + volatile void __iomem *e_aspect_ratio; + volatile void __iomem *e_extended_sar; + volatile void __iomem *e_h264_options; + volatile void __iomem *e_h264_options_2;/* v7 and v8 */ + volatile void __iomem *e_h264_lf_alpha_offset; + volatile void __iomem *e_h264_lf_beta_offset; + volatile void __iomem *e_h264_i_period; + volatile void __iomem *e_h264_fmo_slice_grp_map_type; + volatile void __iomem *e_h264_fmo_num_slice_grp_minus1; + volatile void __iomem *e_h264_fmo_slice_grp_change_dir; + volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1; + volatile void __iomem *e_h264_fmo_run_length_minus1_0; + volatile void __iomem *e_h264_aso_slice_order_0; + volatile void __iomem *e_h264_chroma_qp_offset; + volatile void __iomem *e_h264_num_t_layer; + volatile void __iomem *e_h264_hierarchical_qp_layer0; + volatile void __iomem *e_h264_frame_packing_sei_info; + volatile void __iomem *e_h264_nal_control;/* v7 and v8 */ + volatile void __iomem *e_mvc_frame_qp_view1; + volatile void __iomem *e_mvc_rc_bit_rate_view1; + volatile void __iomem *e_mvc_rc_qbound_view1; + volatile void __iomem *e_mvc_rc_mode_view1; + volatile void __iomem *e_mvc_inter_view_prediction_on; + volatile void __iomem *e_vp8_options;/* v7 and v8 */ + volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */ + volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */ + volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */ + volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ + volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ + volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ }; struct s5p_mfc_hw_ops { 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 e9d1eaf72682..ed3d20f12184 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1880,7 +1880,7 @@ static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { s5p_mfc_clock_on(); - writel(data, (void *)ofs); + writel(data, (volatile void __iomem *)ofs); s5p_mfc_clock_off(); } @@ -1890,7 +1890,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) int ret; s5p_mfc_clock_on(); - ret = readl((void *)ofs); + ret = readl((volatile void __iomem *)ofs); s5p_mfc_clock_off(); return ret; -- cgit v1.2.3 From dc11ef78e78b65fccae91ed42b05a039ddde7a9d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:34:47 -0300 Subject: [media] s5p_mfc_opr_v6: remove address space removal warnings Smatch still has 3 warnings for s5p_mfc_opr_v6: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2028:18: warning: cast removes address space of expression drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2034:18: warning: cast removes address space of expression drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2040:18: warning: cast removes address space of expression Remove them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 ed3d20f12184..e38d78f21726 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -2019,25 +2019,25 @@ static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top); + (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top); } static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot); + (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot); } static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (unsigned int) ctx->dev->mfc_regs->d_display_crop_info1); + (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info1); } static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (unsigned int) ctx->dev->mfc_regs->d_display_crop_info2); + (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info2); } static struct s5p_mfc_regs mfc_regs; -- cgit v1.2.3 From 5c2cacc1028917168b0f7650008dceaa6f7e3fe2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:47:27 -0300 Subject: [media] v4l2-dv-timings: fix a sparse warning This is detected with: gcc-4.8.3-7.fc20.x86_64 sparse-0.5.0-3.fc20.x86_64 drivers/media/v4l2-core/v4l2-dv-timings.c:34:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:35:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:36:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:37:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:38:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:39:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:40:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:41:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:42:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:43:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:44:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:45:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:46:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:47:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:48:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:49:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:50:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:51:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:52:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:53:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:54:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:55:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:56:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:57:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:58:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:59:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:60:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:61:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:62:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:63:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:64:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:65:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:66:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:67:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:68:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:69:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:70:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:71:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:72:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:73:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:74:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:75:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:76:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:77:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:78:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:79:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:80:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:81:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:82:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:83:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:84:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:85:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:86:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:87:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:88:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:89:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:90:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:91:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:92:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:93:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:94:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:95:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:96:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:97:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:98:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:99:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:100:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:101:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:102:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:103:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:104:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:105:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:106:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:107:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:108:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:109:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:110:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:111:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:112:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:113:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:114:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:115:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:116:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:117:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:118:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:119:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:120:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:121:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:122:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:123:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:124:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:125:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:126:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:127:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:128:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:129:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:130:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:131:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:132:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:133:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:134:9: error: unknown field name in initializer drivers/media/v4l2-core/v4l2-dv-timings.c:135:9: error: too many errors drivers/media/usb/hdpvr/hdpvr-video.c:42:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:43:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:44:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:45:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:46:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:47:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:48:9: error: unknown field name in initializer drivers/media/usb/hdpvr/hdpvr-video.c:49:9: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:484:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:485:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:486:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:487:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:488:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:489:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:490:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:491:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:492:18: error: unknown field name in initializer drivers/media/platform/s5p-tv/hdmi_drv.c:493:18: error: unknown field name in initializer Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-dv-timings.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 6c8f159e416e..6a0764c89fcb 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -21,17 +21,8 @@ #ifndef _V4L2_DV_TIMINGS_H #define _V4L2_DV_TIMINGS_H -#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6)) -/* Sadly gcc versions older than 4.6 have a bug in how they initialize - anonymous unions where they require additional curly brackets. - This violates the C1x standard. This workaround adds the curly brackets - if needed. */ #define V4L2_INIT_BT_TIMINGS(_width, args...) \ { .bt = { _width , ## args } } -#else -#define V4L2_INIT_BT_TIMINGS(_width, args...) \ - .bt = { _width , ## args } -#endif /* CEA-861-E timings (i.e. standard HDTV timings) */ -- cgit v1.2.3 From 289297b9a33d4de9644c422c0cf6349387af8ad3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 09:59:02 -0300 Subject: [media] as102_drv.h: added a missing newline drivers/media/usb/as102/as102_drv.h:83:6: warning: no newline at end of file Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index 9430d30163a3..aee2d76e8dfc 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -80,4 +80,4 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From 71d1b2bec07c8aec4252111a84699273f50fdc52 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 10:15:22 -0300 Subject: [media] dvb_frontend: Fix __user namespace As reported by smatch: drivers/media/dvb-core/dvb_frontend.c:1960:45: warning: incorrect type in argument 2 (different address spaces) drivers/media/dvb-core/dvb_frontend.c:1960:45: expected void const [noderef] *from drivers/media/dvb-core/dvb_frontend.c:1960:45: got struct dtv_property *[noderef] props drivers/media/dvb-core/dvb_frontend.c:1992:45: warning: incorrect type in argument 2 (different address spaces) drivers/media/dvb-core/dvb_frontend.c:1992:45: expected void const [noderef] *from drivers/media/dvb-core/dvb_frontend.c:1992:45: got struct dtv_property *[noderef] props drivers/media/dvb-core/dvb_frontend.c:2014:38: warning: incorrect type in argument 1 (different address spaces) drivers/media/dvb-core/dvb_frontend.c:2014:38: expected void [noderef] *to drivers/media/dvb-core/dvb_frontend.c:2014:38: got struct dtv_property *[noderef] props drivers/media/dvb-core/dvb_frontend.c:1946:17: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1947:17: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1951:22: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1951:42: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1954:31: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1960:41: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1960:54: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1965:33: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1978:17: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1979:17: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1983:22: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1983:42: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1986:31: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1992:41: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:1992:54: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:2007:33: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:2014:34: warning: dereference of noderef expression drivers/media/dvb-core/dvb_frontend.c:2014:52: warning: dereference of noderef expression Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index c862ad732d9e..b8579ee68bd6 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1934,15 +1934,13 @@ static int dvb_frontend_ioctl_properties(struct file *file, struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; - struct dtv_properties *tvps = NULL; + struct dtv_properties *tvps = parg; struct dtv_property *tvp = NULL; int i; dev_dbg(fe->dvb->device, "%s:\n", __func__); - if(cmd == FE_SET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; - + if (cmd == FE_SET_PROPERTY) { dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); @@ -1957,7 +1955,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + if (copy_from_user(tvp, (void __user *)tvps->props, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } @@ -1972,10 +1971,7 @@ static int dvb_frontend_ioctl_properties(struct file *file, if (c->state == DTV_TUNE) dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - } else - if(cmd == FE_GET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; - + } else if (cmd == FE_GET_PROPERTY) { dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); @@ -1990,7 +1986,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + if (copy_from_user(tvp, (void __user *)tvps->props, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } @@ -2012,7 +2009,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, (tvp + i)->result = err; } - if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } -- cgit v1.2.3 From d51a12c962f26fcb859203372fa196c2dfcd5f77 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 10:51:35 -0300 Subject: [media] as102: fix endiannes casts Smatch complains a lot about endiannes issues on as102: drivers/media/usb/as102/as10x_cmd_stream.c:41:47: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:41:47: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_stream.c:41:47: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_stream.c:43:43: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:43:43: expected unsigned short [unsigned] [usertype] pid drivers/media/usb/as102/as10x_cmd_stream.c:43:43: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_stream.c:98:47: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:98:47: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_stream.c:98:47: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_stream.c:100:43: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:100:43: expected unsigned short [unsigned] [usertype] pid drivers/media/usb/as102/as10x_cmd_stream.c:100:43: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_stream.c:142:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:142:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_stream.c:142:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_stream.c:185:47: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_stream.c:185:47: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_stream.c:185:47: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:46:40: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:46:40: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_cfg.c:46:40: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:47:36: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:47:36: expected unsigned short [unsigned] [usertype] tag drivers/media/usb/as102/as10x_cmd_cfg.c:47:36: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:48:37: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:48:37: expected unsigned short [unsigned] [usertype] type drivers/media/usb/as102/as10x_cmd_cfg.c:48:37: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:72:27: warning: cast to restricted __le32 drivers/media/usb/as102/as10x_cmd_cfg.c:102:40: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:102:40: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_cfg.c:102:40: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:104:50: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:104:50: expected unsigned int [unsigned] [usertype] value32 drivers/media/usb/as102/as10x_cmd_cfg.c:104:50: got restricted __le32 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:105:36: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:105:36: expected unsigned short [unsigned] [usertype] tag drivers/media/usb/as102/as10x_cmd_cfg.c:105:36: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:106:37: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:106:37: expected unsigned short [unsigned] [usertype] type drivers/media/usb/as102/as10x_cmd_cfg.c:106:37: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:156:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd_cfg.c:156:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd_cfg.c:156:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd_cfg.c:197:14: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:40:40: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:40:40: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:40:40: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:81:41: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:81:41: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:81:41: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:123:41: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:123:41: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:123:41: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:124:43: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:124:43: expected unsigned int [unsigned] [usertype] freq drivers/media/usb/as102/as10x_cmd.c:124:43: got restricted __le32 [usertype] drivers/media/usb/as102/as10x_cmd.c:178:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:178:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:178:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:202:17: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:203:24: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:204:24: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:230:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:230:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:230:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:262:25: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:289:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:289:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:289:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:313:17: warning: cast to restricted __le32 drivers/media/usb/as102/as10x_cmd.c:315:17: warning: cast to restricted __le32 drivers/media/usb/as102/as10x_cmd.c:317:17: warning: cast to restricted __le32 drivers/media/usb/as102/as10x_cmd.c:319:17: warning: cast to restricted __le16 drivers/media/usb/as102/as10x_cmd.c:349:48: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:349:48: expected unsigned short [unsigned] [usertype] proc_id drivers/media/usb/as102/as10x_cmd.c:349:48: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:387:29: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:387:29: expected unsigned short [unsigned] [usertype] req_id drivers/media/usb/as102/as10x_cmd.c:387:29: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:388:27: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:388:27: expected unsigned short [unsigned] [usertype] prog drivers/media/usb/as102/as10x_cmd.c:388:27: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:389:30: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:389:30: expected unsigned short [unsigned] [usertype] version drivers/media/usb/as102/as10x_cmd.c:389:30: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:390:31: warning: incorrect type in assignment (different base types) drivers/media/usb/as102/as10x_cmd.c:390:31: expected unsigned short [unsigned] [usertype] data_len drivers/media/usb/as102/as10x_cmd.c:390:31: got restricted __le16 [usertype] drivers/media/usb/as102/as10x_cmd.c:408:14: warning: cast to restricted __le16 This happens because of the command endiannes that are sent/received to the firmware. So, add the correct endiannes tags to the command fields. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as10x_cmd.c | 18 +++--- drivers/media/usb/as102/as10x_cmd.h | 100 ++++++++++++++++---------------- drivers/media/usb/as102/as10x_cmd_cfg.c | 4 +- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c index ef238022dfe5..870617994410 100644 --- a/drivers/media/usb/as102/as10x_cmd.c +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -121,7 +121,7 @@ int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, /* fill command */ preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); - preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); + preq->body.set_tune.req.args.freq = (__force __u32)cpu_to_le32(ptune->freq); preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; preq->body.set_tune.req.args.hier_select = ptune->hier_select; preq->body.set_tune.req.args.modulation = ptune->modulation; @@ -199,9 +199,9 @@ int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, /* Response OK -> get response data */ pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; pstatus->signal_strength = - le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); - pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); - pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); + le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.signal_strength); + pstatus->PER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.PER); + pstatus->BER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.BER); out: return error; @@ -259,7 +259,7 @@ int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; - ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); + ptps->cell_ID = le16_to_cpu((__force __le16)prsp->body.get_tps.rsp.tps.cell_ID); out: return error; @@ -310,13 +310,13 @@ int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, /* Response OK -> get response data */ pdemod_stats->frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); + le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.frame_count); pdemod_stats->bad_frame_count = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); + le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bad_frame_count); pdemod_stats->bytes_fixed_by_rs = - le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); + le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); pdemod_stats->mer = - le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); + le16_to_cpu((__force __le16)prsp->body.get_demod_stats.rsp.stats.mer); pdemod_stats->has_started = prsp->body.get_demod_stats.rsp.stats.has_started; diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index 09134f73ba3d..e06b84e2ff79 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -92,12 +92,12 @@ union as10x_turn_on { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; } __packed rsp; @@ -107,12 +107,12 @@ union as10x_turn_off { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t err; } __packed rsp; @@ -122,14 +122,14 @@ union as10x_set_tune { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* tune params */ struct as10x_tune_args args; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; } __packed rsp; @@ -139,12 +139,12 @@ union as10x_get_tune_status { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; /* tune status */ @@ -156,12 +156,12 @@ union as10x_get_tps { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; /* tps details */ @@ -173,12 +173,12 @@ union as10x_common { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; } __packed rsp; @@ -188,9 +188,9 @@ union as10x_add_pid_filter { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* PID to filter */ - uint16_t pid; + __le16 pid; /* stream type (MPE, PSI/SI or PES )*/ uint8_t stream_type; /* PID index in filter table */ @@ -199,7 +199,7 @@ union as10x_add_pid_filter { /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; /* Filter id */ @@ -211,14 +211,14 @@ union as10x_del_pid_filter { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* PID to remove */ - uint16_t pid; + __le16 pid; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* response error */ uint8_t error; } __packed rsp; @@ -228,12 +228,12 @@ union as10x_start_streaming { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; } __packed rsp; @@ -243,12 +243,12 @@ union as10x_stop_streaming { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; } __packed rsp; @@ -258,12 +258,12 @@ union as10x_get_demod_stats { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; /* demod stats */ @@ -275,12 +275,12 @@ union as10x_get_impulse_resp { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; /* impulse response ready */ @@ -292,22 +292,22 @@ union as10x_fw_context { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* value to write (for set context)*/ struct as10x_register_value reg_val; /* context tag */ - uint16_t tag; + __le16 tag; /* context request type */ - uint16_t type; + __le16 type; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* value read (for get context) */ struct as10x_register_value reg_val; /* context request type */ - uint16_t type; + __le16 type; /* error */ uint8_t error; } __packed rsp; @@ -317,7 +317,7 @@ union as10x_set_register { /* request */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* register description */ struct as10x_register_addr reg_addr; /* register content */ @@ -326,7 +326,7 @@ union as10x_set_register { /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; } __packed rsp; @@ -336,14 +336,14 @@ union as10x_get_register { /* request */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* register description */ struct as10x_register_addr reg_addr; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; /* register content */ @@ -355,24 +355,24 @@ union as10x_cfg_change_mode { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* mode */ uint8_t mode; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; } __packed rsp; } __packed; struct as10x_cmd_header_t { - uint16_t req_id; - uint16_t prog; - uint16_t version; - uint16_t data_len; + __le16 req_id; + __le16 prog; + __le16 version; + __le16 data_len; } __packed; #define DUMP_BLOCK_SIZE 16 @@ -381,18 +381,18 @@ union as10x_dump_memory { /* request */ struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* dump memory type request */ uint8_t dump_req; /* register description */ struct as10x_register_addr reg_addr; /* nb blocks to read */ - uint16_t num_blocks; + __le16 num_blocks; } __packed req; /* response */ struct { /* response identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; /* dump response */ @@ -400,8 +400,8 @@ union as10x_dump_memory { /* data */ union { uint8_t data8[DUMP_BLOCK_SIZE]; - uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; - uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; + __le16 data16[DUMP_BLOCK_SIZE / sizeof(__le16)]; + __le32 data32[DUMP_BLOCK_SIZE / sizeof(__le32)]; } __packed u; } __packed rsp; } __packed; @@ -409,13 +409,13 @@ union as10x_dump_memory { union as10x_dumplog_memory { struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* dump memory type request */ uint8_t dump_req; } __packed req; struct { /* request identifier */ - uint16_t proc_id; + __le16 proc_id; /* error */ uint8_t error; /* dump response */ @@ -428,13 +428,13 @@ union as10x_dumplog_memory { union as10x_raw_data { /* request */ struct { - uint16_t proc_id; + __le16 proc_id; uint8_t data[64 - sizeof(struct as10x_cmd_header_t) - 2 /* proc_id */]; } __packed req; /* response */ struct { - uint16_t proc_id; + __le16 proc_id; uint8_t error; uint8_t data[64 - sizeof(struct as10x_cmd_header_t) - 2 /* proc_id */ - 1 /* rc */]; diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c index 6f9dea1d860b..c87f2ca223a2 100644 --- a/drivers/media/usb/as102/as10x_cmd_cfg.c +++ b/drivers/media/usb/as102/as10x_cmd_cfg.c @@ -69,7 +69,7 @@ int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, if (error == 0) { /* Response OK -> get response data */ - *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); + *pvalue = le32_to_cpu((__force __le32)prsp->body.context.rsp.reg_val.u.value32); /* value returned is always a 32-bit value */ } @@ -101,7 +101,7 @@ int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, /* fill command */ pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); /* pcmd->body.context.req.reg_val.mode initialization is not required */ - pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); + pcmd->body.context.req.reg_val.u.value32 = (__force u32)cpu_to_le32(value); pcmd->body.context.req.tag = cpu_to_le16(tag); pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); -- cgit v1.2.3 From 7f01308e543f33a977750bf464ae6bf3f9733cf0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 11:07:31 -0300 Subject: [media] ir-hix5hd2: fix address space casting drivers/media/rc/ir-hix5hd2.c:99:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:99:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:99:41: got void * drivers/media/rc/ir-hix5hd2.c:100:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:100:16: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:100:16: got void * drivers/media/rc/ir-hix5hd2.c:117:40: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:117:40: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:117:40: got void * drivers/media/rc/ir-hix5hd2.c:119:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:119:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:119:41: got void * drivers/media/rc/ir-hix5hd2.c:121:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:121:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:121:41: got void * drivers/media/rc/ir-hix5hd2.c:147:18: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:147:18: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:147:18: got void * drivers/media/rc/ir-hix5hd2.c:155:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:155:28: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:155:28: got void * drivers/media/rc/ir-hix5hd2.c:157:25: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:157:25: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:157:25: got void * drivers/media/rc/ir-hix5hd2.c:159:61: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:159:61: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:159:61: got void * drivers/media/rc/ir-hix5hd2.c:167:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:167:28: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:167:28: got void * drivers/media/rc/ir-hix5hd2.c:169:36: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/ir-hix5hd2.c:169:36: expected void const volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:169:36: got void * drivers/media/rc/ir-hix5hd2.c:188:64: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:188:64: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:188:64: got void * drivers/media/rc/ir-hix5hd2.c:190:68: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:190:68: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:190:68: got void * drivers/media/rc/ir-hix5hd2.c:220:20: warning: incorrect type in assignment (different address spaces) drivers/media/rc/ir-hix5hd2.c:220:20: expected void *base drivers/media/rc/ir-hix5hd2.c:220:20: got void [noderef] * drivers/media/rc/ir-hix5hd2.c:315:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:315:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:315:41: got void * drivers/media/rc/ir-hix5hd2.c:316:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:316:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:316:41: got void * drivers/media/rc/ir-hix5hd2.c:317:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:317:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:317:41: got void * drivers/media/rc/ir-hix5hd2.c:318:41: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/ir-hix5hd2.c:318:41: expected void volatile [noderef] *addr drivers/media/rc/ir-hix5hd2.c:318:41: got void * Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-hix5hd2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 94967d0e0478..c555ca2aed0e 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -68,7 +68,7 @@ struct hix5hd2_ir_priv { int irq; - void *base; + void volatile __iomem *base; struct device *dev; struct rc_dev *rdev; struct regmap *regmap; @@ -218,8 +218,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); + if (IS_ERR((__force void *)priv->base)) + return PTR_ERR((__force void *)priv->base); priv->irq = platform_get_irq(pdev, 0); if (priv->irq < 0) { -- cgit v1.2.3 From 8f8218e89d5500f5d53556a3e0739d1ffc591aa1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 11:11:44 -0300 Subject: [media] st_rc: fix address space casting drivers/media/rc/st_rc.c:107:38: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/st_rc.c:107:38: expected void const volatile [noderef] *addr drivers/media/rc/st_rc.c:107:38: got void * drivers/media/rc/st_rc.c:110:53: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/st_rc.c:110:53: expected void const volatile [noderef] *addr drivers/media/rc/st_rc.c:110:53: got void * drivers/media/rc/st_rc.c:116:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:116:54: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:116:54: got void * drivers/media/rc/st_rc.c:120:45: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/st_rc.c:120:45: expected void const volatile [noderef] *addr drivers/media/rc/st_rc.c:120:45: got void * drivers/media/rc/st_rc.c:121:43: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/st_rc.c:121:43: expected void const volatile [noderef] *addr drivers/media/rc/st_rc.c:121:43: got void * drivers/media/rc/st_rc.c:150:46: warning: incorrect type in argument 1 (different address spaces) drivers/media/rc/st_rc.c:150:46: expected void const volatile [noderef] *addr drivers/media/rc/st_rc.c:150:46: got void * drivers/media/rc/st_rc.c:153:42: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:153:42: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:153:42: got void * drivers/media/rc/st_rc.c:174:32: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:174:32: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:174:32: got void * drivers/media/rc/st_rc.c:177:48: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:177:48: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:177:48: got void * drivers/media/rc/st_rc.c:187:48: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:187:48: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:187:48: got void * drivers/media/rc/st_rc.c:204:42: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:204:42: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:204:42: got void * drivers/media/rc/st_rc.c:205:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:205:35: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:205:35: got void * drivers/media/rc/st_rc.c:215:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:215:35: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:215:35: got void * drivers/media/rc/st_rc.c:216:35: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:216:35: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:216:35: got void * drivers/media/rc/st_rc.c:269:22: warning: incorrect type in assignment (different address spaces) drivers/media/rc/st_rc.c:269:22: expected void *base drivers/media/rc/st_rc.c:269:22: got void [noderef] * drivers/media/rc/st_rc.c:349:46: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:349:46: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:349:46: got void * drivers/media/rc/st_rc.c:350:46: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:350:46: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:350:46: got void * drivers/media/rc/st_rc.c:371:61: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:371:61: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:371:61: got void * drivers/media/rc/st_rc.c:372:54: warning: incorrect type in argument 2 (different address spaces) drivers/media/rc/st_rc.c:372:54: expected void volatile [noderef] *addr drivers/media/rc/st_rc.c:372:54: got void * Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/st_rc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index e309441a266d..0e758ae2e529 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -22,8 +22,8 @@ struct st_rc_device { int irq; int irq_wake; struct clk *sys_clock; - void *base; /* Register base address */ - void *rx_base;/* RX Register base address */ + volatile void __iomem *base; /* Register base address */ + volatile void __iomem *rx_base;/* RX Register base address */ struct rc_dev *rdev; bool overclocking; int sample_mult; @@ -267,8 +267,8 @@ static int st_rc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rc_dev->base = devm_ioremap_resource(dev, res); - if (IS_ERR(rc_dev->base)) { - ret = PTR_ERR(rc_dev->base); + if (IS_ERR((__force void *)rc_dev->base)) { + ret = PTR_ERR((__force void *)rc_dev->base); goto err; } -- cgit v1.2.3 From 87f4ebcd0693f6de14f60cf7bf9821a005b5850f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 11:17:06 -0300 Subject: [media] sta2x11_vip: fix address space casting drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: got void volatile [noderef] *iomem drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: got void volatile [noderef] *iomem drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/sta2x11/sta2x11_vip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 365bd21301ba..22450f583da1 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -152,7 +152,7 @@ struct sta2x11_vip { int tcount, bcount; int overflow; - void *iomem; /* I/O Memory */ + void __iomem *iomem; /* I/O Memory */ struct vip_config *config; }; -- cgit v1.2.3 From 5a9ff85dc176e80c6fb7067dcb807c5e3ff7a913 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 14:06:25 -0300 Subject: [media] saa7164-core: declare symbols as static Those symbols are used only at saa7164-core. drivers/media/pci/saa7164/saa7164-core.c:55:14: warning: symbol 'fw_debug' was not declared. Should it be static? drivers/media/pci/saa7164/saa7164-core.c:75:14: warning: symbol 'print_histogram' was not declared. Should it be static? drivers/media/pci/saa7164/saa7164-core.c:83:14: warning: symbol 'guard_checking' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 1bf06970ca3e..cc1be8a7a451 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -52,7 +52,7 @@ unsigned int saa_debug; module_param_named(debug, saa_debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); -unsigned int fw_debug; +static unsigned int fw_debug; module_param(fw_debug, int, 0644); MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2"); @@ -72,7 +72,7 @@ static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -unsigned int print_histogram = 64; +static unsigned int print_histogram = 64; module_param(print_histogram, int, 0644); MODULE_PARM_DESC(print_histogram, "print histogram values once"); @@ -80,7 +80,7 @@ unsigned int crc_checking = 1; module_param(crc_checking, int, 0644); MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers"); -unsigned int guard_checking = 1; +static unsigned int guard_checking = 1; module_param(guard_checking, int, 0644); MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns"); -- cgit v1.2.3 From 64e01cbd9d3e22e38eadeff9e0d251d0d7d1c9d2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 15:35:55 -0300 Subject: [media] pms: Fix a bad usage of the stack As warned by smatch: drivers/media/parport/pms.c:632:21: warning: Variable length array is used. The pms driver is doing something really bad: it is using the stack to read data into a buffer whose size is given by the user by the read() syscall. Replace it by a dynamically allocated buffer. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/parport/pms.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c index 9bc105b3db1b..e6b497528cea 100644 --- a/drivers/media/parport/pms.c +++ b/drivers/media/parport/pms.c @@ -629,11 +629,15 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) { int y; int dw = 2 * dev->width; - char tmp[dw + 32]; /* using a temp buffer is faster than direct */ + char *tmp; /* using a temp buffer is faster than direct */ int cnt = 0; int len = 0; unsigned char r8 = 0x5; /* value for reg8 */ + tmp = kmalloc(dw + 32, GFP_KERNEL); + if (!tmp) + return 0; + if (rgb555) r8 |= 0x20; /* else use untranslated rgb = 565 */ mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */ @@ -664,6 +668,7 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) len += dt; } } + kfree(tmp); return len; } -- cgit v1.2.3 From 24c8f11f8bce5a959d04f887179b0f1ec43e1c33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 15:42:11 -0300 Subject: [media] radio-sf16fmi: declare pnp_attached as static drivers/media/radio/radio-sf16fmi.c:59:6: warning: symbol 'pnp_attached' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-sf16fmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index bcd0946c84a5..28a89466cddc 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -56,7 +56,7 @@ struct fmi static struct fmi fmi_card; static struct pnp_dev *dev; -bool pnp_attached; +static bool pnp_attached; #define RSF16_MINFREQ (87U * 16000) #define RSF16_MAXFREQ (108U * 16000) -- cgit v1.2.3 From 25fb62b61bc5485a95988d3ecfd672b48f4bf6e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 15:44:08 -0300 Subject: [media] radio-sf16fmr2: declare some structs as static drivers/media/radio/radio-sf16fmr2.c:308:19: warning: symbol 'fmr2_isa_driver' was not declared. Should it be static? drivers/media/radio/radio-sf16fmr2.c:316:19: warning: symbol 'fmr2_pnp_driver' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-sf16fmr2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 93d864eb8306..b8d61cbc18cb 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -305,7 +305,7 @@ static void fmr2_pnp_remove(struct pnp_dev *pdev) pnp_set_drvdata(pdev, NULL); } -struct isa_driver fmr2_isa_driver = { +static struct isa_driver fmr2_isa_driver = { .match = fmr2_isa_match, .remove = fmr2_isa_remove, .driver = { @@ -313,7 +313,7 @@ struct isa_driver fmr2_isa_driver = { }, }; -struct pnp_driver fmr2_pnp_driver = { +static struct pnp_driver fmr2_pnp_driver = { .name = "radio-sf16fmr2", .id_table = fmr2_pnp_ids, .probe = fmr2_pnp_probe, -- cgit v1.2.3 From e2392d347e1dbb4987beaaee0f87653480fcddc8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 15:49:50 -0300 Subject: [media] cx88: fix cards table CodingStyle This is actually a coding style issue, but it was generating lots of smatch warnings: drivers/media/pci/cx88/cx88-cards.c:1513:37: warning: Initializer entry defined twice drivers/media/pci/cx88/cx88-cards.c:1517:19: also defined here drivers/media/pci/cx88/cx88-cards.c:1533:36: warning: Initializer entry defined twice drivers/media/pci/cx88/cx88-cards.c:1538:19: also defined here ... Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-cards.c | 632 ++++++++++++++++++------------------ 1 file changed, 316 insertions(+), 316 deletions(-) diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index e18a7ace08b1..851754bf1291 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE3, .vmux = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE4, .vmux = 3, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE] = { .name = "Hauppauge WinTV 34xxx models", @@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xff02, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff01, @@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PIXELVIEW] = { .name = "PixelView", @@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff10, @@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x03ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03fe, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03fe, - }}, + } }, }, [CX88_BOARD_WINFAST2000XP_EXPERT] = { .name = "Leadtek Winfast 2000XP Expert", @@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00F5e700, .gpio1 = 0x00003004, .gpio2 = 0x00F5e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00F5d700, @@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio1 = 0xe09f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio1 = 0xe05f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio1 = 0xe05f, - }}, + } }, .radio = { .gpio1 = 0xe0df, .type = CX88_RADIO, @@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 3, @@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0035e700, .gpio1 = 0x00003004, .gpio2 = 0x0035e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x00003004, .gpio2 = 0x0035c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0035c700, .gpio1 = 0x0035c700, .gpio2 = 0x02000000, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0035d700, @@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, @@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PROLINK_PLAYTVPVR] = { .name = "Prolink PlayTV PVR", @@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbff0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbff3, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbff3, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbff0, @@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000fde6, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000fde2, @@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc08, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - }}, + } }, }, [CX88_BOARD_KWORLD_DVB_T] = { .name = "KWorld/VStream XPert DVB-T", @@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { @@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_LTV883] = { @@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x07f8, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0x07f9, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000007fa, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000007fa, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x000007f8, @@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = { 0 - normal RF 1 - high RF */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0f0d, - },{ + }, { .type = CX88_VMUX_CABLE, .vmux = 0, .gpio0 = 0x0f05, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0f00, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0f00, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_DVB_T1] = { @@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_CONEXANT_DVB_T1] = { @@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PROVIDEO_PV259] = { @@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .audioroute = 1, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { @@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DNTV_LIVE_DVB_T] = { @@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD3000] = { @@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = { * * GPIO[16] = Remote control input */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00008404, @@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xed1a, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xed92, .gpio2 = 0x00ff, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xed96, @@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, @@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 1, .gpio1 = 0x0000e03f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, .gpio1 = 0x0000e07f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 3, .gpio1 = 0x0000e07f, - }} + } } }, [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = { .name = "PixelView PlayTV Ultra Pro (Stereo)", @@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, /* Some variants use a tda9874 and so need the tvaudio module. */ .audio_chip = CX88_AUDIO_TVAUDIO, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbf61, /* internal decoder */ - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbf63, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbf63, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbf60, @@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x97ed, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x97e9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x97e9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_ADSTECH_DVB_T_PCI] = { @@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { .name = "TerraTec Cinergy 1400 DVB-T", .tuner_type = TUNER_ABSENT, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = { @@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = { @@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 2, @@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = { /* Alexander Wold */ .name = "Kworld V-Stream Xpert DVD", .tuner_type = UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - }}, + } }, }, [CX88_BOARD_ATI_HDTVWONDER] = { .name = "ATI HDTV Wonder", @@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000ff7, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_WINFAST_DTV1000] = { @@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERTV_303] = { @@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00ff, .gpio1 = 0xe09f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { .name = "Hauppauge Nova-S-Plus DVB-S", @@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, .i2sinputcntl = 2, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { @@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_DVBS_100] = { @@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR1100] = { @@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xf80808, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xf80808, @@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = { @@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000067df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000067df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { @@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x3de2, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x3de6, @@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000a75f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000a75b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000a75b, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD5500] = { @@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_MCE200_DELUXE] = { @@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000BDE6 - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = { @@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x5da6, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = { @@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0788, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x078b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x078b, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x074a, @@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017304, @@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x0000b207, .gpio2 = 0x0001d701, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00015702, @@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017300, .gpio1 = 0x00008207, .gpio2 = 0x00000000, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00018300, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00018301, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00018301, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00015702, @@ -1360,13 +1360,13 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR3000] = { @@ -1377,25 +1377,25 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .audio_chip = CX88_AUDIO_WM8775, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x84bf, /* 1: TV Audio / FM Mono */ .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x84bf, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x84bf, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x84bf, @@ -1411,19 +1411,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0709, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x070b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x070b, - }}, + } }, }, [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", @@ -1431,28 +1431,28 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE_HVR1300] = { .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", @@ -1465,25 +1465,25 @@ static const struct cx88_board cx88_boards[] = { /* * gpio0 as reported by Mike Crash */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xef88, /* 1: TV Audio / FM Mono */ .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xef88, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xef88, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, .radio = { .type = CX88_RADIO, @@ -1510,19 +1510,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DEBUG, .vmux = 3, .gpio0 = 0x04ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x07fa, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x07fa, - }}, + } }, }, [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { .name = "Pinnacle PCTV HD 800i", @@ -1530,24 +1530,24 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x04fb, .gpio1 = 0x10ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x04fb, .gpio1 = 0x10ef, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x04fb, .gpio1 = 0x10ef, .audioroute = 1, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = { @@ -1557,7 +1557,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x000027df, /* Unconfirmed */ @@ -1815,19 +1815,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x10df, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x16d9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x16d9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PROLINK_PV_8000GT] = { @@ -1967,7 +1967,7 @@ static const struct cx88_board cx88_boards[] = { * 3: Line-In Expansion * 4: FM Stereo */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xc4bf, @@ -2001,7 +2001,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2013,7 +2013,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2025,7 +2025,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2037,7 +2037,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2049,7 +2049,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2061,7 +2061,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2073,7 +2073,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, .gpio0 = 0x8080, @@ -2086,7 +2086,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2098,7 +2098,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2110,7 +2110,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2170,7 +2170,7 @@ static const struct cx88_board cx88_boards[] = { * 13: audio source (0=tuner audio,1=line in) * 14: FM (0=on,1=off ???) */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2211,7 +2211,7 @@ static const struct cx88_board cx88_boards[] = { * 13: audio source (0=tuner audio,1=line in) * 14: FM (0=on,1=off ???) */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2229,7 +2229,7 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x0400, /* pin 2 = 0 */ .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ .gpio2 = 0x0000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2252,7 +2252,7 @@ static const struct cx88_board cx88_boards[] = { * 14: 0: FM radio * 16: 0: RF input is cable */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0403, @@ -2280,7 +2280,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0xF0F7, .gpio2 = 0x0101, .gpio3 = 0x0000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0403, @@ -2308,7 +2308,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2324,19 +2324,19 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x3400, .card = CX88_BOARD_HAUPPAUGE, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x3401, .card = CX88_BOARD_HAUPPAUGE, - },{ + }, { .subvendor = 0x14c7, .subdevice = 0x0106, .card = CX88_BOARD_GDI, - },{ + }, { .subvendor = 0x14c7, .subdevice = 0x0107, /* with mpeg encoder */ .card = CX88_BOARD_GDI, - },{ + }, { .subvendor = PCI_VENDOR_ID_ATI, .subdevice = 0x00f8, .card = CX88_BOARD_ATI_WONDER_PRO, @@ -2348,176 +2348,176 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x107d, .subdevice = 0x6611, .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6613, /* NTSC */ .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6620, .card = CX88_BOARD_WINFAST_DV2000, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x663b, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x663c, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x000b, .card = CX88_BOARD_AVERTV_STUDIO_303, - },{ + }, { .subvendor = 0x1462, .subdevice = 0x8606, .card = CX88_BOARD_MSI_TVANYWHERE_MASTER, - },{ + }, { .subvendor = 0x10fc, .subdevice = 0xd003, .card = CX88_BOARD_IODATA_GVVCP3PCI, - },{ + }, { .subvendor = 0x1043, .subdevice = 0x4823, /* with mpeg encoder */ .card = CX88_BOARD_ASUS_PVR_416, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08a6, .card = CX88_BOARD_KWORLD_DVB_T, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd810, .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd820, .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb00, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9002, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0187, .card = CX88_BOARD_CONEXANT_DVB_T1, - },{ + }, { .subvendor = 0x1540, .subdevice = 0x2580, .card = CX88_BOARD_PROVIDEO_PV259, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb10, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, - },{ + }, { .subvendor = 0x1554, .subdevice = 0x4811, .card = CX88_BOARD_PIXELVIEW, - },{ + }, { .subvendor = 0x7063, .subdevice = 0x3000, /* HD-3000 card */ .card = CX88_BOARD_PCHDTV_HD3000, - },{ + }, { .subvendor = 0x17de, .subdevice = 0xa8a6, .card = CX88_BOARD_DNTV_LIVE_DVB_T, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x2801, .card = CX88_BOARD_HAUPPAUGE_ROSLYN, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0342, .card = CX88_BOARD_DIGITALLOGIC_MEC, - },{ + }, { .subvendor = 0x10fc, .subdevice = 0xd035, .card = CX88_BOARD_IODATA_GVBCTV7E, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0334, .card = CX88_BOARD_ADSTECH_DVB_T_PCI, - },{ + }, { .subvendor = 0x153b, .subdevice = 0x1166, .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x8011, .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550, - },{ + }, { .subvendor = PCI_VENDOR_ID_ATI, .subdevice = 0xa101, .card = CX88_BOARD_ATI_HDTVWONDER, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x665f, .card = CX88_BOARD_WINFAST_DTV1000, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x000a, .card = CX88_BOARD_AVERTV_303, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9200, .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9201, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9202, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08b2, .card = CX88_BOARD_KWORLD_DVBS_100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9400, .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9402, .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9800, .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9802, .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9001, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x1822, .subdevice = 0x0025, .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08a1, .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb50, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb54, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, /* Re-branded DViCO: DigitalNow DVB-T Dual */ - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb11, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, @@ -2530,55 +2530,55 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x17de, .subdevice = 0x0840, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0305, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb40, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb44, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ + }, { .subvendor = 0x7063, .subdevice = 0x5500, .card = CX88_BOARD_PCHDTV_HD5500, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x0841, .card = CX88_BOARD_KWORLD_MCE200_DELUXE, - },{ + }, { .subvendor = 0x1822, .subdevice = 0x0019, .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ + }, { .subvendor = 0x1554, .subdevice = 0x4813, .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0842, .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x665e, .card = CX88_BOARD_WINFAST_DTV2000H, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6f2b, .card = CX88_BOARD_WINFAST_DTV2000H_J, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0084, .card = CX88_BOARD_GENIATECH_DVBS, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1404, .card = CX88_BOARD_HAUPPAUGE_HVR3000, @@ -2590,60 +2590,60 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdccd, .card = CX88_BOARD_SAMSUNG_SMT_7020, - },{ + }, { .subvendor = 0x1461, .subdevice = 0xc111, /* AverMedia M150-D */ /* This board is known to work with the ASUS PVR416 config */ .card = CX88_BOARD_ASUS_PVR_416, - },{ + }, { .subvendor = 0xc180, .subdevice = 0xc980, .card = CX88_BOARD_TE_DTV_250_OEM_SWANN, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9600, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9601, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9602, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6632, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x12ab, .subdevice = 0x2300, /* Club3D Zap TV2100 */ .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9000, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1400, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1401, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1402, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ .card = CX88_BOARD_KWORLD_DVBS_100, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, - },{ + }, { .subvendor = 0x11bd, .subdevice = 0x0051, .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, -- cgit v1.2.3 From 84babee8fea9fc4fae2b5414ce71db1902eb7b7b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 16:23:30 -0300 Subject: [media] cx88: remove return after BUG() As reported by smatch: drivers/media/pci/cx88/cx88-video.c:699 get_queue() info: ignoring unreachable code. drivers/media/pci/cx88/cx88-video.c:714 get_resource() info: ignoring unreachable code. drivers/media/pci/cx88/cx88-video.c:815 video_read() info: ignoring unreachable code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-video.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ed8cb9037b6f..ce27e6d4f16e 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -696,7 +696,6 @@ static struct videobuf_queue *get_queue(struct file *file) return &fh->vbiq; default: BUG(); - return NULL; } } @@ -711,7 +710,6 @@ static int get_resource(struct file *file) return RESOURCE_VBI; default: BUG(); - return 0; } } @@ -812,7 +810,6 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) file->f_flags & O_NONBLOCK); default: BUG(); - return 0; } } -- cgit v1.2.3 From ae64b5ab4a181b483ff819174cfc74d02a54286a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 16:24:50 -0300 Subject: [media] saa7146: remove return after BUG() As reported by smatch: drivers/media/common/saa7146/saa7146_fops.c:314 fops_mmap() info: ignoring unreachable code. drivers/media/common/saa7146/saa7146_fops.c:402 fops_read() info: ignoring unreachable code. drivers/media/common/saa7146/saa7146_fops.c:426 fops_write() info: ignoring unreachable code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index 6c47f3fe9b0f..b7d63933dae6 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -311,7 +311,6 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma) } default: BUG(); - return 0; } if (mutex_lock_interruptible(vdev->lock)) @@ -399,7 +398,6 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof return -EINVAL; default: BUG(); - return 0; } } @@ -423,7 +421,6 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou return -EINVAL; default: BUG(); - return -EINVAL; } } -- cgit v1.2.3 From b39ba19cf3d0f8a7c86bfcf0b0964b0d4c1fae33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 16:29:45 -0300 Subject: [media] drxd: remove a dead code drivers/media/dvb-frontends/drxd_hard.c:2839 drxd_init() info: ignoring unreachable code. Firmware request/release is not at drxd_init. So, we can remove that dead code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxd_hard.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 961641b67728..687e893d29fe 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2831,14 +2831,8 @@ static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status) static int drxd_init(struct dvb_frontend *fe) { struct drxd_state *state = fe->demodulator_priv; - int err = 0; -/* if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */ return DRXD_init(state, NULL, 0); - - err = DRXD_init(state, state->fw->data, state->fw->size); - release_firmware(state->fw); - return err; } static int drxd_config_i2c(struct dvb_frontend *fe, int onoff) -- cgit v1.2.3 From 0db3241458685b22b6cd4db363722e6932244601 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 18:23:23 -0300 Subject: [media] em28xx: Fix identation drivers/media/usb/em28xx/em28xx-audio.c:270 snd_em28xx_capture_open() warn: if statement not indented Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 90c7a83989d1..957c7ae30efe 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -268,7 +268,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) nonblock = !!(substream->f_flags & O_NONBLOCK); if (nonblock) { if (!mutex_trylock(&dev->lock)) - return -EAGAIN; + return -EAGAIN; } else mutex_lock(&dev->lock); -- cgit v1.2.3 From e13f7d5aec0694bf2cb6f53a732f6a444933fdf4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 18:32:54 -0300 Subject: [media] s5p_mfc_opr_v5: Fix lots of warnings on x86_64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiled on x86_64, several warnings popup: drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:476:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:480:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:485:4: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:493:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:570:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:570:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:609:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:609:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:640:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:640:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:666:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] drivers/media//platform/s5p-mfc/s5p_mfc_opr_v5.c:666:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 6234e4d70596..90e3d61c1b59 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -473,16 +473,16 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) frame_size_mv); for (i = 0; i < ctx->total_dpb_count; i++) { /* Bank2 */ - mfc_debug(2, "Luma %d: %x\n", i, + mfc_debug(2, "Luma %d: %zx\n", i, ctx->dst_bufs[i].cookie.raw.luma); mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), S5P_FIMV_DEC_LUMA_ADR + i * 4); - mfc_debug(2, "\tChroma %d: %x\n", i, + mfc_debug(2, "\tChroma %d: %zx\n", i, ctx->dst_bufs[i].cookie.raw.chroma); mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), S5P_FIMV_DEC_CHROMA_ADR + i * 4); if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { - mfc_debug(2, "\tBuf2: %x, size: %d\n", + mfc_debug(2, "\tBuf2: %zx, size: %d\n", buf_addr2, buf_size2); mfc_write(dev, OFFSETB(buf_addr2), S5P_FIMV_H264_MV_ADR + i * 4); @@ -490,7 +490,7 @@ static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) buf_size2 -= frame_size_mv; } } - mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); + mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1); mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", buf_size1, buf_size2, ctx->total_dpb_count); if (buf_size1 < 0 || buf_size2 < 0) { @@ -567,7 +567,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) enc_ref_c_size = ALIGN(guard_width * guard_height, S5P_FIMV_NV12MT_SALIGN); } - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); + mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", buf_size1, buf_size2); switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_ENC: for (i = 0; i < 2; i++) { @@ -606,7 +606,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) S5P_FIMV_H264_NBOR_INFO_ADR); buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", buf_size1, buf_size2); break; case S5P_MFC_CODEC_MPEG4_ENC: @@ -637,7 +637,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) S5P_FIMV_MPEG4_ACDC_COEF_ADR); buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", buf_size1, buf_size2); break; case S5P_MFC_CODEC_H263_ENC: @@ -663,7 +663,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", buf_size1, buf_size2); break; default: -- cgit v1.2.3 From 4966bac19c870526f56ca0755539e86acd92fa72 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 18:43:59 -0300 Subject: [media] s5p_mfc_opr_v6: get rid of warnings when compiled with 64 bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are several errors related to size_t size and the usage of unsigned int for pointers: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_alloc_codec_buffers_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:103:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] mfc_debug(2, "recon luma size: %d chroma size: %d\n", ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:103:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_set_dec_frame_buffer_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:472:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘size_t’ [-Wformat=] mfc_debug(2, "Luma %d: %x\n", i, ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:476:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘size_t’ [-Wformat=] mfc_debug(2, "\tChroma %d: %x\n", i, ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:490:4: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat=] mfc_debug(2, "\tBuf1: %x, size: %d\n", ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:498:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat=] mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_set_enc_ref_buffer_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:596:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 4 has type ‘size_t’ [-Wformat=] mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_write_info_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:1883:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] writel(data, (volatile void __iomem *)ofs); ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_read_info_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:1893:14: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] ret = readl((volatile void __iomem *)ofs); ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_get_pic_type_top_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2022:3: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top); ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_get_pic_type_bot_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2028:3: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot); ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_get_crop_info_h_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2034:3: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info1); ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c: In function ‘s5p_mfc_get_crop_info_v_v6’: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c:2040:3: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info2); Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) 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 e38d78f21726..89de7a6daa5b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -100,7 +100,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) mb_width, mb_height), S5P_FIMV_ME_BUFFER_ALIGN_V6); - mfc_debug(2, "recon luma size: %d chroma size: %d\n", + mfc_debug(2, "recon luma size: %zd chroma size: %zd\n", ctx->luma_dpb_size, ctx->chroma_dpb_size); } else { return -EINVAL; @@ -469,11 +469,11 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) for (i = 0; i < ctx->total_dpb_count; i++) { /* Bank2 */ - mfc_debug(2, "Luma %d: %x\n", i, + mfc_debug(2, "Luma %d: %zx\n", i, ctx->dst_bufs[i].cookie.raw.luma); writel(ctx->dst_bufs[i].cookie.raw.luma, mfc_regs->d_first_plane_dpb + i * 4); - mfc_debug(2, "\tChroma %d: %x\n", i, + mfc_debug(2, "\tChroma %d: %zx\n", i, ctx->dst_bufs[i].cookie.raw.chroma); writel(ctx->dst_bufs[i].cookie.raw.chroma, mfc_regs->d_second_plane_dpb + i * 4); @@ -487,7 +487,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) align_gap = buf_addr1 - align_gap; buf_size1 -= align_gap; - mfc_debug(2, "\tBuf1: %x, size: %d\n", + mfc_debug(2, "\tBuf1: %zx, size: %d\n", buf_addr1, buf_size1); writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4); buf_addr1 += frame_size_mv; @@ -495,7 +495,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) } } - mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", + mfc_debug(2, "Buf1: %zu, buf_size1: %d (frames %d)\n", buf_addr1, buf_size1, ctx->total_dpb_count); if (buf_size1 < 0) { mfc_debug(2, "Not enough memory has been allocated.\n"); @@ -593,7 +593,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) buf_addr1 += ctx->tmv_buffer_size >> 1; buf_size1 -= ctx->tmv_buffer_size; - mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", + mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n", buf_addr1, buf_size1, ctx->pb_count); if (buf_size1 < 0) { mfc_debug(2, "Not enough memory has been allocated.\n"); @@ -1880,7 +1880,7 @@ static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { s5p_mfc_clock_on(); - writel(data, (volatile void __iomem *)ofs); + writel(data, (volatile void __iomem *)((unsigned long)ofs)); s5p_mfc_clock_off(); } @@ -1890,7 +1890,7 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) int ret; s5p_mfc_clock_on(); - ret = readl((volatile void __iomem *)ofs); + ret = readl((volatile void __iomem *)((unsigned long)ofs)); s5p_mfc_clock_off(); return ret; @@ -2019,25 +2019,25 @@ static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top); + (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top); } static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (__force unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot); + (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot); } static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info1); + (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1); } static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, - (__force unsigned int) ctx->dev->mfc_regs->d_display_crop_info2); + (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2); } static struct s5p_mfc_regs mfc_regs; -- cgit v1.2.3 From c0a566f3d51beb226f2cd79f7e9439ff3bed44b3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 19:15:06 -0300 Subject: [media] s3c-camif: fix dma_addr_t printks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media//platform/s3c-camif/camif-capture.c: In function ‘camif_prepare_addr’: include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-capture.c:283:2: note: in expansion of macro ‘pr_debug’ pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 6 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-capture.c:283:2: note: in expansion of macro ‘pr_debug’ pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-capture.c:283:2: note: in expansion of macro ‘pr_debug’ pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 6 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-regs.c:217:2: note: in expansion of macro ‘pr_debug’ pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 7 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-regs.c:217:2: note: in expansion of macro ‘pr_debug’ pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 8 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media//platform/s3c-camif/camif-regs.c:217:2: note: in expansion of macro ‘pr_debug’ pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n", ^ Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-capture.c | 4 ++-- drivers/media/platform/s3c-camif/camif-regs.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index f33641384e15..4f81b4c9d113 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -280,8 +280,8 @@ static int camif_prepare_addr(struct camif_vp *vp, struct vb2_buffer *vb, return -EINVAL; } - pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n", - paddr->y, paddr->cb, paddr->cr); + pr_debug("DMA address: y: %pad cb: %pad cr: %pad\n", + &paddr->y, &paddr->cb, &paddr->cr); return 0; } diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c index ebf5b184cce4..6e0c9988a191 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.c +++ b/drivers/media/platform/s3c-camif/camif-regs.c @@ -214,8 +214,8 @@ void camif_hw_set_output_addr(struct camif_vp *vp, paddr->cr); } - pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n", - i, paddr->y, paddr->cb, paddr->cr); + pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n", + i, &paddr->y, &paddr->cb, &paddr->cr); } static void camif_hw_set_out_dma_size(struct camif_vp *vp) -- cgit v1.2.3 From 5b31d9e036c1e18141b0458e89ce78e966a0d590 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 19:22:20 -0300 Subject: [media] ti-vpe: Fix typecast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses have the same size of unsigned long, and not u32. That removes a warning on 64 bits compilation: drivers/media//platform/ti-vpe/vpdma.c:332:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] WARN_ON(((u32) buf->addr & VPDMA_DESC_ALIGN) != 0); ^ include/asm-generic/bug.h:86:25: note: in definition of macro ‘WARN_ON’ int __ret_warn_on = !!(condition); \ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 684ba19bbedd..3e2e3a33e6ed 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -329,7 +329,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) if (!buf->addr) return -ENOMEM; - WARN_ON(((u32) buf->addr & VPDMA_DESC_ALIGN) != 0); + WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0); return 0; } -- cgit v1.2.3 From f1a0c1858c63888511811a5b5661bd4d08941028 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 18:50:33 -0300 Subject: [media] s5p_mfc_opr: Fix warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC drivers/media//platform/s5p-mfc/s5p_mfc_opr.o drivers/media//platform/s5p-mfc/s5p_mfc_opr.c: In function ‘s5p_mfc_alloc_priv_buf’: drivers/media//platform/s5p-mfc/s5p_mfc_opr.c:44:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] mfc_debug(3, "Allocating priv: %d\n", b->size); ^ drivers/media//platform/s5p-mfc/s5p_mfc_opr.c:53:2: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat=] mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma); ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index c9a227428e6a..00a1d8b2a8c2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -41,7 +41,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, struct s5p_mfc_priv_buf *b) { - mfc_debug(3, "Allocating priv: %d\n", b->size); + mfc_debug(3, "Allocating priv: %zu\n", b->size); b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); @@ -50,7 +50,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, return -ENOMEM; } - mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma); + mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); return 0; } -- cgit v1.2.3 From 03ce781626138e9cc972fa4fef0034a067726fb6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 19:07:36 -0300 Subject: [media] s5p-mfc: Fix several printk warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:192:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘dma_addr_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:196:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘dma_addr_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:196:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:1206:4: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:1206:32: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1757:3: warning: format ‘%zx’ expects argument of type ‘size_t’, but argument 6 has type ‘dma_addr_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1879:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat=] drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:1206:4: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:1206:32: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 6 +++--- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 10 +++++----- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 8 ++++---- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 3c10e31d017b..0c885a8a0e9f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -189,12 +189,12 @@ static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { if (IS_MFCV6_PLUS(dev)) { mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); - mfc_debug(2, "Base Address : %08x\n", dev->bank1); + mfc_debug(2, "Base Address : %pad\n", &dev->bank1); } else { mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); - mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", - dev->bank1, dev->bank2); + mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", + &dev->bank1, &dev->bank2); } } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 77eb952a744a..a98fe023deaf 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -1202,7 +1202,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) else f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT; ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); - mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", - (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); + mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n", + ctx->src_fmt, ctx->dst_fmt); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index adffdb37746b..a904a1c7bb21 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1750,13 +1750,13 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) return -EINVAL; } for (i = 0; i < fmt->num_planes; i++) { - if (!vb2_dma_contig_plane_dma_addr(vb, i)) { + dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i); + if (!dma) { mfc_err("failed to get plane cookie\n"); return -EINVAL; } - mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx\n", - vb->v4l2_buf.index, i, - vb2_dma_contig_plane_dma_addr(vb, i)); + mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n", + vb->v4l2_buf.index, i, &dma); } return 0; } @@ -1876,7 +1876,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) ret = check_vb_with_fmt(ctx->dst_fmt, vb); if (ret < 0) return ret; - mfc_debug(2, "plane size: %ld, dst size: %d\n", + mfc_debug(2, "plane size: %ld, dst size: %zu\n", vb2_plane_size(vb, 0), ctx->enc_dst_buf_size); if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) { mfc_err("plane size is too small for capture\n"); 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 90e3d61c1b59..7cf07963187d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -567,7 +567,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) enc_ref_c_size = ALIGN(guard_width * guard_height, S5P_FIMV_NV12MT_SALIGN); } - mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", buf_size1, buf_size2); + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_ENC: for (i = 0; i < 2; i++) { @@ -606,7 +606,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) S5P_FIMV_H264_NBOR_INFO_ADR); buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); break; case S5P_MFC_CODEC_MPEG4_ENC: @@ -637,7 +637,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) S5P_FIMV_MPEG4_ACDC_COEF_ADR); buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); break; case S5P_MFC_CODEC_H263_ENC: @@ -663,7 +663,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %zd, buf_size2: %zd\n", + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); break; default: 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 89de7a6daa5b..8798b14bacce 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -100,7 +100,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) mb_width, mb_height), S5P_FIMV_ME_BUFFER_ALIGN_V6); - mfc_debug(2, "recon luma size: %zd chroma size: %zd\n", + mfc_debug(2, "recon luma size: %zu chroma size: %zu\n", ctx->luma_dpb_size, ctx->chroma_dpb_size); } else { return -EINVAL; -- cgit v1.2.3 From 35f30f36a7e66caa0973a4db620b4245df2cf428 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 20:35:12 -0300 Subject: [media] dvb-frontends: use %zu instead of %zd size_t is unsigned. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/bcm3510.c | 2 +- drivers/media/dvb-frontends/mt312.c | 2 +- drivers/media/dvb-frontends/or51211.c | 2 +- drivers/media/dvb-frontends/zl10039.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 998d15031461..638c7aa0fb7e 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -639,7 +639,7 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe) err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); return ret; } - deb_info("got firmware: %zd\n",fw->size); + deb_info("got firmware: %zu\n", fw->size); b = fw->data; for (i = 0; i < fw->size;) { diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index a74ac0ddb833..2163490c1e6b 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, if (1 + count > sizeof(buf)) { printk(KERN_WARNING - "mt312: write: len=%zd is too big!\n", count); + "mt312: write: len=%zu is too big!\n", count); return -EINVAL; } diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index 10cfc0579168..873ea1da844b 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -111,7 +111,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe, u8 tudata[585]; int i; - dprintk("Firmware is %zd bytes\n",fw->size); + dprintk("Firmware is %zu bytes\n", fw->size); /* Get eprom data */ tudata[0] = 17; diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index 91b6b2e9b792..ee09ec26c553 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c @@ -111,7 +111,7 @@ static int zl10039_write(struct zl10039_state *state, if (1 + count > sizeof(buf)) { printk(KERN_WARNING - "%s: i2c wr reg=%04x: len=%zd is too big!\n", + "%s: i2c wr reg=%04x: len=%zu is too big!\n", KBUILD_MODNAME, reg, count); return -EINVAL; } -- cgit v1.2.3 From 339f06c5d354c4c89814f11d0c3393f198b3dd00 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 20:35:48 -0300 Subject: [media] pci drivers: use %zu instead of %zd size_t is unsigned. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-alsa-pcm.c | 2 +- drivers/media/pci/cx18/cx18-firmware.c | 4 ++-- drivers/media/pci/cx18/cx18-queue.c | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/ivtv/ivtv-alsa-pcm.c | 2 +- drivers/media/pci/ivtv/ivtv-firmware.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index 180077c49123..ffb6acdc575f 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, int period_elapsed = 0; int length; - dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, + dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc, pcm_data, num_bytes); substream = cxsc->capture_pcm_substream; diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index 53a7578d525b..c6c83445f8bf 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) } } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size); size = fw->size; release_firmware(fw); cx18_setup_page(cx, SCB_OFFSET); @@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, offset += seghdr.size; } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n", fn, apu_version, fw->size); size = fw->size; release_firmware(fw); diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 8884537bd62f..2a247d264b87 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s) ((char __iomem *)cx->scb->cpu_mdl)); CX18_ERR("Too many buffers, cannot fit in SCB area\n"); - CX18_ERR("Max buffers = %zd\n", + CX18_ERR("Max buffers = %zu\n", bufsz / sizeof(struct cx18_mdl_ent)); return -ENOMEM; } diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 6973055f0814..3948db386fb5 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -942,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", + "(have %zu, expected %d)\n", firmware->size, CX23885_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 7a9b98bc208b..7bf9cbca4fa6 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -81,7 +81,7 @@ static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc, int period_elapsed = 0; int length; - dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc, + dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc, pcm_data, num_bytes); substream = itvsc->capture_pcm_substream; diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index ed73edd2bcd3..4b0e758a7bce 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -65,7 +65,7 @@ retry: the wrong file was sometimes loaded. So we check filesizes to see if at least the right-sized file was loaded. If not, then we retry. */ - IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); + IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size); release_firmware(fw); retries--; goto retry; @@ -76,7 +76,7 @@ retry: dst++; src++; } - IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size); + IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size); release_firmware(fw); return size; } -- cgit v1.2.3 From 7983b773bad92fcc790152fe6db616644db1dfda Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 20:36:07 -0300 Subject: [media] usb drivers: use %zu instead of %zd size_t is unsigned. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-avcore.c | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/usb/siano/smsusb.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 51872b9f75a1..40a69879fc0a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -1595,7 +1595,7 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, if_freq = 16000000; } - cx231xx_info("Enter IF=%zd\n", + cx231xx_info("Enter IF=%zu\n", ARRAY_SIZE(Dif_set_array)); for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) { if (Dif_set_array[i].if_freq == if_freq) { diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3284de99fc99..0ce816352d51 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -481,7 +481,7 @@ static void em28xx_copy_video(struct em28xx *dev, lencopy = lencopy > remain ? remain : lencopy; if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n", + em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n", ((char *)startwrite + lencopy) - ((char *)buf->vb_buf + buf->length)); remain = (char *)buf->vb_buf + buf->length - @@ -507,7 +507,7 @@ static void em28xx_copy_video(struct em28xx *dev, if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end" + em28xx_isocdbg("Overflow of %zu bytes past buffer end" "(2)\n", ((char *)startwrite + lencopy) - ((char *)buf->vb_buf + buf->length)); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 89c86ee2b225..94e10b10b66e 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -277,14 +277,14 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000); - sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc); + sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc); kfree(fw_buffer); } else { sms_err("failed to allocate firmware buffer"); rc = -ENOMEM; } - sms_info("read FW %s, size=%zd", fw_filename, fw->size); + sms_info("read FW %s, size=%zu", fw_filename, fw->size); release_firmware(fw); -- cgit v1.2.3 From 7d4020c3c400260ea0601a74eace1cb071f01dd3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 22:08:41 -0300 Subject: [media] exynos4-is: fix some warnings when compiling on arm64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Got those warnings when compiling with gcc 4.9.1 for arm64: drivers/media/platform/exynos4-is/fimc-isp-video.c: In function ‘isp_video_capture_buffer_queue’: drivers/media/platform/exynos4-is/fimc-isp-video.c:221:4: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 7 has type ‘dma_addr_t’ [-Wformat=] isp_dbg(2, &video->ve.vdev, ^ drivers/media/platform/exynos4-is/fimc-is.c: In function ‘fimc_is_load_firmware’: drivers/media/platform/exynos4-is/fimc-is.c:391:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘size_t’ [-Wformat=] dev_err(dev, "wrong firmware size: %d\n", fw->size); ^ In file included from include/linux/printk.h:260:0, from include/linux/kernel.h:13, from include/linux/kernfs.h:10, from include/linux/sysfs.h:15, from include/linux/kobject.h:21, from include/linux/device.h:17, from drivers/media/platform/exynos4-is/fimc-is.c:15: include/linux/dynamic_debug.h:64:16: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:84:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/device.h:1106:2: note: in expansion of macro ‘dynamic_dev_dbg’ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ ^ drivers/media/platform/exynos4-is/fimc-is.c:419:2: note: in expansion of macro ‘dev_dbg’ dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr); ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:84:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/device.h:1106:2: note: in expansion of macro ‘dynamic_dev_dbg’ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ ^ drivers/media/platform/exynos4-is/fimc-is.c:419:2: note: in expansion of macro ‘dev_dbg’ dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr); ^ drivers/media/platform/exynos4-is/fimc-is.c: In function ‘fimc_is_hw_initialize’: include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media/platform/exynos4-is/fimc-is.c:696:2: note: in expansion of macro ‘pr_debug’ pr_debug("shared region: %#x, parameter region: %#x\n", ^ include/linux/dynamic_debug.h:64:16: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 6 has type ‘dma_addr_t’ [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro ‘DEFINE_DYNAMIC_DEBUG_METADATA’ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:266:2: note: in expansion of macro ‘dynamic_pr_debug’ dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ drivers/media/platform/exynos4-is/fimc-is.c:696:2: note: in expansion of macro ‘pr_debug’ pr_debug("shared region: %#x, parameter region: %#x\n", ^ Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is.c | 10 +++++----- drivers/media/platform/exynos4-is/fimc-isp-video.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 5476dce3ad29..22162b2567da 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -388,7 +388,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context) 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); + dev_err(dev, "wrong firmware size: %zu\n", fw->size); goto done; } @@ -416,7 +416,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context) 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); + dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr); is->is_shared_region->chip_id = 0xe4412; is->is_shared_region->chip_rev_no = 1; @@ -693,9 +693,9 @@ int fimc_is_hw_initialize(struct fimc_is *is) return -EIO; } - pr_debug("shared region: %#x, parameter region: %#x\n", - is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET, - is->is_dma_p_region); + pr_debug("shared region: %pad, parameter region: %pad\n", + &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET, + &is->is_dma_p_region); is->setfile.sub_index = 0; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 9d8d885558e5..76b6b4d14616 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -219,9 +219,9 @@ static void isp_video_capture_buffer_queue(struct vb2_buffer *vb) ivb->dma_addr[i]; isp_dbg(2, &video->ve.vdev, - "dma_buf %d (%d/%d/%d) addr: %#x\n", - buf_index, ivb->index, i, vb->v4l2_buf.index, - ivb->dma_addr[i]); + "dma_buf %pad (%d/%d/%d) addr: %pad\n", + &buf_index, ivb->index, i, vb->v4l2_buf.index, + &ivb->dma_addr[i]); } if (++video->buf_count < video->reqbufs_count) -- cgit v1.2.3 From 214635f94dc3e4069b05817e5d55b58784ba8971 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 26 Sep 2014 06:53:15 -0300 Subject: Revert "[media] media: em28xx - remove reset_resume interface" The reset_resume call is needed, otherwise it will break resume on some conditions, depending on the usb ehci/xhci controller. This reverts commit b89193e0b06f44f48e3bf897a5b5cb4a7aff3359. Reported-by: Johannes Stezenbach Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index f1425882a843..71fa51e7984e 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3515,6 +3515,7 @@ static struct usb_driver em28xx_usb_driver = { .disconnect = em28xx_usb_disconnect, .suspend = em28xx_usb_suspend, .resume = em28xx_usb_resume, + .reset_resume = em28xx_usb_resume, .id_table = em28xx_id_table, }; -- cgit v1.2.3 From cf3167cf1e969b17671a4d3d956d22718a8ceb85 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 26 Sep 2014 22:45:36 -0300 Subject: [media] pt3: fix DTV FE I2C driver load error paths Get rid of 'module_is_live' usage. on x86_64: when CONFIG_MODULES is not enabled: ../drivers/media/pci/pt3/pt3.c: In function 'pt3_attach_fe': ../drivers/media/pci/pt3/pt3.c:433:6: error: implicit declaration of function 'module_is_live' [-Werror=implicit-function-declaration] Reported-by: Randy Dunlap Cc: Akihiro Tsukada Cc: Stephen Rothwell Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pt3/pt3.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 90f86ce7a001..1fdeac11501a 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -393,7 +393,7 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i) return -ENODEV; pt3->adaps[i]->i2c_demod = cl; if (!try_module_get(cl->dev.driver->owner)) - goto err_demod; + goto err_demod_i2c_unregister_device; if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) { struct qm1d1c0042_config tcfg; @@ -415,28 +415,27 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i) cl = i2c_new_device(cfg.tuner_i2c, &info); } if (!cl || !cl->dev.driver) - goto err_demod; + goto err_demod_module_put; pt3->adaps[i]->i2c_tuner = cl; if (!try_module_get(cl->dev.driver->owner)) - goto err_tuner; + goto err_tuner_i2c_unregister_device; dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; ret = dvb_register_frontend(dvb_adap, cfg.fe); if (ret < 0) - goto err_tuner; + goto err_tuner_module_put; pt3->adaps[i]->fe = cfg.fe; return 0; -err_tuner: +err_tuner_module_put: + module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); +err_tuner_i2c_unregister_device: i2c_unregister_device(pt3->adaps[i]->i2c_tuner); - if (pt3->adaps[i]->i2c_tuner->dev.driver->owner && - module_is_live(pt3->adaps[i]->i2c_tuner->dev.driver->owner)) - module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); -err_demod: +err_demod_module_put: + module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); +err_demod_i2c_unregister_device: i2c_unregister_device(pt3->adaps[i]->i2c_demod); - if (pt3->adaps[i]->i2c_demod->dev.driver->owner && - module_is_live(pt3->adaps[i]->i2c_demod->dev.driver->owner)) - module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); + return ret; } -- cgit v1.2.3 From 5563caaf8b8cd22e35997d5d74cb3609df86b223 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 9 Oct 2014 10:41:28 -0300 Subject: [media] ir-hix5hd2: fix build on c6x arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While not all archs have readl_relaxed, we need to add a hack at the driver to allow it to COMPILE_TEST on all archs: drivers/media/rc/ir-hix5hd2.c: In function ‘hix5hd2_ir_config’: drivers/media/rc/ir-hix5hd2.c:100:2: error: implicit declaration of function ‘readl_relaxed’ [-Werror=implicit-function-declaration] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-hix5hd2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index c555ca2aed0e..08bbd4f508cd 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -20,6 +20,9 @@ #ifndef writel_relaxed # define writel_relaxed writel #endif +#ifndef readl_relaxed +# define readl_relaxed readl +#endif #define IR_ENABLE 0x00 #define IR_CONFIG 0x04 -- cgit v1.2.3