linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] em28xx: some improvements
@ 2018-03-02 19:34 Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 1/8] media: em28xx: don't use coherent buffer for DMA transfers Mauro Carvalho Chehab
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Antti Palosaari,
	Arnd Bergmann

The first patch in this series change the em28xx to don't
require coherent memory for DMA transfers. This should bring
some performance gains on non-x86 archs.

The other patches in this series are results of my tests
with the first patch :-)

patch 2 does some cleanups at i2c and Xclock speed settings.

Patches 3 and 4 do something that I'm intending to do for a
long time: it constifies most static structs inside the driver.
Before that, the cards list were modified in runtime, with is
a bad idea when multiple (but different) boards use the same
entry (for example, a webcam and a em28xx capture "generic"
board).

Patch 5 solves a FIXME.

Patch 6 was written by Arnd, as a way to solve an issue with
KASAN: without it, more than 4Kbytes were spent at the stack,
with can cause very bad things. He sent it sometime ago.

As I answered when the patchset was sent, I didn't like very
much that approach, as a way to solve KASAN, as the real solution
is to improve the I2C binding logic inside this (and other)
drivers. Yet, it brings a nice cleanup at em28xx.

So, patch 7 does that! It is something that I'm wanting to do
for a long time, but only today I found the needed time: it 
adds helper functions at the DVB core in order to bind/unbind
I2C modules to a driver. It is aligned with the new I2C
binding work made by Antti.

Patch 8 converts em28xx-dvb to use the new dvb_module_probe()
and dvb_module_release() fuctions, with caused a reduction
of almost 10% on the size of this module!

A side effect of patches 7 and 8 is that we don't to use
noinline_for_stack "black" magic there anymore, with is a
good thing.

Arnd Bergmann (1):
  media: em28xx: split up em28xx_dvb_init to reduce stack size

Mauro Carvalho Chehab (7):
  media: em28xx: don't use coherent buffer for DMA transfers
  media: em28xx: improve the logic with sets Xclk and I2C speed
  media: em28xx: stop rewriting device's struct
  media: em28xx: constify most static structs
  media: em28xx: adjust I2C timeout according with I2C speed
  media: dvb-core: add helper functions for I2C binding
  media: em28xx-dvb: simplify DVB module probing logic

 drivers/media/dvb-core/dvbdev.c         |  48 ++
 drivers/media/usb/em28xx/em28xx-cards.c | 163 +++----
 drivers/media/usb/em28xx/em28xx-core.c  |  57 ++-
 drivers/media/usb/em28xx/em28xx-dvb.c   | 775 ++++++++++++--------------------
 drivers/media/usb/em28xx/em28xx-i2c.c   |  36 +-
 drivers/media/usb/em28xx/em28xx-input.c |   6 +-
 drivers/media/usb/em28xx/em28xx-video.c |  24 +-
 drivers/media/usb/em28xx/em28xx.h       |  39 +-
 include/media/dvbdev.h                  |  65 ++-
 9 files changed, 579 insertions(+), 634 deletions(-)

-- 
2.14.3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/8] media: em28xx: don't use coherent buffer for DMA transfers
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 2/8] media: em28xx: improve the logic with sets Xclk and I2C speed Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

While coherent memory is cheap on x86, it may cause performance
impacts on other archs. As we don't have any good reason to
use it, let's change the logic by allocating memory via kmalloc()
and letting the USB core to do the DMA mapping and memory free
for us.

While here, also fixes an issue that it was not de-allocating
memories if something gets wrong during memory block
allocation.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-core.c | 51 +++++++++++++++-------------------
 drivers/media/usb/em28xx/em28xx.h      |  2 +-
 2 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 1d0d8cc06103..932ab93a05a6 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -800,7 +800,6 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
 {
 	struct urb *urb;
 	struct em28xx_usb_bufs *usb_bufs;
-	struct usb_device *udev = interface_to_usbdev(dev->intf);
 	int i;
 
 	em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n",
@@ -819,23 +818,16 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
 			else
 				usb_unlink_urb(urb);
 
-			if (usb_bufs->transfer_buffer[i]) {
-				usb_free_coherent(udev,
-						  urb->transfer_buffer_length,
-						  usb_bufs->transfer_buffer[i],
-						  urb->transfer_dma);
-			}
 			usb_free_urb(urb);
 			usb_bufs->urb[i] = NULL;
 		}
-		usb_bufs->transfer_buffer[i] = NULL;
 	}
 
 	kfree(usb_bufs->urb);
-	kfree(usb_bufs->transfer_buffer);
+	kfree(usb_bufs->buf);
 
 	usb_bufs->urb = NULL;
-	usb_bufs->transfer_buffer = NULL;
+	usb_bufs->buf = NULL;
 	usb_bufs->num_bufs = 0;
 
 	em28xx_capture_start(dev, 0);
@@ -912,14 +904,13 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
 
 	usb_bufs->num_bufs = num_bufs;
 
-	usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+	usb_bufs->urb = kcalloc(sizeof(void *), num_bufs,  GFP_KERNEL);
 	if (!usb_bufs->urb)
 		return -ENOMEM;
 
-	usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
-					     GFP_KERNEL);
-	if (!usb_bufs->transfer_buffer) {
-		kfree(usb_bufs->urb);
+	usb_bufs->buf = kcalloc(sizeof(void *), num_bufs, GFP_KERNEL);
+	if (!usb_bufs->buf) {
+		kfree(usb_bufs->buf);
 		return -ENOMEM;
 	}
 
@@ -942,37 +933,41 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
 		}
 		usb_bufs->urb[i] = urb;
 
-		usb_bufs->transfer_buffer[i] = usb_alloc_coherent(udev,
-			sb_size, GFP_KERNEL, &urb->transfer_dma);
-		if (!usb_bufs->transfer_buffer[i]) {
+		usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL);
+		if (!usb_bufs->buf[i]) {
 			dev_err(&dev->intf->dev,
 				"unable to allocate %i bytes for transfer buffer %i%s\n",
 			       sb_size, i,
 			       in_interrupt() ? " while in int" : "");
+
 			em28xx_uninit_usb_xfer(dev, mode);
+
+			for (i--; i >= 0; i--)
+				kfree(usb_bufs->buf[i]);
+
+			kfree(usb_bufs->buf);
+			usb_bufs->buf = NULL;
+
 			return -ENOMEM;
 		}
-		memset(usb_bufs->transfer_buffer[i], 0, sb_size);
+
+		urb->transfer_flags = URB_FREE_BUFFER;
 
 		if (xfer_bulk) { /* bulk */
 			pipe = usb_rcvbulkpipe(udev,
 					       mode == EM28XX_ANALOG_MODE ?
 					       dev->analog_ep_bulk :
 					       dev->dvb_ep_bulk);
-			usb_fill_bulk_urb(urb, udev, pipe,
-					  usb_bufs->transfer_buffer[i], sb_size,
-					  em28xx_irq_callback, dev);
-			urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+			usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->buf[i],
+					  sb_size, em28xx_irq_callback, dev);
 		} else { /* isoc */
 			pipe = usb_rcvisocpipe(udev,
 					       mode == EM28XX_ANALOG_MODE ?
 					       dev->analog_ep_isoc :
 					       dev->dvb_ep_isoc);
-			usb_fill_int_urb(urb, udev, pipe,
-					 usb_bufs->transfer_buffer[i], sb_size,
-					 em28xx_irq_callback, dev, 1);
-			urb->transfer_flags = URB_ISO_ASAP |
-					      URB_NO_TRANSFER_DMA_MAP;
+			usb_fill_int_urb(urb, udev, pipe, usb_bufs->buf[i],
+					 sb_size, em28xx_irq_callback, dev, 1);
+			urb->transfer_flags |= URB_ISO_ASAP;
 			k = 0;
 			for (j = 0; j < usb_bufs->num_packets; j++) {
 				urb->iso_frame_desc[j].offset = k;
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 88084f24f033..bd6eaf642662 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -239,7 +239,7 @@ struct em28xx_usb_bufs {
 	struct urb			**urb;
 
 		/* transfer buffers for isoc/bulk transfer */
-	char				**transfer_buffer;
+	char				**buf;
 };
 
 struct em28xx_usb_ctl {
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/8] media: em28xx: improve the logic with sets Xclk and I2C speed
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 1/8] media: em28xx: don't use coherent buffer for DMA transfers Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 3/8] media: em28xx: stop rewriting device's struct Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

The logic there should be called on two places. Also,
ideally, it should not be modifying the device struct.

So, change the logic accordingly.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 45 +++++++++++++++++----------------
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 34e16f6ab4ac..cbd7a43bd559 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2669,20 +2669,35 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 }
 EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
 
-static inline void em28xx_set_model(struct em28xx *dev)
+static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
 {
-	dev->board = em28xx_boards[dev->model];
+	struct em28xx_board *board = &em28xx_boards[dev->model];
+	u8 xclk = board->xclk, i2c_speed = board->i2c_speed;
 
 	/* Those are the default values for the majority of boards
 	   Use those values if not specified otherwise at boards entry
 	 */
-	if (!dev->board.xclk)
-		dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE |
+	if (!xclk)
+		xclk = EM28XX_XCLK_IR_RC5_MODE |
 				  EM28XX_XCLK_FREQUENCY_12MHZ;
 
-	if (!dev->board.i2c_speed)
-		dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
-				       EM28XX_I2C_FREQ_100_KHZ;
+	em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
+
+
+	if (!i2c_speed)
+		i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+			    EM28XX_I2C_FREQ_100_KHZ;
+
+	if (!dev->board.is_em2800)
+		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed);
+	msleep(50);
+}
+
+static inline void em28xx_set_model(struct em28xx *dev)
+{
+	dev->board = em28xx_boards[dev->model];
+
+	em28xx_set_xclk_i2c_speed(dev);
 
 	/* Should be initialized early, for I2C to work */
 	dev->def_i2c_bus = dev->board.def_i2c_bus;
@@ -2725,10 +2740,7 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
 {
 	/* Set the initial XCLK and I2C clock values based on the board
 	   definition */
-	em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
-	if (!dev->board.is_em2800)
-		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
-	msleep(50);
+	em28xx_set_xclk_i2c_speed(dev);
 
 	/* request some modules */
 	switch (dev->model) {
@@ -3382,17 +3394,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 
 	em28xx_pre_card_setup(dev);
 
-	if (!dev->board.is_em2800) {
-		/* Resets I2C speed */
-		retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
-		if (retval < 0) {
-			dev_err(&dev->intf->dev,
-			       "%s: em28xx_write_reg failed! retval [%d]\n",
-			       __func__, retval);
-			return retval;
-		}
-	}
-
 	rt_mutex_init(&dev->i2c_bus_lock);
 
 	/* register i2c bus 0 */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/8] media: em28xx: stop rewriting device's struct
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 1/8] media: em28xx: don't use coherent buffer for DMA transfers Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 2/8] media: em28xx: improve the logic with sets Xclk and I2C speed Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 4/8] media: em28xx: constify most static structs Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

Writing at the device's struct is evil, as two em28xx devices
may be using it. So, stop abusing it, storing the values
inside struct em28xx_dev.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 12 +++++++-----
 drivers/media/usb/em28xx/em28xx-core.c  |  4 ++--
 drivers/media/usb/em28xx/em28xx-video.c | 24 ++++++++++++------------
 drivers/media/usb/em28xx/em28xx.h       |  2 ++
 4 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index cbd7a43bd559..91c2198c8a2c 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2696,6 +2696,8 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
 static inline void em28xx_set_model(struct em28xx *dev)
 {
 	dev->board = em28xx_boards[dev->model];
+	dev->has_msp34xx = dev->board.has_msp34xx;
+	dev->is_webcam = dev->board.is_webcam;
 
 	em28xx_set_xclk_i2c_speed(dev);
 
@@ -2855,7 +2857,7 @@ static int em28xx_hint_board(struct em28xx *dev)
 {
 	int i;
 
-	if (dev->board.is_webcam) {
+	if (dev->is_webcam) {
 		if (dev->em28xx_sensor == EM28XX_MT9V011) {
 			dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
 		} else if (dev->em28xx_sensor == EM28XX_MT9M001 ||
@@ -2947,11 +2949,11 @@ static void em28xx_card_setup(struct em28xx *dev)
 	 * If the device can be a webcam, seek for a sensor.
 	 * If sensor is not found, then it isn't a webcam.
 	 */
-	if (dev->board.is_webcam) {
+	if (dev->is_webcam) {
 		em28xx_detect_sensor(dev);
 		if (dev->em28xx_sensor == EM28XX_NOSENSOR)
 			/* NOTE: error/unknown sensor/no sensor */
-			dev->board.is_webcam = 0;
+			dev->is_webcam = 0;
 	}
 
 	switch (dev->model) {
@@ -3013,7 +3015,7 @@ static void em28xx_card_setup(struct em28xx *dev)
 
 		if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) {
 			dev->i2s_speed = 2048000;
-			dev->board.has_msp34xx = 1;
+			dev->has_msp34xx = 1;
 		}
 		break;
 	}
@@ -3679,7 +3681,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	}
 
 	if (usb_xfer_mode < 0) {
-		if (dev->board.is_webcam)
+		if (dev->is_webcam)
 			try_bulk = 1;
 		else
 			try_bulk = 0;
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 932ab93a05a6..92c99b0320b3 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -378,7 +378,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
 			return ret;
 	}
 
-	if (dev->board.has_msp34xx)
+	if (dev->has_msp34xx)
 		input = EM28XX_AUDIO_SRC_TUNER;
 	else {
 		switch (dev->ctl_ainput) {
@@ -651,7 +651,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 			return rc;
 
 		if (start) {
-			if (dev->board.is_webcam)
+			if (dev->is_webcam)
 				rc = em28xx_write_reg(dev, 0x13, 0x0c);
 
 			/* Enable video capture */
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index a2ba2d905952..407850d9cae0 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -148,7 +148,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
 {
 	struct em28xx_v4l2 *v4l2 = dev->v4l2;
 
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		return v4l2->sensor_xres;
 
 	if (dev->board.max_range_640_480)
@@ -161,7 +161,7 @@ static inline unsigned int norm_maxh(struct em28xx *dev)
 {
 	struct em28xx_v4l2 *v4l2 = dev->v4l2;
 
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		return v4l2->sensor_yres;
 
 	if (dev->board.max_range_640_480)
@@ -176,7 +176,7 @@ static int em28xx_vbi_supported(struct em28xx *dev)
 	if (disable_vbi == 1)
 		return 0;
 
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		return 0;
 
 	/* FIXME: check subdevices for VBI support */
@@ -976,7 +976,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev)
 	}
 
 	/* Webcams don't have input connectors */
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		return;
 
 	/* Create entities for each input connector */
@@ -1277,7 +1277,7 @@ static void video_mux(struct em28xx *dev, int index)
 	v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
 			     INPUT(index)->vmux, 0, 0);
 
-	if (dev->board.has_msp34xx) {
+	if (dev->has_msp34xx) {
 		if (dev->i2s_speed) {
 			v4l2_device_call_all(v4l2_dev, 0, audio,
 					     s_i2s_clock_freq, dev->i2s_speed);
@@ -1587,7 +1587,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
 	int rc = 0;
 
 	p->parm.capture.readbuffers = EM28XX_MIN_BUF;
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
 						video, g_parm, p);
 	else
@@ -1629,7 +1629,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
 	i->std = dev->v4l2->vdev.tvnorms;
 	/* webcams do not have the STD API */
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		i->capabilities = 0;
 
 	return 0;
@@ -2343,7 +2343,7 @@ static void em28xx_vdev_init(struct em28xx *dev,
 	*vfd		= *template;
 	vfd->v4l2_dev	= &dev->v4l2->v4l2_dev;
 	vfd->lock	= &dev->lock;
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		vfd->tvnorms = 0;
 
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
@@ -2458,7 +2458,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	v4l2_ctrl_handler_init(hdl, 8);
 	v4l2->v4l2_dev.ctrl_handler = hdl;
 
-	if (dev->board.is_webcam)
+	if (dev->is_webcam)
 		v4l2->progressive = true;
 
 	/*
@@ -2470,7 +2470,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 
 	/* request some modules */
 
-	if (dev->board.has_msp34xx)
+	if (dev->has_msp34xx)
 		v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
 				    &dev->i2c_adap[dev->def_i2c_bus],
 				    "msp3400", 0, msp3400_addrs);
@@ -2559,7 +2559,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	INIT_LIST_HEAD(&dev->vidq.active);
 	INIT_LIST_HEAD(&dev->vbiq.active);
 
-	if (dev->board.has_msp34xx) {
+	if (dev->has_msp34xx) {
 		/* Send a reset to other chips via gpio */
 		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
 		if (ret < 0) {
@@ -2653,7 +2653,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
 
 	/* disable inapplicable ioctls */
-	if (dev->board.is_webcam) {
+	if (dev->is_webcam) {
 		v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
 		v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD);
 		v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index bd6eaf642662..d64de57769f0 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -619,6 +619,8 @@ struct em28xx {
 	unsigned char disconnected:1;	/* device has been diconnected */
 	unsigned int has_video:1;
 	unsigned int is_audio_only:1;
+	unsigned int is_webcam:1;
+	unsigned int has_msp34xx:1;
 	enum em28xx_int_audio_type int_audio_type;
 	enum em28xx_usb_audio_type usb_audio_type;
 
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/8] media: em28xx: constify most static structs
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2018-03-02 19:34 ` [PATCH 3/8] media: em28xx: stop rewriting device's struct Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

There are several em28xx static structs that can now be constified.

That caused a significant reduction at data segment:

Before:
   text	   data	    bss	    dec	    hex	filename
  85017	  59588	    576	 145181	  2371d	drivers/media/usb/em28xx/em28xx.o

After:
   text	   data	    bss	    dec	    hex	filename
 112345	  32292	    576	 145213	  2373d	drivers/media/usb/em28xx/em28xx.o

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 106 ++++++++++++++++----------------
 drivers/media/usb/em28xx/em28xx-core.c  |   2 +-
 drivers/media/usb/em28xx/em28xx-input.c |   6 +-
 drivers/media/usb/em28xx/em28xx.h       |  16 ++---
 4 files changed, 66 insertions(+), 64 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 91c2198c8a2c..02af067d7451 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -81,26 +81,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev);
  */
 
 /* Reset for the most [analog] boards */
-static struct em28xx_reg_seq default_analog[] = {
+const static struct em28xx_reg_seq default_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6d,   ~EM_GPIO_4,	10},
 	{	-1,		-1,	-1,		-1},
 };
 
 /* Reset for the most [digital] boards */
-static struct em28xx_reg_seq default_digital[] = {
+const static struct em28xx_reg_seq default_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6e,	~EM_GPIO_4,	10},
 	{	-1,		-1,	-1,		-1},
 };
 
 /* Board Hauppauge WinTV HVR 900 analog */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+const static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x2d,	~EM_GPIO_4,	10},
 	{	0x05,		0xff,	0x10,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
 /* Board Hauppauge WinTV HVR 900 digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+const static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x2e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x04,	0x0f,		10},
 	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
@@ -108,14 +108,14 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
 };
 
 /* Board Hauppauge WinTV HVR 900 (R2) digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+const static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x2e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x0c,	0x0f,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
 /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
+const static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x69,   ~EM_GPIO_4,	10},
 	{	-1,		-1,	-1,		-1},
 };
@@ -126,7 +126,7 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
    Analog - No input analog */
 
 /* Board - EM2882 Kworld 315U digital */
-static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+const static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0xff,	0xff,		10},
 	{EM2820_R08_GPIO_CTRL,	0xfe,	0xff,		10},
 	{EM2880_R04_GPO,	0x04,	0xff,		10},
@@ -135,7 +135,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+const static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
 	{EM2880_R04_GPO,	0x08,	0xff,		10},
 	{EM2880_R04_GPO,	0x0c,	0xff,		10},
 	{EM2880_R04_GPO,	0x08,	0xff,		10},
@@ -143,13 +143,13 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq kworld_330u_analog[] = {
+const static struct em28xx_reg_seq kworld_330u_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6d,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x00,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq kworld_330u_digital[] = {
+const static struct em28xx_reg_seq kworld_330u_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x08,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
@@ -161,12 +161,12 @@ static struct em28xx_reg_seq kworld_330u_digital[] = {
    GPIO4 - xc3028 reset
    GOP3  - s5h1409 reset
  */
-static struct em28xx_reg_seq evga_indtube_analog[] = {
+const static struct em28xx_reg_seq evga_indtube_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x79,   0xff,		60},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq evga_indtube_digital[] = {
+const static struct em28xx_reg_seq evga_indtube_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x7a,	0xff,		 1},
 	{EM2880_R04_GPO,	0x04,	0xff,		10},
 	{EM2880_R04_GPO,	0x0c,	0xff,		 1},
@@ -184,12 +184,12 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
  * EM_GPIO_6 - currently unknown
  * EM_GPIO_7 - currently unknown
  */
-static struct em28xx_reg_seq kworld_a340_digital[] = {
+const static struct em28xx_reg_seq kworld_a340_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6d,	~EM_GPIO_4,	10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
+const static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xfe,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xbe,	0xff,	100},
@@ -198,25 +198,25 @@ static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
 };
 
 /* Pinnacle Hybrid Pro eb1a:2881 */
-static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+const static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0xfd,   ~EM_GPIO_4,	10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+const static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x04,	0xff,	       100},/* zl10353 reset */
 	{EM2880_R04_GPO,	0x0c,	0xff,		 1},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
+const static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6d,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x00,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
+const static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x08,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
@@ -226,7 +226,7 @@ static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
    0-5: not used
    6:   demod reset, active low
    7:   LED on, active high */
-static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
+const static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
 	{EM28XX_R06_I2C_CLK,    0x45,   0xff,		  10}, /*400 KHz*/
 	{EM2874_R80_GPIO_P0_CTRL, 0x00,   0xff,		  100},/*Demod reset*/
 	{EM2874_R80_GPIO_P0_CTRL, 0x40,   0xff,		  10},
@@ -236,7 +236,7 @@ static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
 /* eb1a:2868 Reddo DVB-C USB TV Box
    GPIO4 - CU1216L NIM
    Other GPIOs seems to be don't care. */
-static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
+const static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
 	{EM2820_R08_GPIO_CTRL,	0xfe,	0xff,		10},
 	{EM2820_R08_GPIO_CTRL,	0xde,	0xff,		10},
 	{EM2820_R08_GPIO_CTRL,	0xfe,	0xff,		10},
@@ -248,7 +248,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
 };
 
 /* Callback for the most boards */
-static struct em28xx_reg_seq default_tuner_gpio[] = {
+const static struct em28xx_reg_seq default_tuner_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	EM_GPIO_4,	EM_GPIO_4,	10},
 	{EM2820_R08_GPIO_CTRL,	0,		EM_GPIO_4,	10},
 	{EM2820_R08_GPIO_CTRL,	EM_GPIO_4,	EM_GPIO_4,	10},
@@ -256,58 +256,58 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
 };
 
 /* Mute/unmute */
-static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+const static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	5,	7,	10},
 	{	-1,		-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+const static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	4,	7,	10},
 	{	-1,		-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq compro_mute_gpio[] = {
+const static struct em28xx_reg_seq compro_mute_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	6,	7,	10},
 	{	-1,		-1,	-1,	-1},
 };
 
 /* Terratec AV350 */
-static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+const static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	0xff,	0x7f,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+const static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,	0xff,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq silvercrest_reg_seq[] = {
+const static struct em28xx_reg_seq silvercrest_reg_seq[] = {
 	{EM2820_R08_GPIO_CTRL,	0xff,	0xff,		10},
 	{EM2820_R08_GPIO_CTRL,	0x01,	0xf7,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq vc211a_enable[] = {
+const static struct em28xx_reg_seq vc211a_enable[] = {
 	{EM2820_R08_GPIO_CTRL,	0xff,	0x07,		10},
 	{EM2820_R08_GPIO_CTRL,	0xff,	0x0f,		10},
 	{EM2820_R08_GPIO_CTRL,	0xff,	0x0b,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
-static struct em28xx_reg_seq dikom_dk300_digital[] = {
+const static struct em28xx_reg_seq dikom_dk300_digital[] = {
 	{EM2820_R08_GPIO_CTRL,	0x6e,	~EM_GPIO_4,	10},
 	{EM2880_R04_GPO,	0x08,	0xff,		10},
 	{	-1,		-1,	-1,		-1},
 };
 
 /* Reset for the most [digital] boards */
-static struct em28xx_reg_seq leadership_digital[] = {
+const static struct em28xx_reg_seq leadership_digital[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x70,	0xff,	10},
 	{	-1,			-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq leadership_reset[] = {
+const static struct em28xx_reg_seq leadership_reset[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xf0,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xb0,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xf0,	0xff,	10},
@@ -318,7 +318,7 @@ static struct em28xx_reg_seq leadership_reset[] = {
  * GPIO_6 - demod reset
  * GPIO_7 - LED
  */
-static struct em28xx_reg_seq pctv_290e[] = {
+const static struct em28xx_reg_seq pctv_290e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x00,	0xff,	80},
 	{EM2874_R80_GPIO_P0_CTRL,	0x40,	0xff,	80}, /* GPIO_6 = 1 */
 	{EM2874_R80_GPIO_P0_CTRL,	0xc0,	0xff,	80}, /* GPIO_7 = 1 */
@@ -326,7 +326,7 @@ static struct em28xx_reg_seq pctv_290e[] = {
 };
 
 #if 0
-static struct em28xx_reg_seq terratec_h5_gpio[] = {
+const static struct em28xx_reg_seq terratec_h5_gpio[] = {
 	{EM2820_R08_GPIO_CTRL,		0xff,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xf2,	0xff,	50},
@@ -334,7 +334,7 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = {
 	{	-1,			-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq terratec_h5_digital[] = {
+const static struct em28xx_reg_seq terratec_h5_digital[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xa6,	0xff,	10},
@@ -352,7 +352,7 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
  * GPIO_6 - RESET_DEM
  * GPIO_7 - LED (green LED)
  */
-static struct em28xx_reg_seq pctv_460e[] = {
+const static struct em28xx_reg_seq pctv_460e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x01,	0xff,	50},
 	{	0x0d,			0xff,	0xff,	50},
 	{EM2874_R80_GPIO_P0_CTRL,	0x41,	0xff,	50}, /* GPIO_6=1 */
@@ -361,7 +361,7 @@ static struct em28xx_reg_seq pctv_460e[] = {
 	{	-1,			-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
+const static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xfd,	0xff,	10}, /* xc5000 reset */
 	{EM2874_R80_GPIO_P0_CTRL,	0xf9,	0xff,	35},
@@ -384,7 +384,7 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
  * GPIO 6 = #RESET_DEM
  * GPIO 7 = P07_LED (green LED)
  */
-static struct em28xx_reg_seq pctv_461e[] = {
+const static struct em28xx_reg_seq pctv_461e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,      0x7f, 0xff,    0},
 	{0x0d,                 0xff, 0xff,    0},
 	{EM2874_R80_GPIO_P0_CTRL,      0x3f, 0xff,  100}, /* reset demod */
@@ -396,7 +396,7 @@ static struct em28xx_reg_seq pctv_461e[] = {
 };
 
 #if 0
-static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+const static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x6f,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0x4f,	0xff,	10}, /* xc5000 reset */
 	{EM2874_R80_GPIO_P0_CTRL,	0x6f,	0xff,	10},
@@ -404,7 +404,7 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
 	{	-1,			-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+const static struct em28xx_reg_seq hauppauge_930c_digital[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xa6,	0xff,	10},
@@ -417,7 +417,7 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = {
  * GPIO_6 - demod reset, 0=active
  * GPIO_7 - LED, 0=active
  */
-static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+const static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x83,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0xc3,	0xff,	100}, /* GPIO_6 = 1 */
 	{EM2874_R80_GPIO_P0_CTRL,	0x43,	0xff,	000}, /* GPIO_7 = 0 */
@@ -430,7 +430,7 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
  * GPIO_6: demod reset, 0=active
  * GPIO_7: LED, 1=active
  */
-static struct em28xx_reg_seq pctv_510e[] = {
+const static struct em28xx_reg_seq pctv_510e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x10,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0x14,	0xff,	100}, /* GPIO_2 = 1 */
 	{EM2874_R80_GPIO_P0_CTRL,	0x54,	0xff,	050}, /* GPIO_6 = 1 */
@@ -443,7 +443,7 @@ static struct em28xx_reg_seq pctv_510e[] = {
  * GPIO_6: demod reset, 0=active
  * GPIO_7: LED, 1=active
  */
-static struct em28xx_reg_seq pctv_520e[] = {
+const static struct em28xx_reg_seq pctv_520e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0x10,	0xff,	100},
 	{EM2874_R80_GPIO_P0_CTRL,	0x14,	0xff,	100}, /* GPIO_2 = 1 */
 	{EM2874_R80_GPIO_P0_CTRL,	0x54,	0xff,	050}, /* GPIO_6 = 1 */
@@ -460,13 +460,13 @@ static struct em28xx_reg_seq pctv_520e[] = {
  * reg 0x81/0x85:
  * GPIO_7: snapshot button, 0=pressed, 1=unpressed
  */
-static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
+const static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
 	{EM2820_R08_GPIO_CTRL,		0xf7,	0xff,	10},
 	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xb2,	10},
 	{	-1,			-1,	-1,	-1},
 };
 
-static struct em28xx_reg_seq pctv_292e[] = {
+const static struct em28xx_reg_seq pctv_292e[] = {
 	{EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,      0},
 	{0x0d,                         0xff, 0xff,    950},
 	{EM2874_R80_GPIO_P0_CTRL,      0xbd, 0xff,    100},
@@ -478,7 +478,7 @@ static struct em28xx_reg_seq pctv_292e[] = {
 	{-1,                             -1,   -1,     -1},
 };
 
-static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
+const static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	0},
 	{0x0d,				0xff,	0xff,	600},
 	{EM2874_R80_GPIO_P0_CTRL,	0xfc,	0xff,	10},
@@ -492,7 +492,7 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
 	{-1,                             -1,   -1,     -1},
 };
 
-static struct em28xx_reg_seq plex_px_bcud[] = {
+const static struct em28xx_reg_seq plex_px_bcud[] = {
 	{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	0},
 	{0x0d,				0xff,	0xff,	0},
 	{EM2874_R50_IR_CONFIG,		0x01,	0xff,	0},
@@ -517,7 +517,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
  * GPIO_5: Reset #2, 0=active
  * GPIO_6: Reset #1, 0=active
  */
-static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
+const static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
 	{EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,      0},
 	{0x0d,                         0xff, 0xff,    200},
 	{0x50,                         0x04, 0xff,    300},
@@ -534,7 +534,7 @@ static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
 /*
  *  Button definitions
  */
-static struct em28xx_button std_snapshot_button[] = {
+const static struct em28xx_button std_snapshot_button[] = {
 	{
 		.role         = EM28XX_BUTTON_SNAPSHOT,
 		.reg_r        = EM28XX_R0C_USBSUSP,
@@ -545,7 +545,7 @@ static struct em28xx_button std_snapshot_button[] = {
 	{-1, 0, 0, 0, 0},
 };
 
-static struct em28xx_button speedlink_vad_laplace_buttons[] = {
+const static struct em28xx_button speedlink_vad_laplace_buttons[] = {
 	{
 		.role     = EM28XX_BUTTON_SNAPSHOT,
 		.reg_r    = EM2874_R85_GPIO_P1_STATE,
@@ -629,7 +629,7 @@ static struct em28xx_led hauppauge_dualhd_leds[] = {
 /*
  *  Board definitions
  */
-struct em28xx_board em28xx_boards[] = {
+const struct em28xx_board em28xx_boards[] = {
 	[EM2750_BOARD_UNKNOWN] = {
 		.name          = "EM2710/EM2750/EM2751 webcam grabber",
 		.xclk          = EM28XX_XCLK_FREQUENCY_20MHZ,
@@ -2626,7 +2626,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table);
 /*
  * EEPROM hash table for devices with generic USB IDs
  */
-static struct em28xx_hash_table em28xx_eeprom_hash[] = {
+const static struct em28xx_hash_table em28xx_eeprom_hash[] = {
 	/* P/N: SA 60002070465 Tuner: TVF7533-MF */
 	{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
 	{0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
@@ -2639,7 +2639,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
-static struct em28xx_hash_table em28xx_i2c_hash[] = {
+const static struct em28xx_hash_table em28xx_i2c_hash[] = {
 	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
 	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
 	{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
@@ -2671,7 +2671,7 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
 
 static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
 {
-	struct em28xx_board *board = &em28xx_boards[dev->model];
+	const struct em28xx_board *board = &em28xx_boards[dev->model];
 	u8 xclk = board->xclk, i2c_speed = board->i2c_speed;
 
 	/* Those are the default values for the majority of boards
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 92c99b0320b3..ee8ef066d1ac 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -691,7 +691,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 	return rc;
 }
 
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio)
 {
 	int rc = 0;
 
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 046223de1e91..270cd68df4a2 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -515,7 +515,8 @@ static void em28xx_query_buttons(struct work_struct *work)
 		j = 0;
 		while (dev->board.buttons[j].role >= 0 &&
 		       dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
-			struct em28xx_button *button = &dev->board.buttons[j];
+			const struct em28xx_button *button = &dev->board.buttons[j];
+
 			/* Check if button uses the current address */
 			if (button->reg_r != dev->button_polling_addresses[i]) {
 				j++;
@@ -618,7 +619,8 @@ static void em28xx_init_buttons(struct em28xx *dev)
 	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];
+		const struct em28xx_button *button = &dev->board.buttons[i];
+
 		/* Check if polling address is already on the list */
 		addr_new = true;
 		for (j = 0; j < dev->num_button_polling_addresses; j++) {
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index d64de57769f0..b23f323b5c99 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -383,7 +383,7 @@ struct em28xx_input {
 	unsigned int vmux;
 	enum em28xx_amux amux;
 	enum em28xx_aout aout;
-	struct em28xx_reg_seq *gpio;
+	const struct em28xx_reg_seq *gpio;
 };
 
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -447,10 +447,10 @@ struct em28xx_board {
 	unsigned int tda9887_conf;
 
 	/* GPIO sequences */
-	struct em28xx_reg_seq *dvb_gpio;
-	struct em28xx_reg_seq *suspend_gpio;
-	struct em28xx_reg_seq *tuner_gpio;
-	struct em28xx_reg_seq *mute_gpio;
+	const struct em28xx_reg_seq *dvb_gpio;
+	const struct em28xx_reg_seq *suspend_gpio;
+	const struct em28xx_reg_seq *tuner_gpio;
+	const struct em28xx_reg_seq *mute_gpio;
 
 	unsigned int is_em2800:1;
 	unsigned int has_msp34xx:1;
@@ -476,7 +476,7 @@ struct em28xx_board {
 	struct em28xx_led	  *leds;
 
 	/* Buttons */
-	struct em28xx_button	  *buttons;
+	const struct em28xx_button *buttons;
 };
 
 struct em28xx_eeprom {
@@ -780,7 +780,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
 void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
 void em28xx_stop_urbs(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
+int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 void em28xx_init_extension(struct em28xx *dev);
@@ -789,7 +789,7 @@ int em28xx_suspend_extension(struct em28xx *dev);
 int em28xx_resume_extension(struct em28xx *dev);
 
 /* Provided by em28xx-cards.c */
-extern struct em28xx_board em28xx_boards[];
+extern const struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2018-03-02 19:34 ` [PATCH 4/8] media: em28xx: constify most static structs Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-03 19:00   ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 6/8] media: em28xx: split up em28xx_dvb_init to reduce stack size Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

If the I2C speed is too slow, it should wait more for an
answer.

While here, change disconnected type from char to unsigned
int, just like all other bitmask fields there at em28xx
struct.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c |  2 ++
 drivers/media/usb/em28xx/em28xx-i2c.c   | 36 ++++++++++++++++++++++++++++++---
 drivers/media/usb/em28xx/em28xx.h       | 19 ++---------------
 3 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 02af067d7451..03bd3ee19419 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2688,6 +2688,8 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
 		i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
 			    EM28XX_I2C_FREQ_100_KHZ;
 
+	dev->i2c_speed = i2c_speed & 0x03;
+
 	if (!dev->board.is_em2800)
 		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed);
 	msleep(50);
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 9bf49d666e5a..f9aaee3f3d91 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -51,13 +51,43 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I
 } while (0)
 
 
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT         35 /* ms */
+
+static int em28xx_i2c_timeout(struct em28xx *dev)
+{
+	int time = EM28XX_I2C_XFER_TIMEOUT;
+
+	switch (dev->i2c_speed & 0x03) {
+	case EM28XX_I2C_FREQ_25_KHZ:
+		return time += 4;		/* Assume 4 ms for transfers */
+		break;
+	case EM28XX_I2C_FREQ_100_KHZ:
+	case EM28XX_I2C_FREQ_400_KHZ:
+		return time += 1;		/* Assume 1 ms for transfers */
+		break;
+	default: /* EM28XX_I2C_FREQ_1_5_MHZ */
+		break;
+	}
+
+	return msecs_to_jiffies(time);
+}
+
 /*
  * em2800_i2c_send_bytes()
  * send up to 4 bytes to the em2800 i2c device
  */
 static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	int ret;
 	u8 b2[6];
 
@@ -110,7 +140,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
  */
 static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	u8 buf2[4];
 	int ret;
 	int i;
@@ -186,7 +216,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
 static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 				 u16 len, int stop)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	int ret;
 
 	if (len < 1 || len > 64)
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index b23f323b5c99..220e7a7a6124 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -195,22 +195,6 @@
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
-/*
- * Time in msecs to wait for i2c xfers to finish.
- * 35ms is the maximum time a SMBUS device could wait when
- * clock stretching is used. As the transfer itself will take
- * some time to happen, set it to 35 ms.
- *
- * Ok, I2C doesn't specify any limit. So, eventually, we may need
- * to increase this timeout.
- *
- * FIXME: this assumes that an I2C message is not longer than 1ms.
- * This is actually dependent on the I2C bus speed, although most
- * devices use a 100kHz clock. So, this assumtion is true most of
- * the time.
- */
-#define EM28XX_I2C_XFER_TIMEOUT		36
-
 /* time in msecs to wait for AC97 xfers to finish */
 #define EM28XX_AC97_XFER_TIMEOUT	100
 
@@ -616,11 +600,12 @@ struct em28xx {
 	enum em28xx_chip_id chip_id;
 
 	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
-	unsigned char disconnected:1;	/* device has been diconnected */
+	unsigned int disconnected:1;	/* device has been diconnected */
 	unsigned int has_video:1;
 	unsigned int is_audio_only:1;
 	unsigned int is_webcam:1;
 	unsigned int has_msp34xx:1;
+	unsigned int i2c_speed:2;
 	enum em28xx_int_audio_type int_audio_type;
 	enum em28xx_usb_audio_type usb_audio_type;
 
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/8] media: em28xx: split up em28xx_dvb_init to reduce stack size
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2018-03-02 19:34 ` [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 7/8] media: dvb-core: add helper functions for I2C binding Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 8/8] media: em28xx-dvb: simplify DVB module probing logic Mauro Carvalho Chehab
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Arnd Bergmann, Mauro Carvalho Chehab, Mauro Carvalho Chehab

From: Arnd Bergmann <arnd@arndb.de>

With CONFIG_KASAN, the init function uses a large amount of kernel stack:

drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init.part.4':
drivers/media/usb/em28xx/em28xx-dvb.c:2061:1: error: the frame size of 3232 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]

Using gcc-7 with -fsanitize-address-use-after-scope makes this even worse:

drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init':
drivers/media/usb/em28xx/em28xx-dvb.c:2069:1: error: the frame size of 4280 bytes is larger than 3072 bytes [-Werror=frame-larger-than=]

By splitting out each part of the switch/case statement that has its own local
variables into a separate function, no single one of them uses more than 500 bytes,
and with a noinline_for_stack annotation we can ensure that they are not merged
back together.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-dvb.c | 947 ++++++++++++++++++----------------
 1 file changed, 508 insertions(+), 439 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 8a81c94a8a27..28c4c7d8dbd8 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -934,7 +934,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = {
 
 /* ------------------------------------------------------------------ */
 
-static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
+static noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
 {
 	struct dvb_frontend *fe;
 	struct xc2028_config cfg;
@@ -1126,6 +1126,492 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
 	dvb_unregister_adapter(&dvb->adapter);
 }
 
+static noinline_for_stack int em28174_dvb_init_pctv_460e(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_client *client;
+	struct i2c_board_info board_info;
+	struct tda10071_platform_data tda10071_pdata = {};
+	struct a8293_platform_data a8293_pdata = {};
+	int result;
+
+	/* attach demod + tuner combo */
+	tda10071_pdata.clk = 40444000, /* 40.444 MHz */
+	tda10071_pdata.i2c_wr_max = 64,
+	tda10071_pdata.ts_mode = TDA10071_TS_SERIAL,
+	tda10071_pdata.pll_multiplier = 20,
+	tda10071_pdata.tuner_i2c_addr = 0x14,
+	memset(&board_info, 0, sizeof(board_info));
+	strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE);
+	board_info.addr = 0x55;
+	board_info.platform_data = &tda10071_pdata;
+	request_module("tda10071");
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
+	dvb->i2c_client_demod = client;
+
+	/* attach SEC */
+	a8293_pdata.dvb_frontend = dvb->fe[0];
+	memset(&board_info, 0, sizeof(board_info));
+	strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
+	board_info.addr = 0x08;
+	board_info.platform_data = &a8293_pdata;
+	request_module("a8293");
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->i2c_client_sec = client;
+	result = 0;
+out_free:
+	return result;
+}
+
+static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_client *client;
+	struct i2c_adapter *i2c_adapter;
+	struct i2c_board_info board_info;
+	struct m88ds3103_platform_data m88ds3103_pdata = {};
+	struct ts2020_config ts2020_config = {};
+	struct a8293_platform_data a8293_pdata = {};
+	int result;
+
+	/* attach demod */
+	m88ds3103_pdata.clk = 27000000;
+	m88ds3103_pdata.i2c_wr_max = 33;
+	m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
+	m88ds3103_pdata.ts_clk = 16000;
+	m88ds3103_pdata.ts_clk_pol = 1;
+	m88ds3103_pdata.agc = 0x99;
+	memset(&board_info, 0, sizeof(board_info));
+	strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
+	board_info.addr = 0x68;
+	board_info.platform_data = &m88ds3103_pdata;
+	request_module("m88ds3103");
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
+	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
+	dvb->i2c_client_demod = client;
+
+	/* attach tuner */
+	ts2020_config.fe = dvb->fe[0];
+	memset(&board_info, 0, sizeof(board_info));
+	strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
+	board_info.addr = 0x60;
+	board_info.platform_data = &ts2020_config;
+	request_module("ts2020");
+	client = i2c_new_device(i2c_adapter, &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->i2c_client_tuner = client;
+	/* delegate signal strength measurement to tuner */
+	dvb->fe[0]->ops.read_signal_strength =
+			dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+	/* attach SEC */
+	a8293_pdata.dvb_frontend = dvb->fe[0];
+	memset(&board_info, 0, sizeof(board_info));
+	strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
+	board_info.addr = 0x08;
+	board_info.platform_data = &a8293_pdata;
+	request_module("a8293");
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_tuner->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_tuner);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_tuner->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_tuner);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->i2c_client_sec = client;
+	result = 0;
+out_free:
+	return result;
+}
+
+static noinline_for_stack int em28178_dvb_init_pctv_292e(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info;
+	struct si2168_config si2168_config;
+	struct si2157_config si2157_config;
+	int result;
+
+	/* attach demod */
+	memset(&si2168_config, 0, sizeof(si2168_config));
+	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;
+	info.platform_data = &si2168_config;
+	request_module(info.type);
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_demod = client;
+
+	/* attach tuner */
+	memset(&si2157_config, 0, sizeof(si2157_config));
+	si2157_config.fe = dvb->fe[0];
+	si2157_config.if_port = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	si2157_config.mdev = dev->media_dev;
+#endif
+	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 = i2c_new_device(adapter, &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_tuner = client;
+	dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
+	result = 0;
+out_free:
+	return result;
+}
+
+static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info;
+	struct si2168_config si2168_config;
+	struct si2157_config si2157_config;
+	int result;
+
+	/* attach demod */
+	memset(&si2168_config, 0, sizeof(si2168_config));
+	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;
+	info.platform_data = &si2168_config;
+	request_module(info.type);
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_demod = client;
+
+	/* attach tuner */
+	memset(&si2157_config, 0, sizeof(si2157_config));
+	si2157_config.fe = dvb->fe[0];
+	si2157_config.if_port = 0;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	si2157_config.mdev = dev->media_dev;
+#endif
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "si2146", I2C_NAME_SIZE);
+	info.addr = 0x60;
+	info.platform_data = &si2157_config;
+	request_module("si2157");
+	client = i2c_new_device(adapter, &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_tuner = client;
+	result = 0;
+out_free:
+	return result;
+}
+
+static noinline_for_stack int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_client *client;
+	struct i2c_board_info info;
+	struct tc90522_config tc90522_config;
+	struct qm1d1c0042_config qm1d1c0042_config;
+	int result;
+
+	/* attach demod */
+	memset(&tc90522_config, 0, sizeof(tc90522_config));
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
+	info.addr = 0x15;
+	info.platform_data = &tc90522_config;
+	request_module("tc90522");
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->i2c_client_demod = client;
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	/* attach tuner */
+	memset(&qm1d1c0042_config, 0,
+	       sizeof(qm1d1c0042_config));
+	qm1d1c0042_config.fe = tc90522_config.fe;
+	qm1d1c0042_config.lpf = 1;
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
+	info.addr = 0x61;
+	info.platform_data = &qm1d1c0042_config;
+	request_module(info.type);
+	client = i2c_new_device(tc90522_config.tuner_i2c,
+				&info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->i2c_client_tuner = client;
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	dvb->fe[0] = tc90522_config.fe;
+	px_bcud_init(dev);
+	result = 0;
+out_free:
+	return result;
+}
+
+static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info;
+	struct si2168_config si2168_config;
+	struct si2157_config si2157_config;
+	int result;
+
+	/* attach demod */
+	memset(&si2168_config, 0, sizeof(si2168_config));
+	si2168_config.i2c_adapter = &adapter;
+	si2168_config.fe = &dvb->fe[0];
+	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 = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_demod = client;
+
+	/* attach tuner */
+	memset(&si2157_config, 0, sizeof(si2157_config));
+	si2157_config.fe = dvb->fe[0];
+	si2157_config.if_port = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	si2157_config.mdev = dev->media_dev;
+#endif
+	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 = i2c_new_device(adapter, &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_tuner = client;
+	result = 0;
+out_free:
+	return result;
+}
+
+static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
+{
+	struct em28xx_dvb *dvb = dev->dvb;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info = {};
+	struct lgdt3306a_config lgdt3306a_config;
+	struct si2157_config si2157_config = {};
+	int result;
+
+	/* attach demod */
+	lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
+	lgdt3306a_config.fe = &dvb->fe[0];
+	lgdt3306a_config.i2c_adapter = &adapter;
+	strlcpy(info.type, "lgdt3306a", sizeof(info.type));
+	info.addr = 0x59;
+	info.platform_data = &lgdt3306a_config;
+	request_module(info.type);
+	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
+			&info);
+	if (client == NULL || client->dev.driver == NULL) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_demod = client;
+
+	/* attach tuner */
+	si2157_config.fe = dvb->fe[0];
+	si2157_config.if_port = 1;
+	si2157_config.inversion = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	si2157_config.mdev = dev->media_dev;
+#endif
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	strlcpy(info.type, "si2157", sizeof(info.type));
+	info.addr = 0x60;
+	info.platform_data = &si2157_config;
+	request_module(info.type);
+
+	client = i2c_new_device(adapter, &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		module_put(dvb->i2c_client_demod->dev.driver->owner);
+		i2c_unregister_device(dvb->i2c_client_demod);
+		result = -ENODEV;
+		goto out_free;
+	}
+
+	dvb->i2c_client_tuner = client;
+	result = 0;
+out_free:
+	return result;
+}
 static int em28xx_dvb_init(struct em28xx *dev)
 {
 	int result = 0;
@@ -1427,60 +1913,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
 				   &dev->i2c_adap[dev->def_i2c_bus],
 				   &c3tech_duo_tda18271_config);
 		break;
-	case EM28174_BOARD_PCTV_460E: {
-		struct i2c_client *client;
-		struct i2c_board_info board_info;
-		struct tda10071_platform_data tda10071_pdata = {};
-		struct a8293_platform_data a8293_pdata = {};
-
-		/* attach demod + tuner combo */
-		tda10071_pdata.clk = 40444000, /* 40.444 MHz */
-		tda10071_pdata.i2c_wr_max = 64,
-		tda10071_pdata.ts_mode = TDA10071_TS_SERIAL,
-		tda10071_pdata.pll_multiplier = 20,
-		tda10071_pdata.tuner_i2c_addr = 0x14,
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE);
-		board_info.addr = 0x55;
-		board_info.platform_data = &tda10071_pdata;
-		request_module("tda10071");
-		client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-		if (client == NULL || client->dev.driver == NULL) {
-			result = -ENODEV;
+	case EM28174_BOARD_PCTV_460E:
+		result = em28174_dvb_init_pctv_460e(dev);
+		if (result)
 			goto out_free;
-		}
-		if (!try_module_get(client->dev.driver->owner)) {
-			i2c_unregister_device(client);
-			result = -ENODEV;
-			goto out_free;
-		}
-		dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
-		dvb->i2c_client_demod = client;
-
-		/* attach SEC */
-		a8293_pdata.dvb_frontend = dvb->fe[0];
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
-		board_info.addr = 0x08;
-		board_info.platform_data = &a8293_pdata;
-		request_module("a8293");
-		client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		if (!try_module_get(client->dev.driver->owner)) {
-			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		dvb->i2c_client_sec = client;
 		break;
-	}
 	case EM2874_BOARD_DELOCK_61959:
 	case EM2874_BOARD_MAXMEDIA_UB425_TC:
 		/* attach demodulator */
@@ -1627,403 +2064,35 @@ static int em28xx_dvb_init(struct em28xx *dev)
 			}
 		}
 		break;
-	case EM28178_BOARD_PCTV_461E: {
-		struct i2c_client *client;
-		struct i2c_adapter *i2c_adapter;
-		struct i2c_board_info board_info;
-		struct m88ds3103_platform_data m88ds3103_pdata = {};
-		struct ts2020_config ts2020_config = {};
-		struct a8293_platform_data a8293_pdata = {};
-
-		/* attach demod */
-		m88ds3103_pdata.clk = 27000000;
-		m88ds3103_pdata.i2c_wr_max = 33;
-		m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
-		m88ds3103_pdata.ts_clk = 16000;
-		m88ds3103_pdata.ts_clk_pol = 1;
-		m88ds3103_pdata.agc = 0x99;
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
-		board_info.addr = 0x68;
-		board_info.platform_data = &m88ds3103_pdata;
-		request_module("m88ds3103");
-		client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-		if (client == NULL || client->dev.driver == NULL) {
-			result = -ENODEV;
+	case EM28178_BOARD_PCTV_461E:
+		result = em28178_dvb_init_pctv_461e(dev);
+		if (result)
 			goto out_free;
-		}
-		if (!try_module_get(client->dev.driver->owner)) {
-			i2c_unregister_device(client);
-			result = -ENODEV;
-			goto out_free;
-		}
-		dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
-		i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
-		dvb->i2c_client_demod = client;
-
-		/* attach tuner */
-		ts2020_config.fe = dvb->fe[0];
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
-		board_info.addr = 0x60;
-		board_info.platform_data = &ts2020_config;
-		request_module("ts2020");
-		client = i2c_new_device(i2c_adapter, &board_info);
-		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		if (!try_module_get(client->dev.driver->owner)) {
-			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		dvb->i2c_client_tuner = client;
-		/* delegate signal strength measurement to tuner */
-		dvb->fe[0]->ops.read_signal_strength =
-				dvb->fe[0]->ops.tuner_ops.get_rf_strength;
-
-		/* attach SEC */
-		a8293_pdata.dvb_frontend = dvb->fe[0];
-		memset(&board_info, 0, sizeof(board_info));
-		strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
-		board_info.addr = 0x08;
-		board_info.platform_data = &a8293_pdata;
-		request_module("a8293");
-		client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-		if (client == NULL || client->dev.driver == NULL) {
-			module_put(dvb->i2c_client_tuner->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_tuner);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		if (!try_module_get(client->dev.driver->owner)) {
-			i2c_unregister_device(client);
-			module_put(dvb->i2c_client_tuner->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_tuner);
-			module_put(dvb->i2c_client_demod->dev.driver->owner);
-			i2c_unregister_device(dvb->i2c_client_demod);
-			result = -ENODEV;
-			goto out_free;
-		}
-		dvb->i2c_client_sec = client;
 		break;
-	}
 	case EM28178_BOARD_PCTV_292E:
-		{
-			struct i2c_adapter *adapter;
-			struct i2c_client *client;
-			struct i2c_board_info info;
-			struct si2168_config si2168_config;
-			struct si2157_config si2157_config;
-
-			/* attach demod */
-			memset(&si2168_config, 0, sizeof(si2168_config));
-			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;
-			info.platform_data = &si2168_config;
-			request_module(info.type);
-			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_demod = client;
-
-			/* attach tuner */
-			memset(&si2157_config, 0, sizeof(si2157_config));
-			si2157_config.fe = dvb->fe[0];
-			si2157_config.if_port = 1;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-			si2157_config.mdev = dev->media_dev;
-#endif
-			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 = i2c_new_device(adapter, &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_tuner = client;
-			dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
-		}
+		result = em28178_dvb_init_pctv_292e(dev);
+		if (result)
+			goto out_free;
 		break;
 	case EM28178_BOARD_TERRATEC_T2_STICK_HD:
-		{
-			struct i2c_adapter *adapter;
-			struct i2c_client *client;
-			struct i2c_board_info info;
-			struct si2168_config si2168_config;
-			struct si2157_config si2157_config;
-
-			/* attach demod */
-			memset(&si2168_config, 0, sizeof(si2168_config));
-			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;
-			info.platform_data = &si2168_config;
-			request_module(info.type);
-			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_demod = client;
-
-			/* attach tuner */
-			memset(&si2157_config, 0, sizeof(si2157_config));
-			si2157_config.fe = dvb->fe[0];
-			si2157_config.if_port = 0;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-			si2157_config.mdev = dev->media_dev;
-#endif
-			memset(&info, 0, sizeof(struct i2c_board_info));
-			strlcpy(info.type, "si2146", I2C_NAME_SIZE);
-			info.addr = 0x60;
-			info.platform_data = &si2157_config;
-			request_module("si2157");
-			client = i2c_new_device(adapter, &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_tuner = client;
-		}
+		result = em28178_dvb_init_terratec_t2_stick_hd(dev);
+		if (result)
+			goto out_free;
 		break;
-
 	case EM28178_BOARD_PLEX_PX_BCUD:
-		{
-			struct i2c_client *client;
-			struct i2c_board_info info;
-			struct tc90522_config tc90522_config;
-			struct qm1d1c0042_config qm1d1c0042_config;
-
-			/* attach demod */
-			memset(&tc90522_config, 0, sizeof(tc90522_config));
-			memset(&info, 0, sizeof(struct i2c_board_info));
-			strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
-			info.addr = 0x15;
-			info.platform_data = &tc90522_config;
-			request_module("tc90522");
-			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				result = -ENODEV;
-				goto out_free;
-			}
-			dvb->i2c_client_demod = client;
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			/* attach tuner */
-			memset(&qm1d1c0042_config, 0,
-			       sizeof(qm1d1c0042_config));
-			qm1d1c0042_config.fe = tc90522_config.fe;
-			qm1d1c0042_config.lpf = 1;
-			memset(&info, 0, sizeof(struct i2c_board_info));
-			strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
-			info.addr = 0x61;
-			info.platform_data = &qm1d1c0042_config;
-			request_module(info.type);
-			client = i2c_new_device(tc90522_config.tuner_i2c,
-						&info);
-			if (client == NULL || client->dev.driver == NULL) {
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-			dvb->i2c_client_tuner = client;
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-			dvb->fe[0] = tc90522_config.fe;
-			px_bcud_init(dev);
-		}
+		result = em28178_dvb_init_plex_px_bcud(dev);
+		if (result)
+			goto out_free;
 		break;
 	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
-		{
-			struct i2c_adapter *adapter;
-			struct i2c_client *client;
-			struct i2c_board_info info;
-			struct si2168_config si2168_config;
-			struct si2157_config si2157_config;
-
-			/* attach demod */
-			memset(&si2168_config, 0, sizeof(si2168_config));
-			si2168_config.i2c_adapter = &adapter;
-			si2168_config.fe = &dvb->fe[0];
-			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 = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_demod = client;
-
-			/* attach tuner */
-			memset(&si2157_config, 0, sizeof(si2157_config));
-			si2157_config.fe = dvb->fe[0];
-			si2157_config.if_port = 1;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-			si2157_config.mdev = dev->media_dev;
-#endif
-			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 = i2c_new_device(adapter, &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_tuner = client;
-
-		}
+		result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev);
+		if (result)
+			goto out_free;
 		break;
 	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595:
-		{
-			struct i2c_adapter *adapter;
-			struct i2c_client *client;
-			struct i2c_board_info info = {};
-			struct lgdt3306a_config lgdt3306a_config;
-			struct si2157_config si2157_config = {};
-
-			/* attach demod */
-			lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
-			lgdt3306a_config.fe = &dvb->fe[0];
-			lgdt3306a_config.i2c_adapter = &adapter;
-			strlcpy(info.type, "lgdt3306a", sizeof(info.type));
-			info.addr = 0x59;
-			info.platform_data = &lgdt3306a_config;
-			request_module(info.type);
-			client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
-					&info);
-			if (client == NULL || client->dev.driver == NULL) {
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_demod = client;
-
-			/* attach tuner */
-			si2157_config.fe = dvb->fe[0];
-			si2157_config.if_port = 1;
-			si2157_config.inversion = 1;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
-			si2157_config.mdev = dev->media_dev;
-#endif
-			memset(&info, 0, sizeof(struct i2c_board_info));
-			strlcpy(info.type, "si2157", sizeof(info.type));
-			info.addr = 0x60;
-			info.platform_data = &si2157_config;
-			request_module(info.type);
-
-			client = i2c_new_device(adapter, &info);
-			if (client == NULL || client->dev.driver == NULL) {
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-			if (!try_module_get(client->dev.driver->owner)) {
-				i2c_unregister_device(client);
-				module_put(dvb->i2c_client_demod->dev.driver->owner);
-				i2c_unregister_device(dvb->i2c_client_demod);
-				result = -ENODEV;
-				goto out_free;
-			}
-
-			dvb->i2c_client_tuner = client;
-		}
+		result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev);
+		if (result)
+			goto out_free;
 		break;
 	default:
 		dev_err(&dev->intf->dev,
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/8] media: dvb-core: add helper functions for I2C binding
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
                   ` (5 preceding siblings ...)
  2018-03-02 19:34 ` [PATCH 6/8] media: em28xx: split up em28xx_dvb_init to reduce stack size Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  2018-03-02 19:34 ` [PATCH 8/8] media: em28xx-dvb: simplify DVB module probing logic Mauro Carvalho Chehab
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

The dvb_attach()/dvb_detach() methods are ugly hacks designed
to keep using the I2C low-level API. The proper way is to
do I2C bus bindings instead.

Several modules were already converted to use it. Yet,
it is painful to use it, as lots of code need to be
duplicated.

Make it easier by providing two new helper functions:
	- dvb_module_probe()
	- dvb_module_release()

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/dvb-core/dvbdev.c | 48 ++++++++++++++++++++++++++++++
 include/media/dvbdev.h          | 65 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 60e9c2ba26be..a840133feacb 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/device.h>
@@ -941,6 +942,53 @@ int dvb_usercopy(struct file *file,
 	return err;
 }
 
+#ifdef CONFIG_I2C
+struct i2c_client *dvb_module_probe(const char *module_name,
+				    const char *name,
+				    struct i2c_adapter *adap,
+				    unsigned char addr,
+				    void *platform_data)
+{
+	struct i2c_client *client;
+	struct i2c_board_info *board_info;
+
+	board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
+
+	if (name)
+		strlcpy(board_info->type, name, I2C_NAME_SIZE);
+	else
+		strlcpy(board_info->type, module_name, I2C_NAME_SIZE);
+
+	board_info->addr = addr;
+	board_info->platform_data = platform_data;
+	request_module(module_name);
+	client = i2c_new_device(adap, board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		kfree(board_info);
+		return NULL;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		client = NULL;
+	}
+
+	kfree(board_info);
+	return client;
+}
+EXPORT_SYMBOL_GPL(dvb_module_probe);
+
+void dvb_module_release(struct i2c_client *client)
+{
+	if (!client)
+		return;
+
+	module_put(client->dev.driver->owner);
+	i2c_unregister_device(client);
+}
+EXPORT_SYMBOL_GPL(dvb_module_release);
+#endif
+
 static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct dvb_device *dvbdev = dev_get_drvdata(dev);
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index 554db879527f..2d2897508590 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -358,7 +358,61 @@ long dvb_generic_ioctl(struct file *file,
 int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 		 int (*func)(struct file *file, unsigned int cmd, void *arg));
 
-/** generic DVB attach function. */
+#ifdef CONFIG_I2C
+
+struct i2c_adapter;
+struct i2c_client;
+/**
+ * dvb_module_probe - helper routine to probe an I2C module
+ *
+ * @module_name:
+ *	Name of the I2C module to be probed
+ * @name:
+ *	Optional name for the I2C module. Used for debug purposes.
+ * 	If %NULL, defaults to @module_name.
+ * @adap:
+ *	pointer to &struct i2c_adapter that describes the I2C adapter where
+ *	the module will be bound.
+ * @addr:
+ *	I2C address of the adapter, in 7-bit notation.
+ * @platform_data:
+ *	Platform data to be passed to the I2C module probed.
+ *
+ * This function binds an I2C device into the DVB core. Should be used by
+ * all drivers that use I2C bus to control the hardware. A module bound
+ * with dvb_module_probe() should use dvb_module_release() to unbind.
+ *
+ * Return:
+ *	On success, return an &struct i2c_client, pointing the the bound
+ *	I2C device. %NULL otherwise.
+ *
+ * .. note::
+ *
+ *    In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
+ *    macro, with does an ugly hack, using I2C low level functions. Such
+ *    usage is deprecated and will be removed soon. Instead, use this routine.
+ */
+struct i2c_client *dvb_module_probe(const char *module_name,
+				    const char *name,
+				    struct i2c_adapter *adap,
+				    unsigned char addr,
+				    void *platform_data);
+
+/**
+ * dvb_module_release - releases an I2C device allocated with
+ *	 dvb_module_probe().
+ *
+ * @client: pointer to &struct i2c_client with the I2C client to be released.
+ *	    can be %NULL.
+ *
+ * This function should be used to free all resources reserved by
+ * dvb_module_probe() and unbinding the I2C hardware.
+ */
+void dvb_module_release(struct i2c_client *client);
+
+#endif /* CONFIG_I2C */
+
+/* Legacy generic DVB attach function. */
 #ifdef CONFIG_MEDIA_ATTACH
 
 /**
@@ -371,6 +425,13 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
  * the @FUNCTION function there, with @ARGS.
  * As it increments symbol usage cont, at unregister, dvb_detach()
  * should be called.
+ *
+ * .. note::
+ *
+ *    In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
+ *    macro, with does an ugly hack, using I2C low level functions. Such
+ *    usage is deprecated and will be removed soon. Instead, you should use
+ *    dvb_module_probe().
  */
 #define dvb_attach(FUNCTION, ARGS...) ({ \
 	void *__r = NULL; \
@@ -402,6 +463,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 
 #define dvb_detach(FUNC)	{}
 
-#endif
+#endif	/* CONFIG_MEDIA_ATTACH */
 
 #endif /* #ifndef _DVBDEV_H_ */
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/8] media: em28xx-dvb: simplify DVB module probing logic
  2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
                   ` (6 preceding siblings ...)
  2018-03-02 19:34 ` [PATCH 7/8] media: dvb-core: add helper functions for I2C binding Mauro Carvalho Chehab
@ 2018-03-02 19:34 ` Mauro Carvalho Chehab
  7 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-02 19:34 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

The module probing logic there is a way more complex than
it should be, and requires some special magic to avoid
stack overflows when KASAN is enabled.

Solve it by creating ancillary functions to setup the
platform data and request module.

Now, the probing functions are cleaner and easier to understand.

As a side effect, the size of the module was reduced by
about 9.7% on x86_64:

Before this patch:
   text	   data	    bss	    dec	    hex	filename
  51090	  14192	     96	  65378	   ff62	drivers/media/usb/em28xx/em28xx-dvb.o

After this patch:
   text	   data	    bss	    dec	    hex	filename
  44743	  14192	     96	  59031	   e697	drivers/media/usb/em28xx/em28xx-dvb.o

Tested with a PCTV 461e device.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
---
 drivers/media/usb/em28xx/em28xx-dvb.c | 528 +++++++++-------------------------
 1 file changed, 138 insertions(+), 390 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 28c4c7d8dbd8..435c2dc31e90 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1126,76 +1126,48 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
 	dvb_unregister_adapter(&dvb->adapter);
 }
 
-static noinline_for_stack int em28174_dvb_init_pctv_460e(struct em28xx *dev)
+static int em28174_dvb_init_pctv_460e(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
-	struct i2c_client *client;
-	struct i2c_board_info board_info;
 	struct tda10071_platform_data tda10071_pdata = {};
 	struct a8293_platform_data a8293_pdata = {};
-	int result;
 
 	/* attach demod + tuner combo */
-	tda10071_pdata.clk = 40444000, /* 40.444 MHz */
-	tda10071_pdata.i2c_wr_max = 64,
-	tda10071_pdata.ts_mode = TDA10071_TS_SERIAL,
-	tda10071_pdata.pll_multiplier = 20,
-	tda10071_pdata.tuner_i2c_addr = 0x14,
-	memset(&board_info, 0, sizeof(board_info));
-	strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE);
-	board_info.addr = 0x55;
-	board_info.platform_data = &tda10071_pdata;
-	request_module("tda10071");
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
-	dvb->i2c_client_demod = client;
+	tda10071_pdata.clk = 40444000; /* 40.444 MHz */
+	tda10071_pdata.i2c_wr_max = 64;
+	tda10071_pdata.ts_mode = TDA10071_TS_SERIAL;
+	tda10071_pdata.pll_multiplier = 20;
+	tda10071_pdata.tuner_i2c_addr = 0x14;
+
+	dvb->i2c_client_demod = dvb_module_probe("tda10071", "tda10071_cx24118",
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x55, &tda10071_pdata);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
+
+	dvb->fe[0] = tda10071_pdata.get_dvb_frontend(dvb->i2c_client_demod);
 
 	/* attach SEC */
 	a8293_pdata.dvb_frontend = dvb->fe[0];
-	memset(&board_info, 0, sizeof(board_info));
-	strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
-	board_info.addr = 0x08;
-	board_info.platform_data = &a8293_pdata;
-	request_module("a8293");
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+
+	dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
+					       &dev->i2c_adap[dev->def_i2c_bus],
+					       0x08, &a8293_pdata);
+	if (!dvb->i2c_client_sec) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->i2c_client_sec = client;
-	result = 0;
-out_free:
-	return result;
+
+	return 0;
 }
 
-static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev)
+static int em28178_dvb_init_pctv_461e(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
-	struct i2c_client *client;
 	struct i2c_adapter *i2c_adapter;
-	struct i2c_board_info board_info;
 	struct m88ds3103_platform_data m88ds3103_pdata = {};
 	struct ts2020_config ts2020_config = {};
 	struct a8293_platform_data a8293_pdata = {};
-	int result;
 
 	/* attach demod */
 	m88ds3103_pdata.clk = 27000000;
@@ -1204,184 +1176,98 @@ static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev)
 	m88ds3103_pdata.ts_clk = 16000;
 	m88ds3103_pdata.ts_clk_pol = 1;
 	m88ds3103_pdata.agc = 0x99;
-	memset(&board_info, 0, sizeof(board_info));
-	strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
-	board_info.addr = 0x68;
-	board_info.platform_data = &m88ds3103_pdata;
-	request_module("m88ds3103");
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
-	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
-	dvb->i2c_client_demod = client;
+
+	dvb->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x68, &m88ds3103_pdata);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
+
+	dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
+	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
 
 	/* attach tuner */
 	ts2020_config.fe = dvb->fe[0];
-	memset(&board_info, 0, sizeof(board_info));
-	strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
-	board_info.addr = 0x60;
-	board_info.platform_data = &ts2020_config;
-	request_module("ts2020");
-	client = i2c_new_device(i2c_adapter, &board_info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+
+	dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
+					         i2c_adapter,
+					         0x60, &ts2020_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->i2c_client_tuner = client;
+
 	/* delegate signal strength measurement to tuner */
 	dvb->fe[0]->ops.read_signal_strength =
 			dvb->fe[0]->ops.tuner_ops.get_rf_strength;
 
 	/* attach SEC */
 	a8293_pdata.dvb_frontend = dvb->fe[0];
-	memset(&board_info, 0, sizeof(board_info));
-	strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
-	board_info.addr = 0x08;
-	board_info.platform_data = &a8293_pdata;
-	request_module("a8293");
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_tuner->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_tuner);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+	dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
+				  &dev->i2c_adap[dev->def_i2c_bus],
+				  0x08, &a8293_pdata);
+	if (!dvb->i2c_client_sec) {
+		dvb_module_release(dvb->i2c_client_tuner);
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_tuner->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_tuner);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->i2c_client_sec = client;
-	result = 0;
-out_free:
-	return result;
+
+	return 0;
 }
 
-static noinline_for_stack int em28178_dvb_init_pctv_292e(struct em28xx *dev)
+static int em28178_dvb_init_pctv_292e(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
 	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	struct i2c_board_info info;
-	struct si2168_config si2168_config;
-	struct si2157_config si2157_config;
-	int result;
+	struct si2168_config si2168_config = {};
+	struct si2157_config si2157_config = {};
 
 	/* attach demod */
-	memset(&si2168_config, 0, sizeof(si2168_config));
 	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;
-	info.platform_data = &si2168_config;
-	request_module(info.type);
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_demod = client;
+	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x64, &si2168_config);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
 
 	/* attach tuner */
-	memset(&si2157_config, 0, sizeof(si2157_config));
 	si2157_config.fe = dvb->fe[0];
 	si2157_config.if_port = 1;
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 	si2157_config.mdev = dev->media_dev;
 #endif
-	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 = i2c_new_device(adapter, &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+						 adapter,
+						 0x60, &si2157_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
-
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_tuner = client;
 	dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
-	result = 0;
-out_free:
-	return result;
+
+	return 0;
 }
 
-static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
+static int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
 	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	struct i2c_board_info info;
-	struct si2168_config si2168_config;
-	struct si2157_config si2157_config;
-	int result;
+	struct si2168_config si2168_config = {};
+	struct si2157_config si2157_config = {};
 
 	/* attach demod */
-	memset(&si2168_config, 0, sizeof(si2168_config));
 	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;
-	info.platform_data = &si2168_config;
-	request_module(info.type);
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_demod = client;
+	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x64, &si2168_config);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
 
 	/* attach tuner */
 	memset(&si2157_config, 0, sizeof(si2157_config));
@@ -1390,127 +1276,65 @@ static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28x
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 	si2157_config.mdev = dev->media_dev;
 #endif
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "si2146", I2C_NAME_SIZE);
-	info.addr = 0x60;
-	info.platform_data = &si2157_config;
-	request_module("si2157");
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+	dvb->i2c_client_tuner = dvb_module_probe("si2157", "si2146",
+						 adapter,
+						 0x60, &si2157_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_tuner = client;
-	result = 0;
-out_free:
-	return result;
+	return 0;
 }
 
-static noinline_for_stack int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
+static int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
-	struct i2c_client *client;
-	struct i2c_board_info info;
-	struct tc90522_config tc90522_config;
-	struct qm1d1c0042_config qm1d1c0042_config;
-	int result;
+	struct tc90522_config tc90522_config = {};
+	struct qm1d1c0042_config qm1d1c0042_config = {};
 
 	/* attach demod */
-	memset(&tc90522_config, 0, sizeof(tc90522_config));
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
-	info.addr = 0x15;
-	info.platform_data = &tc90522_config;
-	request_module("tc90522");
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->i2c_client_demod = client;
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
+	dvb->i2c_client_demod = dvb_module_probe("tc90522", "tc90522sat",
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x15, &tc90522_config);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
 
 	/* attach tuner */
-	memset(&qm1d1c0042_config, 0,
-	       sizeof(qm1d1c0042_config));
 	qm1d1c0042_config.fe = tc90522_config.fe;
 	qm1d1c0042_config.lpf = 1;
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
-	info.addr = 0x61;
-	info.platform_data = &qm1d1c0042_config;
-	request_module(info.type);
-	client = i2c_new_device(tc90522_config.tuner_i2c,
-				&info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-	dvb->i2c_client_tuner = client;
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+
+	dvb->i2c_client_tuner = dvb_module_probe("qm1d1c0042", NULL,
+						 tc90522_config.tuner_i2c,
+						 0x61, &qm1d1c0042_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
+
 	dvb->fe[0] = tc90522_config.fe;
 	px_bcud_init(dev);
-	result = 0;
-out_free:
-	return result;
+
+	return 0;
 }
 
-static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
+static int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
 	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	struct i2c_board_info info;
-	struct si2168_config si2168_config;
-	struct si2157_config si2157_config;
-	int result;
+	struct si2168_config si2168_config = {};
+	struct si2157_config si2157_config = {};
 
 	/* attach demod */
-	memset(&si2168_config, 0, sizeof(si2168_config));
 	si2168_config.i2c_adapter = &adapter;
 	si2168_config.fe = &dvb->fe[0];
 	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 = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_demod = client;
+	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x64, &si2168_config);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
 
 	/* attach tuner */
 	memset(&si2157_config, 0, sizeof(si2157_config));
@@ -1519,65 +1343,34 @@ static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 	si2157_config.mdev = dev->media_dev;
 #endif
-	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 = i2c_new_device(adapter, &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+						 adapter,
+						 0x60, &si2157_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_tuner = client;
-	result = 0;
-out_free:
-	return result;
+	return 0;
 }
 
 static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb = dev->dvb;
 	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	struct i2c_board_info info = {};
-	struct lgdt3306a_config lgdt3306a_config;
+	struct lgdt3306a_config lgdt3306a_config =  {};
 	struct si2157_config si2157_config = {};
-	int result;
 
 	/* attach demod */
 	lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
 	lgdt3306a_config.fe = &dvb->fe[0];
 	lgdt3306a_config.i2c_adapter = &adapter;
-	strlcpy(info.type, "lgdt3306a", sizeof(info.type));
-	info.addr = 0x59;
-	info.platform_data = &lgdt3306a_config;
-	request_module(info.type);
-	client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
-			&info);
-	if (client == NULL || client->dev.driver == NULL) {
-		result = -ENODEV;
-		goto out_free;
-	}
 
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		result = -ENODEV;
-		goto out_free;
-	}
-
-	dvb->i2c_client_demod = client;
+	dvb->i2c_client_demod = dvb_module_probe("lgdt3306a", NULL,
+						 &dev->i2c_adap[dev->def_i2c_bus],
+						 0x59, &lgdt3306a_config);
+	if (!dvb->i2c_client_demod)
+		return -ENODEV;
 
 	/* attach tuner */
 	si2157_config.fe = dvb->fe[0];
@@ -1586,32 +1379,17 @@ static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
 	si2157_config.mdev = dev->media_dev;
 #endif
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	strlcpy(info.type, "si2157", sizeof(info.type));
-	info.addr = 0x60;
-	info.platform_data = &si2157_config;
-	request_module(info.type);
-
-	client = i2c_new_device(adapter, &info);
-	if (client == NULL || client->dev.driver == NULL) {
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
-	}
-	if (!try_module_get(client->dev.driver->owner)) {
-		i2c_unregister_device(client);
-		module_put(dvb->i2c_client_demod->dev.driver->owner);
-		i2c_unregister_device(dvb->i2c_client_demod);
-		result = -ENODEV;
-		goto out_free;
+	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+						 adapter,
+						 0x60, &si2157_config);
+	if (!dvb->i2c_client_tuner) {
+		dvb_module_release(dvb->i2c_client_demod);
+		return -ENODEV;
 	}
 
-	dvb->i2c_client_tuner = client;
-	result = 0;
-out_free:
-	return result;
+	return 0;
 }
+
 static int em28xx_dvb_init(struct em28xx *dev)
 {
 	int result = 0;
@@ -1846,7 +1624,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
 		break;
 	case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
 	{
-		struct xc5000_config cfg;
+		struct xc5000_config cfg = {};
 
 		hauppauge_hvr930c_init(dev);
 
@@ -1863,7 +1641,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
 		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
 
 		/* Attach xc5000 */
-		memset(&cfg, 0, sizeof(cfg));
 		cfg.i2c_address  = 0x61;
 		cfg.if_khz = 4000;
 
@@ -2016,13 +1793,7 @@ 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,
@@ -2034,22 +1805,16 @@ static int em28xx_dvb_init(struct em28xx *dev)
 
 		/* 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->i2c_client_tuner = dvb_module_probe("tda18212", NULL,
+							 adapter,
+							 0x60,
+							 &kworld_ub435q_v3_config);
+		if (!dvb->i2c_client_tuner) {
 			dvb_frontend_detach(dvb->fe[0]);
 			result = -ENODEV;
 			goto out_free;
 		}
-
-		dvb->i2c_client_tuner = client;
 		break;
 	}
 	case EM2874_BOARD_PCTV_HD_MINI_80E:
@@ -2140,7 +1905,6 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
 static int em28xx_dvb_fini(struct em28xx *dev)
 {
 	struct em28xx_dvb *dvb;
-	struct i2c_client *client;
 
 	if (dev->is_audio_only) {
 		/* Shouldn't initialize IR for this interface */
@@ -2176,26 +1940,10 @@ static int em28xx_dvb_fini(struct em28xx *dev)
 
 	em28xx_unregister_dvb(dvb);
 
-	/* remove I2C SEC */
-	client = dvb->i2c_client_sec;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
-
-	/* remove I2C tuner */
-	client = dvb->i2c_client_tuner;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
-
-	/* remove I2C demod */
-	client = dvb->i2c_client_demod;
-	if (client) {
-		module_put(client->dev.driver->owner);
-		i2c_unregister_device(client);
-	}
+	/* release I2C module bindings */
+	dvb_module_release(dvb->i2c_client_sec);
+	dvb_module_release(dvb->i2c_client_tuner);
+	dvb_module_release(dvb->i2c_client_demod);
 
 	kfree(dvb);
 	dev->dvb = NULL;
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed
  2018-03-02 19:34 ` [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed Mauro Carvalho Chehab
@ 2018-03-03 19:00   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-03 19:00 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab

Em Fri,  2 Mar 2018 16:34:46 -0300
Mauro Carvalho Chehab <mchehab@s-opensource.com> escreveu:

> +	switch (dev->i2c_speed & 0x03) {
> +	case EM28XX_I2C_FREQ_25_KHZ:
> +		return time += 4;		/* Assume 4 ms for transfers */
> +		break;

This is obviously wrong. The right patch is enclosed.

Regards,
Mauro


[PATCH v2] media: em28xx: adjust I2C timeout according with I2C speed

If the I2C speed is too slow, it should wait more for an
answer.

While here, change disconnected type from char to unsigned
int, just like all other bitmask fields there at em28xx
struct.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 8648426d3448..4f08e35eddee 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2688,6 +2688,8 @@ static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
 		i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
 			    EM28XX_I2C_FREQ_100_KHZ;
 
+	dev->i2c_speed = i2c_speed & 0x03;
+
 	if (!dev->board.is_em2800)
 		em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed);
 	msleep(50);
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 9bf49d666e5a..e9892a98eb6e 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -51,13 +51,43 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I
 } while (0)
 
 
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT         35 /* ms */
+
+static int em28xx_i2c_timeout(struct em28xx *dev)
+{
+	int time = EM28XX_I2C_XFER_TIMEOUT;
+
+	switch (dev->i2c_speed & 0x03) {
+	case EM28XX_I2C_FREQ_25_KHZ:
+		time += 4;		/* Assume 4 ms for transfers */
+		break;
+	case EM28XX_I2C_FREQ_100_KHZ:
+	case EM28XX_I2C_FREQ_400_KHZ:
+		time += 1;		/* Assume 1 ms for transfers */
+		break;
+	default: /* EM28XX_I2C_FREQ_1_5_MHZ */
+		break;
+	}
+
+	return msecs_to_jiffies(time);
+}
+
 /*
  * em2800_i2c_send_bytes()
  * send up to 4 bytes to the em2800 i2c device
  */
 static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	int ret;
 	u8 b2[6];
 
@@ -110,7 +140,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
  */
 static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	u8 buf2[4];
 	int ret;
 	int i;
@@ -186,7 +216,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
 static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 				 u16 len, int stop)
 {
-	unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+	unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
 	int ret;
 
 	if (len < 1 || len > 64)
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index b23f323b5c99..220e7a7a6124 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -195,22 +195,6 @@
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
-/*
- * Time in msecs to wait for i2c xfers to finish.
- * 35ms is the maximum time a SMBUS device could wait when
- * clock stretching is used. As the transfer itself will take
- * some time to happen, set it to 35 ms.
- *
- * Ok, I2C doesn't specify any limit. So, eventually, we may need
- * to increase this timeout.
- *
- * FIXME: this assumes that an I2C message is not longer than 1ms.
- * This is actually dependent on the I2C bus speed, although most
- * devices use a 100kHz clock. So, this assumtion is true most of
- * the time.
- */
-#define EM28XX_I2C_XFER_TIMEOUT		36
-
 /* time in msecs to wait for AC97 xfers to finish */
 #define EM28XX_AC97_XFER_TIMEOUT	100
 
@@ -616,11 +600,12 @@ struct em28xx {
 	enum em28xx_chip_id chip_id;
 
 	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
-	unsigned char disconnected:1;	/* device has been diconnected */
+	unsigned int disconnected:1;	/* device has been diconnected */
 	unsigned int has_video:1;
 	unsigned int is_audio_only:1;
 	unsigned int is_webcam:1;
 	unsigned int has_msp34xx:1;
+	unsigned int i2c_speed:2;
 	enum em28xx_int_audio_type int_audio_type;
 	enum em28xx_usb_audio_type usb_audio_type;
 

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-03-03 19:00 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-02 19:34 [PATCH 0/8] em28xx: some improvements Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 1/8] media: em28xx: don't use coherent buffer for DMA transfers Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 2/8] media: em28xx: improve the logic with sets Xclk and I2C speed Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 3/8] media: em28xx: stop rewriting device's struct Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 4/8] media: em28xx: constify most static structs Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 5/8] media: em28xx: adjust I2C timeout according with I2C speed Mauro Carvalho Chehab
2018-03-03 19:00   ` Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 6/8] media: em28xx: split up em28xx_dvb_init to reduce stack size Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 7/8] media: dvb-core: add helper functions for I2C binding Mauro Carvalho Chehab
2018-03-02 19:34 ` [PATCH 8/8] media: em28xx-dvb: simplify DVB module probing logic Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).