All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/22] em28xx: split analog part into a separate module
@ 2014-01-04 10:55 Mauro Carvalho Chehab
  2014-01-04 10:55 ` [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video Mauro Carvalho Chehab
                   ` (21 more replies)
  0 siblings, 22 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=true, Size: 2841 bytes --]

This patch series split em28xx into a separate V4L2 driver,
allowing the new dvb-only chips to be supported without requiring
V4L2.

While testing the original patchset, I noticed several issues with
HVR-950. The remaining patches on this series fix most of those
issues.

There's one remaining issue: connecting an em28xx device into an USB 3.0
port is known to have issues. This is not addressed on this patch series.

v4:
	- Fixed the issues pointed by Frank Shäfer;
	- Removed I2C write retry patch from this series;
	- Removed experimental patch that removes URB_ISO_ASAP from
	  the urb::transfer_flags.

The removed patches are experimental, and will be submitted in
separate.

Mauro Carvalho Chehab (22):
  [media] em28xx: move some video-specific functions to em28xx-video
  [media] em28xx: some cosmetic changes
  [media] em28xx: move analog-specific init to em28xx-video
  [media] em28xx: make em28xx-video to be a separate module
  [media] em28xx: initialize analog I2C devices at the right place
  [media] em28xx: add warn messages for timeout
  [media] em28xx: improve extension information messages
  [media] em28xx: convert i2c wait completion logic to use jiffies
  [media] tvp5150: make read operations atomic
  [media] tuner-xc2028: remove unused code
  [media] em28xx: check if a device has audio earlier
  [media] em28xx: properly implement AC97 wait code
  [media] em28xx: initialize audio latter
  [media] em28xx: unify module version
  [media] em28xx: Fix em28xx deplock
  [media] em28xx: use a better value for I2C timeouts
  [media] em28xx-i2c: Fix error code for I2C error transfers
  [media] em28xx: don't return -ENODEV for I2C xfer errors
  [media] em28xx: cleanup I2C debug messages
  [media] em28xx: use usb_alloc_coherent() for audio
  [media] em28xx-audio: allocate URBs at device driver init
  [media] em28xx: retry read operation if it fails

 drivers/media/i2c/tvp5150.c              |  26 +-
 drivers/media/tuners/tuner-xc2028.c      |   9 -
 drivers/media/usb/em28xx/Kconfig         |   6 +-
 drivers/media/usb/em28xx/Makefile        |   5 +-
 drivers/media/usb/em28xx/em28xx-audio.c  | 134 ++++---
 drivers/media/usb/em28xx/em28xx-camera.c |   1 +
 drivers/media/usb/em28xx/em28xx-cards.c  | 305 ++--------------
 drivers/media/usb/em28xx/em28xx-core.c   | 292 +--------------
 drivers/media/usb/em28xx/em28xx-dvb.c    |  11 +-
 drivers/media/usb/em28xx/em28xx-i2c.c    | 237 ++++++------
 drivers/media/usb/em28xx/em28xx-input.c  |   7 +-
 drivers/media/usb/em28xx/em28xx-v4l.h    |  20 ++
 drivers/media/usb/em28xx/em28xx-vbi.c    |   1 +
 drivers/media/usb/em28xx/em28xx-video.c  | 598 +++++++++++++++++++++++++++++--
 drivers/media/usb/em28xx/em28xx.h        |  52 +--
 15 files changed, 905 insertions(+), 799 deletions(-)
 create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h

-- 
1.8.3.1


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

* [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:11   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 02/22] [media] em28xx: some cosmetic changes Mauro Carvalho Chehab
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Now that we want to split the video handling to a separate
module, move all video-specific functions to em28xx-video.

No functional changes.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 107 ---------
 drivers/media/usb/em28xx/em28xx-core.c  | 259 ----------------------
 drivers/media/usb/em28xx/em28xx-video.c | 374 +++++++++++++++++++++++++++++++-
 drivers/media/usb/em28xx/em28xx.h       |   1 +
 4 files changed, 371 insertions(+), 370 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 36853f16bf97..19827e79cf53 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2529,113 +2529,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 }
 
-static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
-{
-	memset(ctl, 0, sizeof(*ctl));
-
-	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
-	ctl->max_len = 64;
-	ctl->mts = em28xx_boards[dev->model].mts_firmware;
-
-	switch (dev->model) {
-	case EM2880_BOARD_EMPIRE_DUAL_TV:
-	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-	case EM2882_BOARD_TERRATEC_HYBRID_XS:
-		ctl->demod = XC3028_FE_ZARLINK456;
-		break;
-	case EM2880_BOARD_TERRATEC_HYBRID_XS:
-	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
-	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
-		ctl->demod = XC3028_FE_ZARLINK456;
-		break;
-	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
-		ctl->demod = XC3028_FE_DEFAULT;
-		break;
-	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
-		ctl->demod = XC3028_FE_DEFAULT;
-		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
-		break;
-	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
-	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
-	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
-		/* FIXME: Better to specify the needed IF */
-		ctl->demod = XC3028_FE_DEFAULT;
-		break;
-	case EM2883_BOARD_KWORLD_HYBRID_330U:
-	case EM2882_BOARD_DIKOM_DK300:
-	case EM2882_BOARD_KWORLD_VS_DVBT:
-		ctl->demod = XC3028_FE_CHINA;
-		ctl->fname = XC2028_DEFAULT_FIRMWARE;
-		break;
-	case EM2882_BOARD_EVGA_INDTUBE:
-		ctl->demod = XC3028_FE_CHINA;
-		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
-		break;
-	default:
-		ctl->demod = XC3028_FE_OREN538;
-	}
-}
-
-static void em28xx_tuner_setup(struct em28xx *dev)
-{
-	struct tuner_setup           tun_setup;
-	struct v4l2_frequency        f;
-
-	if (dev->tuner_type == TUNER_ABSENT)
-		return;
-
-	memset(&tun_setup, 0, sizeof(tun_setup));
-
-	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-	tun_setup.tuner_callback = em28xx_tuner_callback;
-
-	if (dev->board.radio.type) {
-		tun_setup.type = dev->board.radio.type;
-		tun_setup.addr = dev->board.radio_addr;
-
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-	}
-
-	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
-		tun_setup.type   = dev->tuner_type;
-		tun_setup.addr   = dev->tuner_addr;
-
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-	}
-
-	if (dev->tda9887_conf) {
-		struct v4l2_priv_tun_config tda9887_cfg;
-
-		tda9887_cfg.tuner = TUNER_TDA9887;
-		tda9887_cfg.priv = &dev->tda9887_conf;
-
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
-	}
-
-	if (dev->tuner_type == TUNER_XC2028) {
-		struct v4l2_priv_tun_config  xc2028_cfg;
-		struct xc2028_ctrl           ctl;
-
-		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
-		memset(&ctl, 0, sizeof(ctl));
-
-		em28xx_setup_xc3028(dev, &ctl);
-
-		xc2028_cfg.tuner = TUNER_XC2028;
-		xc2028_cfg.priv  = &ctl;
-
-		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
-	}
-
-	/* configure tuner */
-	f.tuner = 0;
-	f.type = V4L2_TUNER_ANALOG_TV;
-	f.frequency = 9076;     /* just a magic number */
-	dev->ctl_freq = f.frequency;
-	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-}
-
 static int em28xx_hint_board(struct em28xx *dev)
 {
 	int i;
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index f6076a512e8f..3012912d2997 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -53,14 +53,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
 		printk(KERN_INFO "%s %s :"fmt, \
 			 dev->name, __func__ , ##arg); } while (0)
 
-static int alt;
-module_param(alt, int, 0644);
-MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-static unsigned int disable_vbi;
-module_param(disable_vbi, int, 0644);
-MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-
 /* FIXME */
 #define em28xx_isocdbg(fmt, arg...) do {\
 	if (core_debug) \
@@ -603,24 +595,6 @@ init_audio:
 }
 EXPORT_SYMBOL_GPL(em28xx_audio_setup);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev)
-{
-	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
-	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
-	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
-	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
-	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
-	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
-
-	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
-	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
-	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
-	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
-	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
-	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
-	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
-}
-
 const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
 					 enum em28xx_led_role role)
 {
@@ -696,227 +670,6 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 	return rc;
 }
 
-int em28xx_vbi_supported(struct em28xx *dev)
-{
-	/* Modprobe option to manually disable */
-	if (disable_vbi == 1)
-		return 0;
-
-	if (dev->board.is_webcam)
-		return 0;
-
-	/* FIXME: check subdevices for VBI support */
-
-	if (dev->chip_id == CHIP_ID_EM2860 ||
-	    dev->chip_id == CHIP_ID_EM2883)
-		return 1;
-
-	/* Version of em28xx that does not support VBI */
-	return 0;
-}
-
-int em28xx_set_outfmt(struct em28xx *dev)
-{
-	int ret;
-	u8 fmt, vinctrl;
-
-	fmt = dev->format->reg;
-	if (!dev->is_em25xx)
-		fmt |= 0x20;
-	/*
-	 * NOTE: it's not clear if this is really needed !
-	 * The datasheets say bit 5 is a reserved bit and devices seem to work
-	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
-	 * devices and we've always been setting it, too.
-	 *
-	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
-	 * it's likely used for an additional (compressed ?) format there.
-	 */
-	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
-	if (ret < 0)
-		return ret;
-
-	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
-	if (ret < 0)
-		return ret;
-
-	vinctrl = dev->vinctl;
-	if (em28xx_vbi_supported(dev) == 1) {
-		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
-		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
-		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
-		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
-		if (dev->norm & V4L2_STD_525_60) {
-			/* NTSC */
-			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
-		} else if (dev->norm & V4L2_STD_625_50) {
-			/* PAL */
-			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
-		}
-	}
-
-	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
-}
-
-static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
-				  u8 ymin, u8 ymax)
-{
-	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
-			xmin, ymin, xmax, ymax);
-
-	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
-	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
-	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
-	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
-}
-
-static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
-				   u16 width, u16 height)
-{
-	u8 cwidth = width >> 2;
-	u8 cheight = height >> 2;
-	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
-	/* NOTE: size limit: 2047x1023 = 2MPix */
-
-	em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
-		       hstart, vstart,
-		       ((overflow & 2) << 9 | cwidth << 2),
-		       ((overflow & 1) << 10 | cheight << 2));
-
-	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
-	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
-	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
-	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
-	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
-
-	/* FIXME: function/meaning of these registers ? */
-	/* FIXME: align width+height to multiples of 4 ?! */
-	if (dev->is_em25xx) {
-		em28xx_write_reg(dev, 0x34, width >> 4);
-		em28xx_write_reg(dev, 0x35, height >> 4);
-	}
-}
-
-static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
-{
-	u8 mode;
-	/* the em2800 scaler only supports scaling down to 50% */
-
-	if (dev->board.is_em2800) {
-		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
-	} else {
-		u8 buf[2];
-
-		buf[0] = h;
-		buf[1] = h >> 8;
-		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
-
-		buf[0] = v;
-		buf[1] = v >> 8;
-		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
-		/* it seems that both H and V scalers must be active
-		   to work correctly */
-		mode = (h || v) ? 0x30 : 0x00;
-	}
-	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
-}
-
-/* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
-{
-	int width, height;
-	width = norm_maxw(dev);
-	height = norm_maxh(dev);
-
-	/* Properly setup VBI */
-	dev->vbi_width = 720;
-	if (dev->norm & V4L2_STD_525_60)
-		dev->vbi_height = 12;
-	else
-		dev->vbi_height = 18;
-
-	em28xx_set_outfmt(dev);
-
-	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
-
-	/* If we don't set the start position to 2 in VBI mode, we end up
-	   with line 20/21 being YUYV encoded instead of being in 8-bit
-	   greyscale.  The core of the issue is that line 21 (and line 23 for
-	   PAL WSS) are inside of active video region, and as a result they
-	   get the pixelformatting associated with that area.  So by cropping
-	   it out, we end up with the same format as the rest of the VBI
-	   region */
-	if (em28xx_vbi_supported(dev) == 1)
-		em28xx_capture_area_set(dev, 0, 2, width, height);
-	else
-		em28xx_capture_area_set(dev, 0, 0, width, height);
-
-	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
-}
-
-/* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
-{
-	int errCode;
-	int i;
-	unsigned int min_pkt_size = dev->width * 2 + 4;
-
-	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
-		 bulk transfers seem to work only with alt=0 ! */
-	dev->alt = 0;
-	if ((alt > 0) && (alt < dev->num_alt)) {
-		em28xx_coredbg("alternate forced to %d\n", dev->alt);
-		dev->alt = alt;
-		goto set_alt;
-	}
-	if (dev->analog_xfer_bulk)
-		goto set_alt;
-
-	/* When image size is bigger than a certain value,
-	   the frame size should be increased, otherwise, only
-	   green screen will be received.
-	 */
-	if (dev->width * 2 * dev->height > 720 * 240 * 2)
-		min_pkt_size *= 2;
-
-	for (i = 0; i < dev->num_alt; i++) {
-		/* stop when the selected alt setting offers enough bandwidth */
-		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
-			dev->alt = i;
-			break;
-		/* otherwise make sure that we end up with the maximum bandwidth
-		   because the min_pkt_size equation might be wrong...
-		*/
-		} else if (dev->alt_max_pkt_size_isoc[i] >
-			   dev->alt_max_pkt_size_isoc[dev->alt])
-			dev->alt = i;
-	}
-
-set_alt:
-	/* NOTE: for bulk transfers, we need to call usb_set_interface()
-	 * even if the previous settings were the same. Otherwise streaming
-	 * fails with all urbs having status = -EOVERFLOW ! */
-	if (dev->analog_xfer_bulk) {
-		dev->max_pkt_size = 512; /* USB 2.0 spec */
-		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
-	} else { /* isoc */
-		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
-			       min_pkt_size, dev->alt);
-		dev->max_pkt_size =
-				  dev->alt_max_pkt_size_isoc[dev->alt];
-		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
-	}
-	em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
-		       dev->alt, dev->max_pkt_size);
-	errCode = usb_set_interface(dev->udev, 0, dev->alt);
-	if (errCode < 0) {
-		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
-			      dev->alt, errCode);
-		return errCode;
-	}
-	return 0;
-}
-
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
 {
 	int rc = 0;
@@ -1282,18 +1035,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
 EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
 
 /*
- * em28xx_wake_i2c()
- * configure i2c attached devices
- */
-void em28xx_wake_i2c(struct em28xx *dev)
-{
-	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
-	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
-			INPUT(dev->ctl_input)->vmux, 0, 0);
-	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-}
-
-/*
  * Device control list
  */
 
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index dd19c9ff76e0..70ffe259df5b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -53,15 +53,23 @@
 
 #define EM28XX_VERSION "0.2.0"
 
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
+
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
 #define em28xx_videodbg(fmt, arg...) do {\
 	if (video_debug) \
 		printk(KERN_INFO "%s %s :"fmt, \
 			 dev->name, __func__ , ##arg); } while (0)
 
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
 #define em28xx_isocdbg(fmt, arg...) \
 do {\
 	if (isoc_debug) { \
@@ -135,6 +143,257 @@ static struct em28xx_fmt format[] = {
 	},
 };
 
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+			INPUT(dev->ctl_input)->vmux, 0, 0);
+	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
+
+	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+int em28xx_set_outfmt(struct em28xx *dev)
+{
+	int ret;
+	u8 fmt, vinctrl;
+
+	fmt = dev->format->reg;
+	if (!dev->is_em25xx)
+		fmt |= 0x20;
+	/*
+	 * NOTE: it's not clear if this is really needed !
+	 * The datasheets say bit 5 is a reserved bit and devices seem to work
+	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
+	 * devices and we've always been setting it, too.
+	 *
+	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+	 * it's likely used for an additional (compressed ?) format there.
+	 */
+	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+	if (ret < 0)
+		return ret;
+
+	vinctrl = dev->vinctl;
+	if (em28xx_vbi_supported(dev) == 1) {
+		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+		if (dev->norm & V4L2_STD_525_60) {
+			/* NTSC */
+			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+		} else if (dev->norm & V4L2_STD_625_50) {
+			/* PAL */
+			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+		}
+	}
+
+	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+				  u8 ymin, u8 ymax)
+{
+	em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+			xmin, ymin, xmax, ymax);
+
+	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+				   u16 width, u16 height)
+{
+	u8 cwidth = width >> 2;
+	u8 cheight = height >> 2;
+	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
+	/* NOTE: size limit: 2047x1023 = 2MPix */
+
+	em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
+		       hstart, vstart,
+		       ((overflow & 2) << 9 | cwidth << 2),
+		       ((overflow & 1) << 10 | cheight << 2));
+
+	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+	/* FIXME: function/meaning of these registers ? */
+	/* FIXME: align width+height to multiples of 4 ?! */
+	if (dev->is_em25xx) {
+		em28xx_write_reg(dev, 0x34, width >> 4);
+		em28xx_write_reg(dev, 0x35, height >> 4);
+	}
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+	u8 mode;
+	/* the em2800 scaler only supports scaling down to 50% */
+
+	if (dev->board.is_em2800) {
+		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+	} else {
+		u8 buf[2];
+
+		buf[0] = h;
+		buf[1] = h >> 8;
+		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+		buf[0] = v;
+		buf[1] = v >> 8;
+		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+		/* it seems that both H and V scalers must be active
+		   to work correctly */
+		mode = (h || v) ? 0x30 : 0x00;
+	}
+	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+	int width, height;
+	width = norm_maxw(dev);
+	height = norm_maxh(dev);
+
+	/* Properly setup VBI */
+	dev->vbi_width = 720;
+	if (dev->norm & V4L2_STD_525_60)
+		dev->vbi_height = 12;
+	else
+		dev->vbi_height = 18;
+
+	em28xx_set_outfmt(dev);
+
+	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+	/* If we don't set the start position to 2 in VBI mode, we end up
+	   with line 20/21 being YUYV encoded instead of being in 8-bit
+	   greyscale.  The core of the issue is that line 21 (and line 23 for
+	   PAL WSS) are inside of active video region, and as a result they
+	   get the pixelformatting associated with that area.  So by cropping
+	   it out, we end up with the same format as the rest of the VBI
+	   region */
+	if (em28xx_vbi_supported(dev) == 1)
+		em28xx_capture_area_set(dev, 0, 2, width, height);
+	else
+		em28xx_capture_area_set(dev, 0, 0, width, height);
+
+	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+int em28xx_vbi_supported(struct em28xx *dev)
+{
+	/* Modprobe option to manually disable */
+	if (disable_vbi == 1)
+		return 0;
+
+	if (dev->board.is_webcam)
+		return 0;
+
+	/* FIXME: check subdevices for VBI support */
+
+	if (dev->chip_id == CHIP_ID_EM2860 ||
+	    dev->chip_id == CHIP_ID_EM2883)
+		return 1;
+
+	/* Version of em28xx that does not support VBI */
+	return 0;
+}
+
+/* Set USB alternate setting for analog video */
+int em28xx_set_alternate(struct em28xx *dev)
+{
+	int errCode;
+	int i;
+	unsigned int min_pkt_size = dev->width * 2 + 4;
+
+	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
+		 bulk transfers seem to work only with alt=0 ! */
+	dev->alt = 0;
+	if ((alt > 0) && (alt < dev->num_alt)) {
+		em28xx_videodbg("alternate forced to %d\n", dev->alt);
+		dev->alt = alt;
+		goto set_alt;
+	}
+	if (dev->analog_xfer_bulk)
+		goto set_alt;
+
+	/* When image size is bigger than a certain value,
+	   the frame size should be increased, otherwise, only
+	   green screen will be received.
+	 */
+	if (dev->width * 2 * dev->height > 720 * 240 * 2)
+		min_pkt_size *= 2;
+
+	for (i = 0; i < dev->num_alt; i++) {
+		/* stop when the selected alt setting offers enough bandwidth */
+		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
+			dev->alt = i;
+			break;
+		/* otherwise make sure that we end up with the maximum bandwidth
+		   because the min_pkt_size equation might be wrong...
+		*/
+		} else if (dev->alt_max_pkt_size_isoc[i] >
+			   dev->alt_max_pkt_size_isoc[dev->alt])
+			dev->alt = i;
+	}
+
+set_alt:
+	/* NOTE: for bulk transfers, we need to call usb_set_interface()
+	 * even if the previous settings were the same. Otherwise streaming
+	 * fails with all urbs having status = -EOVERFLOW ! */
+	if (dev->analog_xfer_bulk) {
+		dev->max_pkt_size = 512; /* USB 2.0 spec */
+		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
+	} else { /* isoc */
+		em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
+			       min_pkt_size, dev->alt);
+		dev->max_pkt_size =
+				  dev->alt_max_pkt_size_isoc[dev->alt];
+		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
+	}
+	em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
+		       dev->alt, dev->max_pkt_size);
+	errCode = usb_set_interface(dev->udev, 0, dev->alt);
+	if (errCode < 0) {
+		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+			      dev->alt, errCode);
+		return errCode;
+	}
+	return 0;
+}
+
 /* ------------------------------------------------------------------
 	DMA and thread functions
    ------------------------------------------------------------------*/
@@ -1817,6 +2076,113 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 	return vfd;
 }
 
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+	memset(ctl, 0, sizeof(*ctl));
+
+	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+	ctl->max_len = 64;
+	ctl->mts = em28xx_boards[dev->model].mts_firmware;
+
+	switch (dev->model) {
+	case EM2880_BOARD_EMPIRE_DUAL_TV:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2882_BOARD_TERRATEC_HYBRID_XS:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
+	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+		ctl->demod = XC3028_FE_ZARLINK456;
+		break;
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
+	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+		ctl->demod = XC3028_FE_DEFAULT;
+		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+		break;
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+		/* FIXME: Better to specify the needed IF */
+		ctl->demod = XC3028_FE_DEFAULT;
+		break;
+	case EM2883_BOARD_KWORLD_HYBRID_330U:
+	case EM2882_BOARD_DIKOM_DK300:
+	case EM2882_BOARD_KWORLD_VS_DVBT:
+		ctl->demod = XC3028_FE_CHINA;
+		ctl->fname = XC2028_DEFAULT_FIRMWARE;
+		break;
+	case EM2882_BOARD_EVGA_INDTUBE:
+		ctl->demod = XC3028_FE_CHINA;
+		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+		break;
+	default:
+		ctl->demod = XC3028_FE_OREN538;
+	}
+}
+
+void em28xx_tuner_setup(struct em28xx *dev)
+{
+	struct tuner_setup           tun_setup;
+	struct v4l2_frequency        f;
+
+	if (dev->tuner_type == TUNER_ABSENT)
+		return;
+
+	memset(&tun_setup, 0, sizeof(tun_setup));
+
+	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+	tun_setup.tuner_callback = em28xx_tuner_callback;
+
+	if (dev->board.radio.type) {
+		tun_setup.type = dev->board.radio.type;
+		tun_setup.addr = dev->board.radio_addr;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+	}
+
+	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+		tun_setup.type   = dev->tuner_type;
+		tun_setup.addr   = dev->tuner_addr;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+	}
+
+	if (dev->tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
+	}
+
+	if (dev->tuner_type == TUNER_XC2028) {
+		struct v4l2_priv_tun_config  xc2028_cfg;
+		struct xc2028_ctrl           ctl;
+
+		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+		memset(&ctl, 0, sizeof(ctl));
+
+		em28xx_setup_xc3028(dev, &ctl);
+
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+	}
+
+	/* configure tuner */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 9076;     /* just a magic number */
+	dev->ctl_freq = f.frequency;
+	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+}
+
 int em28xx_register_analog_devices(struct em28xx *dev)
 {
 	u8 val;
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 191ef3593891..0259270dda46 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -748,6 +748,7 @@ void em28xx_init_extension(struct em28xx *dev);
 void em28xx_close_extension(struct em28xx *dev);
 
 /* Provided by em28xx-video.c */
+void em28xx_tuner_setup(struct em28xx *dev);
 int em28xx_vb2_setup(struct em28xx *dev);
 int em28xx_register_analog_devices(struct em28xx *dev);
 void em28xx_release_analog_resources(struct em28xx *dev);
-- 
1.8.3.1


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

* [PATCH v4 02/22] [media] em28xx: some cosmetic changes
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
  2014-01-04 10:55 ` [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:13   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video Mauro Carvalho Chehab
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

In order to make easier for the next patches, do some
cosmetic changes.

No functional changes.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c |  2 +-
 drivers/media/usb/em28xx/em28xx-video.c |  2 --
 drivers/media/usb/em28xx/em28xx.h       | 11 ++++++-----
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 19827e79cf53..551cbc294190 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2106,7 +2106,7 @@ struct em28xx_board em28xx_boards[] = {
 	},
 	/* 1b80:e1cc Delock 61959
 	 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
-         * mostly the same as MaxMedia UB-425-TC but different remote */
+	 * mostly the same as MaxMedia UB-425-TC but different remote */
 	[EM2874_BOARD_DELOCK_61959] = {
 		.name          = "Delock 61959",
 		.tuner_type    = TUNER_ABSENT,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 70ffe259df5b..8b8a4eb96875 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -51,8 +51,6 @@
 
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
 
-#define EM28XX_VERSION "0.2.0"
-
 static unsigned int isoc_debug;
 module_param(isoc_debug, int, 0644);
 MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 0259270dda46..7ae05ebc13c1 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,6 +26,8 @@
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
+#define EM28XX_VERSION "0.2.0"
+
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
@@ -522,9 +524,12 @@ struct em28xx {
 	int model;		/* index in the device_data struct */
 	int devno;		/* marks the number of this device */
 	enum em28xx_chip_id chip_id;
-	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
 
+	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
 	unsigned char disconnected:1;	/* device has been diconnected */
+	unsigned int has_audio_class:1;
+	unsigned int has_alsa_audio:1;
+	unsigned int is_audio_only:1;
 
 	int audio_ifnum;
 
@@ -544,10 +549,6 @@ struct em28xx {
 	/* Vinmode/Vinctl used at the driver */
 	int vinmode, vinctl;
 
-	unsigned int has_audio_class:1;
-	unsigned int has_alsa_audio:1;
-	unsigned int is_audio_only:1;
-
 	/* Controls audio streaming */
 	struct work_struct wq_trigger;	/* Trigger to start/stop audio for alsa module */
 	atomic_t       stream_started;	/* stream should be running if true */
-- 
1.8.3.1


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

* [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
  2014-01-04 10:55 ` [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video Mauro Carvalho Chehab
  2014-01-04 10:55 ` [PATCH v4 02/22] [media] em28xx: some cosmetic changes Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:26   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module Mauro Carvalho Chehab
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

There are several init code inside em28xx-cards that are actually
part of analog initialization. Move the code to em28x-video, in
order to remove part of the mess.

In thesis, no functional changes so far.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 71 -------------------------
 drivers/media/usb/em28xx/em28xx-video.c | 91 ++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 78 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 551cbc294190..175cd776e0a1 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2907,7 +2907,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 			   struct usb_interface *interface,
 			   int minor)
 {
-	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 	int retval;
 	static const char *default_chip_name = "em28xx";
 	const char *chip_name = default_chip_name;
@@ -3034,15 +3033,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		}
 	}
 
-	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
-	if (retval < 0) {
-		em28xx_errdev("Call to v4l2_device_register() failed!\n");
-		return retval;
-	}
-
-	v4l2_ctrl_handler_init(hdl, 8);
-	dev->v4l2_dev.ctrl_handler = hdl;
-
 	rt_mutex_init(&dev->i2c_bus_lock);
 
 	/* register i2c bus 0 */
@@ -3071,72 +3061,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		}
 	}
 
-	/*
-	 * Default format, used for tvp5150 or saa711x output formats
-	 */
-	dev->vinmode = 0x10;
-	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
-		       EM28XX_VINCTRL_CCIR656_ENABLE;
-
 	/* Do board specific init and eeprom reading */
 	em28xx_card_setup(dev);
 
-	/* Configure audio */
-	retval = em28xx_audio_setup(dev);
-	if (retval < 0) {
-		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
-			__func__, retval);
-		goto fail;
-	}
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
-	} else {
-		/* install the em28xx notify callback */
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
-				em28xx_ctrl_notify, dev);
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
-				em28xx_ctrl_notify, dev);
-	}
-
-	/* wake i2c devices */
-	em28xx_wake_i2c(dev);
-
-	/* init video dma queues */
-	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vbiq.active);
-
-	if (dev->board.has_msp34xx) {
-		/* Send a reset to other chips via gpio */
-		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
-		if (retval < 0) {
-			em28xx_errdev("%s: em28xx_write_reg - "
-				      "msp34xx(1) failed! error [%d]\n",
-				      __func__, retval);
-			goto fail;
-		}
-		msleep(3);
-
-		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
-		if (retval < 0) {
-			em28xx_errdev("%s: em28xx_write_reg - "
-				      "msp34xx(2) failed! error [%d]\n",
-				      __func__, retval);
-			goto fail;
-		}
-		msleep(3);
-	}
-
 	retval = em28xx_register_analog_devices(dev);
 	if (retval < 0) {
 		goto fail;
 	}
 
-	/* Save some power by putting tuner to sleep */
-	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
-
 	return 0;
 
 fail:
@@ -3388,9 +3320,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(interface, dev);
 
-	/* initialize videobuf2 stuff */
-	em28xx_vb2_setup(dev);
-
 	/* allocate device struct */
 	mutex_init(&dev->lock);
 	mutex_lock(&dev->lock);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 8b8a4eb96875..85284626dbd6 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2186,10 +2186,78 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	u8 val;
 	int ret;
 	unsigned int maxw;
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
+	if (!dev->is_audio_only) {
+		/* This device does not support the v4l2 extension */
+		return 0;
+	}
 
 	printk(KERN_INFO "%s: v4l2 driver version %s\n",
 		dev->name, EM28XX_VERSION);
 
+	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+	if (ret < 0) {
+		em28xx_errdev("Call to v4l2_device_register() failed!\n");
+		goto err;
+	}
+
+	v4l2_ctrl_handler_init(hdl, 8);
+	dev->v4l2_dev.ctrl_handler = hdl;
+
+	/*
+	 * Default format, used for tvp5150 or saa711x output formats
+	 */
+	dev->vinmode = 0x10;
+	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
+		       EM28XX_VINCTRL_CCIR656_ENABLE;
+
+	/* Configure audio */
+	ret = em28xx_audio_setup(dev);
+	if (ret < 0) {
+		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+			__func__, ret);
+		goto err;
+	}
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+	} else {
+		/* install the em28xx notify callback */
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+				em28xx_ctrl_notify, dev);
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+				em28xx_ctrl_notify, dev);
+	}
+
+	/* wake i2c devices */
+	em28xx_wake_i2c(dev);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vbiq.active);
+
+	if (dev->board.has_msp34xx) {
+		/* Send a reset to other chips via gpio */
+		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
+		if (ret < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
+				      __func__, ret);
+			goto err;
+		}
+		msleep(3);
+
+		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
+		if (ret < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
+				      __func__, ret);
+			goto err;
+		}
+		msleep(3);
+	}
+
 	/* set default norm */
 	dev->norm = V4L2_STD_PAL;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
@@ -2252,14 +2320,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	/* Reset image controls */
 	em28xx_colorlevels_set_default(dev);
 	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-	if (dev->ctrl_handler.error)
-		return dev->ctrl_handler.error;
+	ret = dev->ctrl_handler.error;
+	if (ret)
+		goto err;
 
 	/* allocate and fill video video_device struct */
 	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
 	if (!dev->vdev) {
 		em28xx_errdev("cannot allocate video_device.\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err;
 	}
 	dev->vdev->queue = &dev->vb_vidq;
 	dev->vdev->queue->lock = &dev->vb_queue_lock;
@@ -2289,7 +2359,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	if (ret) {
 		em28xx_errdev("unable to register video device (error=%i).\n",
 			      ret);
-		return ret;
+		goto err;
 	}
 
 	/* Allocate and fill vbi video_device struct */
@@ -2318,7 +2388,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 					    vbi_nr[dev->devno]);
 		if (ret < 0) {
 			em28xx_errdev("unable to register vbi device\n");
-			return ret;
+			goto err;
 		}
 	}
 
@@ -2327,13 +2397,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 						  "radio");
 		if (!dev->radio_dev) {
 			em28xx_errdev("cannot allocate video_device.\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto err;
 		}
 		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
 					    radio_nr[dev->devno]);
 		if (ret < 0) {
 			em28xx_errdev("can't register radio device\n");
-			return ret;
+			goto err;
 		}
 		em28xx_info("Registered radio device as %s\n",
 			    video_device_node_name(dev->radio_dev));
@@ -2346,5 +2417,11 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 		em28xx_info("V4L2 VBI device registered as %s\n",
 			    video_device_node_name(dev->vbi_dev));
 
+	/* Save some power by putting tuner to sleep */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+	/* initialize videobuf2 stuff */
+	em28xx_vb2_setup(dev);
+err:
 	return 0;
 }
-- 
1.8.3.1


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

* [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:47   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place Mauro Carvalho Chehab
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Now that all analog-specific code are at em28xx-video, convert
it into an em28xx extension and load it as a separate module.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/Kconfig         |  6 ++-
 drivers/media/usb/em28xx/Makefile        |  5 ++-
 drivers/media/usb/em28xx/em28xx-camera.c |  1 +
 drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
 drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
 drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
 drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
 drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
 drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
 9 files changed, 107 insertions(+), 80 deletions(-)
 create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h

diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index d6ba514d31eb..838fc9dbb747 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -1,8 +1,12 @@
 config VIDEO_EM28XX
-	tristate "Empia EM28xx USB video capture support"
+	tristate "Empia EM28xx USB devices support"
 	depends on VIDEO_DEV && I2C
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
+
+config VIDEO_EM28XX_V4L2
+	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
+	depends on VIDEO_EM28XX && I2C
 	select VIDEOBUF2_VMALLOC
 	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index ad6d48557940..3f850d5063d0 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,10 +1,11 @@
-em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
+em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
 
+em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
 em28xx-alsa-objs := em28xx-audio.o
 em28xx-rc-objs := em28xx-input.o
 
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
 obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index d666741797d4..c29f5c4e7b40 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(em28xx_init_camera);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 175cd776e0a1..938daaabd8e0 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
 		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
 	},
 };
+EXPORT_SYMBOL_GPL(em28xx_boards);
+
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
@@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
 				"tuner", dev->tuner_addr, NULL);
 		}
 	}
-
-	em28xx_tuner_setup(dev);
-
-	em28xx_init_camera(dev);
 }
 
 
@@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
 	em28xx_init_extension(dev);
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
+	if (dev->has_video)
+		request_module("em28xx-v4l");
 	if (dev->has_audio_class)
 		request_module("snd-usb-audio");
 	else if (dev->has_alsa_audio)
 		request_module("em28xx-alsa");
-
 	if (dev->board.has_dvb)
 		request_module("em28xx-dvb");
 	if (dev->board.buttons ||
@@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
 {
 	/*FIXME: I2C IR should be disconnected */
 
-	em28xx_release_analog_resources(dev);
-
 	if (dev->def_i2c_bus)
 		em28xx_i2c_unregister(dev, 1);
 	em28xx_i2c_unregister(dev, 0);
 	if (dev->clk)
 		v4l2_clk_unregister_fixed(dev->clk);
 
-	v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-	v4l2_device_unregister(&dev->v4l2_dev);
-
 	usb_put_dev(dev->udev);
 
 	/* Mark device as unused */
@@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 	if (retval < 0) {
 		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
 			__func__, retval);
-		goto unregister_dev;
+		return retval;
 	}
 
 	/* register i2c bus 1 */
@@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		if (retval < 0) {
 			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
 				__func__, retval);
-			goto unregister_dev;
+			return retval;
 		}
 	}
 
 	/* Do board specific init and eeprom reading */
 	em28xx_card_setup(dev);
 
-	retval = em28xx_register_analog_devices(dev);
-	if (retval < 0) {
-		goto fail;
-	}
-
 	return 0;
-
-fail:
-	if (dev->def_i2c_bus)
-		em28xx_i2c_unregister(dev, 1);
-	em28xx_i2c_unregister(dev, 0);
-	v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-unregister_dev:
-	v4l2_device_unregister(&dev->v4l2_dev);
-
-	return retval;
 }
 
 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
@@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	dev->alt   = -1;
 	dev->is_audio_only = has_audio && !(has_video || has_dvb);
 	dev->has_alsa_audio = has_audio;
+	dev->has_video = has_video;
 	dev->audio_ifnum = ifnum;
 
 	/* Checks if audio is provided by some interface */
@@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
 	/* allocate device struct */
 	mutex_init(&dev->lock);
-	mutex_lock(&dev->lock);
 	retval = em28xx_init_dev(dev, udev, interface, nr);
 	if (retval) {
-		goto unlock_and_free;
+		goto err_free;
 	}
 
 	if (usb_xfer_mode < 0) {
@@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 		if (retval) {
 			printk(DRIVER_NAME
 			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
-			goto unlock_and_free;
+			goto err_free;
 		}
 	}
 
@@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	/* Should be the last thing to do, to avoid newer udev's to
 	   open the device before fully initializing it
 	 */
-	mutex_unlock(&dev->lock);
 
 	return 0;
 
-unlock_and_free:
-	mutex_unlock(&dev->lock);
-
 err_free:
 	kfree(dev->alt_max_pkt_size_isoc);
 	kfree(dev);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 3012912d2997..1113d4e107d8 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -33,6 +33,18 @@
 
 #include "em28xx.h"
 
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+		      "Markus Rechberger <mrechberger@gmail.com>, " \
+		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+		      "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_DESC         "Empia em28xx based USB core driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
 static unsigned int core_debug;
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
new file mode 100644
index 000000000000..bce438691e0e
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -0,0 +1,20 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
+
+   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ */
+
+
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 39f39c527c13..db3d655600df 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 85284626dbd6..d615bff8ac09 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
@@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
 	},
 };
 
+static int em28xx_vbi_supported(struct em28xx *dev);
+
 /*
  * em28xx_wake_i2c()
  * configure i2c attached devices
  */
-void em28xx_wake_i2c(struct em28xx *dev)
+static void em28xx_wake_i2c(struct em28xx *dev)
 {
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
 	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
@@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
 	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
 }
 
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+static int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
 	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
 	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
@@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
 	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
 }
 
-int em28xx_set_outfmt(struct em28xx *dev)
+static int em28xx_set_outfmt(struct em28xx *dev)
 {
 	int ret;
 	u8 fmt, vinctrl;
@@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 }
 
 /* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
+static int em28xx_resolution_set(struct em28xx *dev)
 {
 	int width, height;
 	width = norm_maxw(dev);
@@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
 	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
 }
 
-int em28xx_vbi_supported(struct em28xx *dev)
+static int em28xx_vbi_supported(struct em28xx *dev)
 {
 	/* Modprobe option to manually disable */
 	if (disable_vbi == 1)
@@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
 }
 
 /* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
+static int em28xx_set_alternate(struct em28xx *dev)
 {
 	int errCode;
 	int i;
@@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
 	.wait_finish    = vb2_ops_wait_finish,
 };
 
-int em28xx_vb2_setup(struct em28xx *dev)
+static int em28xx_vb2_setup(struct em28xx *dev)
 {
 	int rc;
 	struct vb2_queue *q;
@@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
 	em28xx_audio_analog_set(dev);
 }
 
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
+static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 {
 	struct em28xx *dev = priv;
 
@@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 		reg->val = ret;
 	} else {
 		__le16 val = 0;
-		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
 						   reg->reg, (char *)&val, 2);
 		if (ret < 0)
 			return ret;
@@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
 }
 
 /*
- * em28xx_realease_resources()
+ * em28xx_v4l2_fini()
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-void em28xx_release_analog_resources(struct em28xx *dev)
+static int em28xx_v4l2_fini(struct em28xx *dev)
 {
 
 	/*FIXME: I2C IR should be disconnected */
@@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
 			video_device_release(dev->vdev);
 		dev->vdev = NULL;
 	}
+
+	return 0;
 }
 
 /*
@@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
 	if (dev->users == 1) {
 		/* the device is already disconnect,
 		   free the remaining resources */
+
 		if (dev->disconnected) {
-			em28xx_release_resources(dev);
+			v4l2_ctrl_handler_free(&dev->ctrl_handler);
+			v4l2_device_unregister(&dev->v4l2_dev);
 			kfree(dev->alt_max_pkt_size_isoc);
-			mutex_unlock(&dev->lock);
-			kfree(dev);
-			return 0;
+			goto exit;
 		}
 
 		/* Save some power by putting tuner to sleep */
@@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
 		}
 	}
 
+exit:
 	dev->users--;
 	mutex_unlock(&dev->lock);
 	return 0;
@@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
 
 /******************************** usb interface ******************************/
 
-
-
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 					const struct video_device *template,
 					const char *type_name)
@@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
 	}
 }
 
-void em28xx_tuner_setup(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev)
 {
 	struct tuner_setup           tun_setup;
 	struct v4l2_frequency        f;
@@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
 }
 
-int em28xx_register_analog_devices(struct em28xx *dev)
+static int em28xx_v4l2_init(struct em28xx *dev)
 {
 	u8 val;
 	int ret;
 	unsigned int maxw;
 	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 
-	if (!dev->is_audio_only) {
+	if (!dev->has_video) {
 		/* This device does not support the v4l2 extension */
 		return 0;
 	}
@@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	printk(KERN_INFO "%s: v4l2 driver version %s\n",
 		dev->name, EM28XX_VERSION);
 
+	mutex_lock(&dev->lock);
+
 	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
 	if (ret < 0) {
 		em28xx_errdev("Call to v4l2_device_register() failed!\n");
@@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
 		       EM28XX_VINCTRL_CCIR656_ENABLE;
 
+	/* Initialize tuner and camera */
+	em28xx_tuner_setup(dev);
+	em28xx_init_camera(dev);
+
 	/* Configure audio */
 	ret = em28xx_audio_setup(dev);
 	if (ret < 0) {
@@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 
 	/* initialize videobuf2 stuff */
 	em28xx_vb2_setup(dev);
+
 err:
-	return 0;
+	mutex_unlock(&dev->lock);
+	return ret;
+}
+
+static struct em28xx_ops v4l2_ops = {
+	.id   = EM28XX_V4L2,
+	.name = "Em28xx v4l2 Extension",
+	.init = em28xx_v4l2_init,
+	.fini = em28xx_v4l2_fini,
+};
+
+static int __init em28xx_video_register(void)
+{
+	return em28xx_register_extension(&v4l2_ops);
 }
+
+static void __exit em28xx_video_unregister(void)
+{
+	em28xx_unregister_extension(&v4l2_ops);
+}
+
+module_init(em28xx_video_register);
+module_exit(em28xx_video_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 7ae05ebc13c1..9d6f43e4681f 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,7 +26,7 @@
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
-#define EM28XX_VERSION "0.2.0"
+#define EM28XX_VERSION "0.2.1"
 
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
@@ -474,6 +474,7 @@ struct em28xx_eeprom {
 #define EM28XX_AUDIO   0x10
 #define EM28XX_DVB     0x20
 #define EM28XX_RC      0x30
+#define EM28XX_V4L2    0x40
 
 /* em28xx resource types (used for res_get/res_lock etc */
 #define EM28XX_RESOURCE_VIDEO 0x01
@@ -527,6 +528,7 @@ struct em28xx {
 
 	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
 	unsigned char disconnected:1;	/* device has been diconnected */
+	unsigned int has_video:1;
 	unsigned int has_audio_class:1;
 	unsigned int has_alsa_audio:1;
 	unsigned int is_audio_only:1;
@@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
 int em28xx_audio_analog_set(struct em28xx *dev);
 int em28xx_audio_setup(struct em28xx *dev);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev);
 const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
 					 enum em28xx_led_role role);
 int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_vbi_supported(struct em28xx *dev);
-int em28xx_set_outfmt(struct em28xx *dev);
-int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_set_alternate(struct em28xx *dev);
 int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
 		      int num_bufs, int max_pkt_size, int packet_multiplier);
 int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
@@ -742,31 +739,17 @@ 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);
-void em28xx_wake_i2c(struct em28xx *dev);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 void em28xx_init_extension(struct em28xx *dev);
 void em28xx_close_extension(struct em28xx *dev);
 
-/* Provided by em28xx-video.c */
-void em28xx_tuner_setup(struct em28xx *dev);
-int em28xx_vb2_setup(struct em28xx *dev);
-int em28xx_register_analog_devices(struct em28xx *dev);
-void em28xx_release_analog_resources(struct em28xx *dev);
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
-int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
-extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
-
 /* Provided by em28xx-cards.c */
 extern 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_release_resources(struct em28xx *dev);
 
-/* Provided by em28xx-vbi.c */
-extern struct vb2_ops em28xx_vbi_qops;
-
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
 int em28xx_init_camera(struct em28xx *dev);
-- 
1.8.3.1


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

* [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:48   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 06/22] [media] em28xx: add warn messages for timeout Mauro Carvalho Chehab
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

In order to initialize the analog tuner, v4l2 should be registere
first, or otherwise we get an oops:

[   51.783537] BUG: unable to handle kernel NULL pointer dereference at        )
[   51.784479] IP: [<ffffffff81319fbb>] __list_add+0x1b/0xc0
[   51.784479] PGD 0
[   51.784479] Oops: 0000 [#1] SMP
[   51.784479] Modules linked in: tvp5150 em28xx(+) tveeprom v4l2_common videode
[   51.784479] CPU: 0 PID: 946 Comm: systemd-udevd Not tainted 3.13.0-rc1+ #38
[   51.784479] Hardware name: PCCHIPS P17G/P17G, BIOS 080012  05/14/2008
[   51.784479] task: ffff880027482080 ti: ffff88003c9b6000 task.ti: ffff88003c90
[   51.784479] RIP: 0010:[<ffffffff81319fbb>]  [<ffffffff81319fbb>] __list_add+0
[   51.784479] RSP: 0018:ffff88003c9b7a10  EFLAGS: 00010246
[   51.784479] RAX: 0000000000000000 RBX: ffff880036d12428 RCX: 0000000000000000
[   51.784479] RDX: ffff880036ce6040 RSI: 0000000000000000 RDI: ffff880036d12428
[   51.784479] RBP: ffff88003c9b7a28 R08: 0000000000000000 R09: 0000000000000001
[   51.784479] R10: 0000000000000001 R11: 0000000000000000 R12: ffff880036ce6040
[   51.784479] R13: 0000000000000000 R14: ffff880036ce62c0 R15: ffffffffa045c176
[   51.784479] FS:  00007fba89124880(0000) GS:ffff88003f400000(0000) knlGS:00000
[   51.784479] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   51.784479] CR2: 0000000000000000 CR3: 000000003bccf000 CR4: 00000000000007f0
[   51.784479] Stack:
[   51.784479]  ffff880036d12428 ffff880036ce6038 0000000000000000 ffff88003c9b0
[   51.784479]  ffffffffa0425bbc ffff880028246800 ffff880036d12428 ffff880036ce8
[   51.784479]  ffff88003c9b7a80 ffffffffa044d733 ffff88003c9b7a90 ffff880036ce8
[   51.784479] Call Trace:
[   51.784479]  [<ffffffffa0425bbc>] v4l2_device_register_subdev+0xdc/0x120 [vi]
[   51.784479]  [<ffffffffa044d733>] v4l2_i2c_new_subdev_board+0xa3/0x100 [v4l2]
[   51.784479]  [<ffffffffa044d7fa>] v4l2_i2c_new_subdev+0x6a/0x90 [v4l2_common]
[   51.784479]  [<ffffffffa0455dcb>] em28xx_usb_probe+0xd3b/0x10a0 [em28xx]
[   51.784479]  [<ffffffff81478f74>] usb_probe_interface+0x1c4/0x2f0
[   51.784479]  [<ffffffff81400127>] driver_probe_device+0x87/0x390
[   51.784479]  [<ffffffff81400503>] __driver_attach+0x93/0xa0
[   51.784479]  [<ffffffff81400470>] ? __device_attach+0x40/0x40
[   51.784479]  [<ffffffff813fe153>] bus_for_each_dev+0x63/0xa0
[   51.784479]  [<ffffffff813ffb7e>] driver_attach+0x1e/0x20
[   51.784479]  [<ffffffff813ff760>] bus_add_driver+0x180/0x250
[   51.784479]  [<ffffffff81400b34>] driver_register+0x64/0xf0
[   51.784479]  [<ffffffff81477751>] usb_register_driver+0x81/0x160
[   51.784479]  [<ffffffffa0467000>] ? 0xffffffffa0466fff
[   51.784479]  [<ffffffffa046701e>] em28xx_usb_driver_init+0x1e/0x1000 [em28xx]
[   51.784479]  [<ffffffff8100214a>] do_one_initcall+0xfa/0x1b0
[   51.784479]  [<ffffffff81053793>] ? set_memory_nx+0x43/0x50
[   51.784479]  [<ffffffff810d9926>] load_module+0x1bc6/0x24b0
[   51.784479]  [<ffffffff810d5940>] ? store_uevent+0x40/0x40
[   51.784479]  [<ffffffff810da386>] SyS_finit_module+0x86/0xb0
[   51.784479]  [<ffffffff81666529>] system_call_fastpath+0x16/0x1b
[   51.784479] Code: ff ff 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 1f 00 55 48 89 e
[   51.784479] RIP  [<ffffffff81319fbb>] __list_add+0x1b/0xc0
[   51.784479]  RSP <ffff88003c9b7a10>
[   51.784479] CR2: 0000000000000000
[   52.218397] ---[ end trace 0bd601544e51b8a3 ]---

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 64 --------------------------------
 drivers/media/usb/em28xx/em28xx-video.c | 65 +++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 64 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 938daaabd8e0..d1c75e66554c 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2362,24 +2362,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
 };
 /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
 
-/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
-static unsigned short saa711x_addrs[] = {
-	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
-	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
-	I2C_CLIENT_END };
-
-static unsigned short tvp5150_addrs[] = {
-	0xb8 >> 1,
-	0xba >> 1,
-	I2C_CLIENT_END
-};
-
-static unsigned short msp3400_addrs[] = {
-	0x80 >> 1,
-	0x88 >> 1,
-	I2C_CLIENT_END
-};
-
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 {
 	struct em28xx_i2c_bus *i2c_bus = ptr;
@@ -2784,54 +2766,8 @@ static void em28xx_card_setup(struct em28xx *dev)
 	/* Allow override tuner type by a module parameter */
 	if (tuner >= 0)
 		dev->tuner_type = tuner;
-
-	/* request some modules */
-	if (dev->board.has_msp34xx)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"msp3400", 0, msp3400_addrs);
-
-	if (dev->board.decoder == EM28XX_SAA711X)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"saa7115_auto", 0, saa711x_addrs);
-
-	if (dev->board.decoder == EM28XX_TVP5150)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"tvp5150", 0, tvp5150_addrs);
-
-	if (dev->board.adecoder == EM28XX_TVAUDIO)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"tvaudio", dev->board.tvaudio_addr, NULL);
-
-	if (dev->board.tuner_type != TUNER_ABSENT) {
-		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
-
-		if (dev->board.radio.type)
-			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-				"tuner", dev->board.radio_addr, NULL);
-
-		if (has_demod)
-			v4l2_i2c_new_subdev(&dev->v4l2_dev,
-				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
-				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
-		if (dev->tuner_addr == 0) {
-			enum v4l2_i2c_tuner_type type =
-				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
-			struct v4l2_subdev *sd;
-
-			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
-				0, v4l2_i2c_tuner_addrs(type));
-
-			if (sd)
-				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
-		} else {
-			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-				"tuner", dev->tuner_addr, NULL);
-		}
-	}
 }
 
-
 static void request_module_async(struct work_struct *work)
 {
 	struct em28xx *dev = container_of(work,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index d615bff8ac09..56d1b46164a0 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2051,6 +2051,24 @@ static struct video_device em28xx_radio_template = {
 	.ioctl_ops 	      = &radio_ioctl_ops,
 };
 
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+	I2C_CLIENT_END };
+
+static unsigned short tvp5150_addrs[] = {
+	0xb8 >> 1,
+	0xba >> 1,
+	I2C_CLIENT_END
+};
+
+static unsigned short msp3400_addrs[] = {
+	0x80 >> 1,
+	0x88 >> 1,
+	I2C_CLIENT_END
+};
+
 /******************************** usb interface ******************************/
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
@@ -2218,7 +2236,54 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
 		       EM28XX_VINCTRL_CCIR656_ENABLE;
 
+	/* request some modules */
+
+	if (dev->board.has_msp34xx)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"msp3400", 0, msp3400_addrs);
+
+	if (dev->board.decoder == EM28XX_SAA711X)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"saa7115_auto", 0, saa711x_addrs);
+
+	if (dev->board.decoder == EM28XX_TVP5150)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"tvp5150", 0, tvp5150_addrs);
+
+	if (dev->board.adecoder == EM28XX_TVAUDIO)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"tvaudio", dev->board.tvaudio_addr, NULL);
+
 	/* Initialize tuner and camera */
+
+	if (dev->board.tuner_type != TUNER_ABSENT) {
+		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+		if (dev->board.radio.type)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+				"tuner", dev->board.radio_addr, NULL);
+
+		if (has_demod)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (dev->tuner_addr == 0) {
+			enum v4l2_i2c_tuner_type type =
+				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+			struct v4l2_subdev *sd;
+
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
+				0, v4l2_i2c_tuner_addrs(type));
+
+			if (sd)
+				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+		} else {
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+				"tuner", dev->tuner_addr, NULL);
+		}
+	}
+
 	em28xx_tuner_setup(dev);
 	em28xx_init_camera(dev);
 
-- 
1.8.3.1


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

* [PATCH v4 06/22] [media] em28xx: add warn messages for timeout
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:51   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 07/22] [media] em28xx: improve extension information messages Mauro Carvalho Chehab
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

changeset 45f04e82d035 added a logic to check if em28xx got
a timeout on an I2C transfer.

That patch started to produce a series of errors that is present
with HVR-950, like:

[ 4032.218656] xc2028 19-0061: Error on line 1299: -19

However, as there are several places where -ENODEV is produced,
there's no way to know what's happening.

So, let's add a printk to report what error condition was reached:

[ 4032.218652] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
[ 4032.218656] xc2028 19-0061: Error on line 1299: -19

Interesting enough, when connected to an USB3 port, the number of
errors increase:

[ 4249.941375] em2882/3 #0: I2C transfer timeout on writing to addr 0xb8
[ 4249.941378] tvp5150 19-005c: i2c i/o error: rc == -19 (should be 2)
[ 4250.023854] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
[ 4250.023857] xc2028 19-0061: Error on line 1299: -19

Due to that, I suspect that the logic in the driver is wrong: instead
of just returning an error if 0x10 is returned, it should be waiting for
a while and read the I2C status register again.

However, more tests are needed.

For now, instead of just returning -ENODEV, output an error message
to help debug what's happening.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index c4ff9739a7ae..9e6a11d01858 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -80,6 +80,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		if (ret == 0x80 + len - 1) {
 			return len;
 		} else if (ret == 0x94 + len - 1) {
+			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
 			return -ENODEV;
 		} else if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
@@ -123,6 +124,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		if (ret == 0x84 + len - 1) {
 			break;
 		} else if (ret == 0x94 + len - 1) {
+			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
 			return -ENODEV;
 		} else if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
@@ -198,6 +200,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		if (ret == 0) { /* success */
 			return len;
 		} else if (ret == 0x10) {
+			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
 			return -ENODEV;
 		} else if (ret < 0) {
 			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
@@ -255,6 +258,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 	}
 	if (ret > 0) {
 		if (ret == 0x10) {
+			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
 			return -ENODEV;
 		} else {
 			em28xx_warn("unknown i2c error (status=%i)\n", ret);
@@ -316,8 +320,10 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	 */
 	if (!ret)
 		return len;
-	else if (ret > 0)
+	else if (ret > 0) {
+		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
 		return -ENODEV;
+	}
 
 	return ret;
 	/*
@@ -367,8 +373,10 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	 */
 	if (!ret)
 		return len;
-	else if (ret > 0)
+	else if (ret > 0) {
+		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
 		return -ENODEV;
+	}
 
 	return ret;
 	/*
-- 
1.8.3.1


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

* [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (5 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 06/22] [media] em28xx: add warn messages for timeout Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 10:55   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies Mauro Carvalho Chehab
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Add a message with consistent prints before and after each
extension initialization, and provide a better text for module
load.

While here, add a missing sanity check for extension finish
code at em28xx-v4l extension.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
 drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
 drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
 drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
 drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
 5 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 2fdb66ee44ab..263886adcf26 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 		return 0;
 	}
 
-	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+	em28xx_info("Binding audio extension\n");
+
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
 			 "Rechberger\n");
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
@@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
 	adev->sndcard = card;
 	adev->udev = dev->udev;
 
+	em28xx_info("Audio extension successfully initialized\n");
 	return 0;
 }
 
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 1113d4e107d8..33cf26e106b5 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
 		ops->init(dev);
 	}
 	mutex_unlock(&em28xx_devlist_mutex);
-	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
 	return 0;
 }
 EXPORT_SYMBOL(em28xx_register_extension);
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index ddc0e609065d..f72663a9b5c5 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
 static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 {
 	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
-        struct em28xx *dev = i2c_bus->dev;
+	struct em28xx *dev = i2c_bus->dev;
 
 	if (acquire)
 		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
 
 	if (!dev->board.has_dvb) {
 		/* This device does not support the extension */
-		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
 		return 0;
 	}
 
+	em28xx_info("Binding DVB extension\n");
+
 	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
 
 	if (dvb == NULL) {
@@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
 	/* MFE lock */
 	dvb->adapter.mfe_shared = mfe_shared;
 
-	em28xx_info("Successfully loaded em28xx-dvb\n");
+	em28xx_info("DVB extension successfully initialized\n");
 ret:
 	em28xx_set_mode(dev, EM28XX_SUSPEND);
 	mutex_unlock(&dev->lock);
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 93a7d02b9cb4..eed7dd79f734 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_info("Registering input extension\n");
+
 	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 	rc = rc_allocate_device();
 	if (!ir || !rc)
@@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
 	if (err)
 		goto error;
 
+	em28xx_info("Input extension successfully initalized\n");
+
 	return 0;
 
 error:
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 56d1b46164a0..b767262c642b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
 
 	/*FIXME: I2C IR should be disconnected */
 
+	if (!dev->has_video) {
+		/* This device does not support the v4l2 extension */
+		return 0;
+	}
+
 	if (dev->radio_dev) {
 		if (video_is_registered(dev->radio_dev))
 			video_unregister_device(dev->radio_dev);
@@ -2215,8 +2220,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 		return 0;
 	}
 
-	printk(KERN_INFO "%s: v4l2 driver version %s\n",
-		dev->name, EM28XX_VERSION);
+	em28xx_info("Registering V4L2 extension\n");
 
 	mutex_lock(&dev->lock);
 
@@ -2498,6 +2502,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	/* initialize videobuf2 stuff */
 	em28xx_vb2_setup(dev);
 
+	em28xx_info("V4L2 extension successfully initialized\n");
+
 err:
 	mutex_unlock(&dev->lock);
 	return ret;
-- 
1.8.3.1


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

* [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (6 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 07/22] [media] em28xx: improve extension information messages Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:03   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 09/22] [media] tvp5150: make read operations atomic Mauro Carvalho Chehab
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

The I2C wait completion/timeout logic currently assumes that
msleep(5) will wait exaclty 5 ms. This is not true at all,
as it depends on CONFIG_HZ.

Convert it to use jiffies, in order to not wait for more time
than needed.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 65 ++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 31 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 9e6a11d01858..9fa7ed51e5b1 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
+#include <linux/jiffies.h>
 
 #include "em28xx.h"
 #include "tuner-xc2028.h"
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
  */
 static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
+	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
 	int ret;
-	int write_timeout;
 	u8 b2[6];
 
 	if (len < 1 || len > 4)
@@ -74,15 +75,15 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		return (ret < 0) ? ret : -EIO;
 	}
 	/* wait for completion */
-	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
-	     write_timeout -= 5) {
+	while (time_is_after_jiffies(timeout)) {
 		ret = dev->em28xx_read_reg(dev, 0x05);
-		if (ret == 0x80 + len - 1) {
+		if (ret == 0x80 + len - 1)
 			return len;
-		} else if (ret == 0x94 + len - 1) {
+		if (ret == 0x94 + len - 1) {
 			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
 			return -ENODEV;
-		} else if (ret < 0) {
+		}
+		if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
 				    ret);
 			return ret;
@@ -99,9 +100,9 @@ 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(EM2800_I2C_XFER_TIMEOUT);
 	u8 buf2[4];
 	int ret;
-	int read_timeout;
 	int i;
 
 	if (len < 1 || len > 4)
@@ -118,15 +119,15 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 	}
 
 	/* wait for completion */
-	for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
-	     read_timeout -= 5) {
+	while (time_is_after_jiffies(timeout)) {
 		ret = dev->em28xx_read_reg(dev, 0x05);
-		if (ret == 0x84 + len - 1) {
+		if (ret == 0x84 + len - 1)
 			break;
-		} else if (ret == 0x94 + len - 1) {
+		if (ret == 0x94 + len - 1) {
 			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
 			return -ENODEV;
-		} else if (ret < 0) {
+		}
+		if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
 				    ret);
 			return ret;
@@ -170,7 +171,8 @@ 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)
 {
-	int write_timeout, ret;
+	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
+	int ret;
 
 	if (len < 1 || len > 64)
 		return -EOPNOTSUPP;
@@ -193,17 +195,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		}
 	}
 
-	/* Check success of the i2c operation */
-	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
-	     write_timeout -= 5) {
+	/* wait for completion */
+	while (time_is_after_jiffies(timeout)) {
 		ret = dev->em28xx_read_reg(dev, 0x05);
-		if (ret == 0) { /* success */
+		if (ret == 0) /* success */
 			return len;
-		} else if (ret == 0x10) {
-			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
+		if (ret == 0x10) {
+			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+				    addr);
 			return -ENODEV;
-		} else if (ret < 0) {
-			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+		}
+		if (ret < 0) {
+			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
 				    ret);
 			return ret;
 		}
@@ -214,6 +217,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		 * (even with high payload) ...
 		 */
 	}
+
 	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
 	return -EIO;
 }
@@ -251,21 +255,20 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 
 	/* Check success of the i2c operation */
 	ret = dev->em28xx_read_reg(dev, 0x05);
+	if (ret == 0) /* success */
+		return len;
 	if (ret < 0) {
-		em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
 			    ret);
 		return ret;
 	}
-	if (ret > 0) {
-		if (ret == 0x10) {
-			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
-			return -ENODEV;
-		} else {
-			em28xx_warn("unknown i2c error (status=%i)\n", ret);
-			return -EIO;
-		}
+	if (ret == 0x10) {
+		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
+		return -ENODEV;
 	}
-	return len;
+
+	em28xx_warn("unknown i2c error (status=%i)\n", ret);
+	return -EIO;
 }
 
 /*
-- 
1.8.3.1


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

* [PATCH v4 09/22] [media] tvp5150: make read operations atomic
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (7 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:07   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 10/22] [media] tuner-xc2028: remove unused code Mauro Carvalho Chehab
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Instead of using two I2C operations between write and read,
use just one i2c_transfer. That allows I2C mutexes to not
let any other I2C transfer between the two.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/i2c/tvp5150.c | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 89c0b13463b7..2ed05b67218b 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -58,21 +58,17 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
 	struct i2c_client *c = v4l2_get_subdevdata(sd);
 	unsigned char buffer[1];
 	int rc;
-
-	buffer[0] = addr;
-
-	rc = i2c_master_send(c, buffer, 1);
-	if (rc < 0) {
-		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
-		return rc;
-	}
-
-	msleep(10);
-
-	rc = i2c_master_recv(c, buffer, 1);
-	if (rc < 0) {
-		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
-		return rc;
+	struct i2c_msg msg[] = {
+		{ .addr = c->addr, .flags = 0,
+		  .buf = &addr, .len = 1 },
+		{ .addr = c->addr, .flags = I2C_M_RD,
+		  .buf = buffer, .len = 1 }
+	};
+
+	rc = i2c_transfer(c->adapter, msg, 2);
+	if (rc < 0 || rc != 2) {
+		v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
+		return rc < 0 ? rc : -EIO;
 	}
 
 	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
-- 
1.8.3.1


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

* [PATCH v4 10/22] [media] tuner-xc2028: remove unused code
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (8 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 09/22] [media] tvp5150: make read operations atomic Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:07   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier Mauro Carvalho Chehab
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

This macro is not used. remove it.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/tuners/tuner-xc2028.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 4be5cf808a40..1057da54c6e0 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -134,15 +134,6 @@ struct xc2028_data {
 	_rc;								\
 })
 
-#define i2c_rcv(priv, buf, size) ({					\
-	int _rc;							\
-	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
-	if (size != _rc)						\
-		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
-			   _rc, (int)size); 				\
-	_rc;								\
-})
-
 #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
 	int _rc;							\
 	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
-- 
1.8.3.1


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

* [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (9 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 10/22] [media] tuner-xc2028: remove unused code Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:12   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code Mauro Carvalho Chehab
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Better to split chipset detection from the audio setup. So, move the
detection code to em28xx_init_dev().

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 11 +++++++++++
 drivers/media/usb/em28xx/em28xx-core.c  | 12 +-----------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index d1c75e66554c..4fe742429f2c 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2930,6 +2930,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		}
 	}
 
+	if (dev->chip_id == CHIP_ID_EM2870 ||
+	    dev->chip_id == CHIP_ID_EM2874 ||
+	    dev->chip_id == CHIP_ID_EM28174 ||
+	    dev->chip_id == CHIP_ID_EM28178) {
+		/* Digital only device - don't load any alsa module */
+		dev->audio_mode.has_audio = false;
+		dev->has_audio_class = false;
+		dev->has_alsa_audio = false;
+	}
+
 	if (chip_name != default_chip_name)
 		printk(KERN_INFO DRIVER_NAME
 		       ": chip ID is %s\n", chip_name);
@@ -3196,6 +3206,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	dev->alt   = -1;
 	dev->is_audio_only = has_audio && !(has_video || has_dvb);
 	dev->has_alsa_audio = has_audio;
+	dev->audio_mode.has_audio = has_audio;
 	dev->has_video = has_video;
 	dev->audio_ifnum = ifnum;
 
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 33cf26e106b5..818248d3fd28 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -505,18 +505,8 @@ int em28xx_audio_setup(struct em28xx *dev)
 	int vid1, vid2, feat, cfg;
 	u32 vid;
 
-	if (dev->chip_id == CHIP_ID_EM2870 ||
-	    dev->chip_id == CHIP_ID_EM2874 ||
-	    dev->chip_id == CHIP_ID_EM28174 ||
-	    dev->chip_id == CHIP_ID_EM28178) {
-		/* Digital only device - don't load any alsa module */
-		dev->audio_mode.has_audio = false;
-		dev->has_audio_class = false;
-		dev->has_alsa_audio = false;
+	if (!dev->audio_mode.has_audio)
 		return 0;
-	}
-
-	dev->audio_mode.has_audio = true;
 
 	/* See how this device is configured */
 	cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
-- 
1.8.3.1


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

* [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (10 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:19   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 13/22] [media] em28xx: initialize audio latter Mauro Carvalho Chehab
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Instead of assuming that msleep() is precise, use a jiffies
based code to wait for AC97 to be available.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-core.c | 7 +++++--
 drivers/media/usb/em28xx/em28xx.h      | 5 ++++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 818248d3fd28..36b2f1ab4474 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -23,6 +23,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -254,16 +255,18 @@ EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
  */
 static int em28xx_is_ac97_ready(struct em28xx *dev)
 {
-	int ret, i;
+	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_AC97_XFER_TIMEOUT);
+	int ret;
 
 	/* Wait up to 50 ms for AC97 command to complete */
-	for (i = 0; i < 10; i++, msleep(5)) {
+	while (time_is_after_jiffies(timeout)) {
 		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
 		if (ret < 0)
 			return ret;
 
 		if (!(ret & 0x01))
 			return 0;
+		msleep (5);
 	}
 
 	em28xx_warn("AC97 command still being executed: not handled properly!\n");
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 9d6f43e4681f..ac79501f5d9f 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -182,9 +182,12 @@
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
-/* time in msecs to wait for i2c writes to finish */
+/* time in msecs to wait for i2c xfers to finish */
 #define EM2800_I2C_XFER_TIMEOUT		20
 
+/* time in msecs to wait for AC97 xfers to finish */
+#define EM2800_AC97_XFER_TIMEOUT	100
+
 /* max. number of button state polling addresses */
 #define EM28XX_NUM_BUTTON_ADDRESSES_MAX		5
 
-- 
1.8.3.1


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

* [PATCH v4 13/22] [media] em28xx: initialize audio latter
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (11 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:29   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 14/22] [media] em28xx: unify module version Mauro Carvalho Chehab
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Better to first write the GPIOs of the input mux, before initializing
the audio.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-video.c | 40 ++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index b767262c642b..328d724a13ea 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2291,26 +2291,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 	em28xx_tuner_setup(dev);
 	em28xx_init_camera(dev);
 
-	/* Configure audio */
-	ret = em28xx_audio_setup(dev);
-	if (ret < 0) {
-		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
-			__func__, ret);
-		goto err;
-	}
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
-	} else {
-		/* install the em28xx notify callback */
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
-				em28xx_ctrl_notify, dev);
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
-				em28xx_ctrl_notify, dev);
-	}
-
 	/* wake i2c devices */
 	em28xx_wake_i2c(dev);
 
@@ -2356,6 +2336,26 @@ static int em28xx_v4l2_init(struct em28xx *dev)
 
 	video_mux(dev, 0);
 
+	/* Configure audio */
+	ret = em28xx_audio_setup(dev);
+	if (ret < 0) {
+		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+			__func__, ret);
+		goto err;
+	}
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+	} else {
+		/* install the em28xx notify callback */
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+				em28xx_ctrl_notify, dev);
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+				em28xx_ctrl_notify, dev);
+	}
+
 	/* Audio defaults */
 	dev->mute = 1;
 	dev->volume = 0x1f;
-- 
1.8.3.1


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

* [PATCH v4 14/22] [media] em28xx: unify module version
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (12 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 13/22] [media] em28xx: initialize audio latter Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:33   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock Mauro Carvalho Chehab
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Use the same module version on all em28xx sub-modules, and use
the same naming convention to describe the driver.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 3 ++-
 drivers/media/usb/em28xx/em28xx-core.c  | 2 --
 drivers/media/usb/em28xx/em28xx-dvb.c   | 4 +++-
 drivers/media/usb/em28xx/em28xx-input.c | 3 ++-
 drivers/media/usb/em28xx/em28xx-video.c | 4 +---
 drivers/media/usb/em28xx/em28xx.h       | 1 +
 6 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 263886adcf26..a6eef06ffdcd 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -747,7 +747,8 @@ static void __exit em28xx_alsa_unregister(void)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Audio driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
+MODULE_VERSION(EM28XX_VERSION);
 
 module_init(em28xx_alsa_register);
 module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 36b2f1ab4474..2ad84ff1fc4f 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -39,8 +39,6 @@
 		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
 		      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_DESC         "Empia em28xx based USB core driver"
-
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index f72663a9b5c5..7fa1c804c34c 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -54,9 +54,11 @@
 #include "m88ds3103.h"
 #include "m88ts2022.h"
 
-MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
+MODULE_VERSION(EM28XX_VERSION);
+
 
 static unsigned int debug;
 module_param(debug, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index eed7dd79f734..f3b629dd57ae 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -836,7 +836,8 @@ static void __exit em28xx_rc_unregister(void)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Input driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
+MODULE_VERSION(EM28XX_VERSION);
 
 module_init(em28xx_rc_register);
 module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 328d724a13ea..999cbfe766a3 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -50,8 +50,6 @@
 		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
 		      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_DESC         "Empia em28xx based USB video device driver"
-
 static unsigned int isoc_debug;
 module_param(isoc_debug, int, 0644);
 MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
@@ -78,7 +76,7 @@ do {\
   } while (0)
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(EM28XX_VERSION);
 
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index ac79501f5d9f..db47c2236ca4 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -27,6 +27,7 @@
 #define _EM28XX_H
 
 #define EM28XX_VERSION "0.2.1"
+#define DRIVER_DESC    "Empia em28xx device driver"
 
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
-- 
1.8.3.1


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

* [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (13 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 14/22] [media] em28xx: unify module version Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 11:38   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

When em28xx extensions are loaded/removed, there are two locks:

a single static em28xx_devlist_mutex that registers each extension
and the struct em28xx dev->lock.

When extensions are registered, em28xx_devlist_mutex is taken first,
and then dev->lock.

Be sure that, when extensions are being removed, the same order
will be used.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-cards.c | 5 +++--
 drivers/media/usb/em28xx/em28xx-core.c  | 2 ++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 4fe742429f2c..36aec50e5c3b 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3334,9 +3334,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 	dev->disconnected = 1;
 
 	if (dev->is_audio_only) {
-		mutex_lock(&dev->lock);
 		em28xx_close_extension(dev);
-		mutex_unlock(&dev->lock);
 		return;
 	}
 
@@ -3355,10 +3353,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
 		em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
 	}
+	mutex_unlock(&dev->lock);
 
 	em28xx_close_extension(dev);
+
 	/* NOTE: must be called BEFORE the resources are released */
 
+	mutex_lock(&dev->lock);
 	if (!dev->users)
 		em28xx_release_resources(dev);
 
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 2ad84ff1fc4f..97cc83c3c287 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1097,10 +1097,12 @@ void em28xx_close_extension(struct em28xx *dev)
 	const struct em28xx_ops *ops = NULL;
 
 	mutex_lock(&em28xx_devlist_mutex);
+	mutex_lock(&dev->lock);
 	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
 		if (ops->fini)
 			ops->fini(dev);
 	}
+	mutex_unlock(&dev->lock);
 	list_del(&dev->devlist);
 	mutex_unlock(&em28xx_devlist_mutex);
 }
-- 
1.8.3.1


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

* [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (14 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 20:38   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

In the lack of a better spec, let's assume the timeout
values compatible with SMBus spec:
	http://smbus.org/specs/smbus110.pdf

at chapter 8 - Electrical Characteristics of SMBus devices

Ok, SMBus is a subset of I2C, and not all devices will be
following it, but the timeout value before this patch was not
even following the spec.

So, while we don't have a better guess for it, use 35 + 1
ms as the timeout.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index db47c2236ca4..9af19332b0f1 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -183,8 +183,21 @@
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
-/* time in msecs to wait for i2c xfers to finish */
-#define EM2800_I2C_XFER_TIMEOUT		20
+/*
+ * 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 EM2800_I2C_XFER_TIMEOUT		36
 
 /* time in msecs to wait for AC97 xfers to finish */
 #define EM2800_AC97_XFER_TIMEOUT	100
-- 
1.8.3.1


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

* [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (15 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 20:40   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

The proper error code for I2C errors are EREMOTEIO. The em28xx driver
is using EIO instead.

Replace all occurrences of EIO at em28xx-i2c, in order to fix it.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 9fa7ed51e5b1..8b35aa51b9bb 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -72,7 +72,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 	if (ret != 2 + len) {
 		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
 			    addr, ret);
-		return (ret < 0) ? ret : -EIO;
+		return (ret < 0) ? ret : -EREMOTEIO;
 	}
 	/* wait for completion */
 	while (time_is_after_jiffies(timeout)) {
@@ -91,7 +91,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		msleep(5);
 	}
 	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
-	return -EIO;
+	return -EREMOTEIO;
 }
 
 /*
@@ -115,7 +115,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 	if (ret != 2) {
 		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
 			    addr, ret);
-		return (ret < 0) ? ret : -EIO;
+		return (ret < 0) ? ret : -EREMOTEIO;
 	}
 
 	/* wait for completion */
@@ -142,7 +142,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 	if (ret != len) {
 		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
 			    addr, ret);
-		return (ret < 0) ? ret : -EIO;
+		return (ret < 0) ? ret : -EREMOTEIO;
 	}
 	for (i = 0; i < len; i++)
 		buf[i] = buf2[len - 1 - i];
@@ -162,7 +162,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
 	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
 	if (ret == 1)
 		return 0;
-	return (ret < 0) ? ret : -EIO;
+	return (ret < 0) ? ret : -EREMOTEIO;
 }
 
 /*
@@ -191,7 +191,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		} else {
 			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
 				    len, addr, ret);
-			return -EIO;
+			return -EREMOTEIO;
 		}
 	}
 
@@ -219,7 +219,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	}
 
 	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
-	return -EIO;
+	return -EREMOTEIO;
 }
 
 /*
@@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 	}
 
 	em28xx_warn("unknown i2c error (status=%i)\n", ret);
-	return -EIO;
+	return -EREMOTEIO;
 }
 
 /*
@@ -283,7 +283,7 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
 	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
 	if (ret == 1)
 		return 0;
-	return (ret < 0) ? ret : -EIO;
+	return (ret < 0) ? ret : -EREMOTEIO;
 }
 
 /*
@@ -312,7 +312,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		} else {
 			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
 				    len, addr, ret);
-			return -EIO;
+			return -EREMOTEIO;
 		}
 	}
 	/* Check success */
-- 
1.8.3.1


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

* [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (16 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 20:49   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

-ENODEV reports a permanent condition where a device is not found,
and used only during device probing or device removal, as stated
at  the V4L2 spec:
	http://linuxtv.org/downloads/v4l-dvb-apis/gen_errors.html

Except during device detection, this is not the case of I2C
transfer timeout errors.

So, change them to return -EREMOTEIO instead.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 8b35aa51b9bb..c3ba8ace5c94 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -81,7 +81,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 			return len;
 		if (ret == 0x94 + len - 1) {
 			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
-			return -ENODEV;
+			return -EREMOTEIO;
 		}
 		if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
@@ -125,7 +125,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 			break;
 		if (ret == 0x94 + len - 1) {
 			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
-			return -ENODEV;
+			return -EREMOTEIO;
 		}
 		if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
@@ -203,7 +203,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		if (ret == 0x10) {
 			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
 				    addr);
-			return -ENODEV;
+			return -EREMOTEIO;
 		}
 		if (ret < 0) {
 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
@@ -249,7 +249,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 	 * bytes if we are on bus B AND there was no write attempt to the
 	 * specified slave address before AND no device is present at the
 	 * requested slave address.
-	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
+	 * Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
 	 * spamming the system log on device probing and do nothing here.
 	 */
 
@@ -264,7 +264,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 	}
 	if (ret == 0x10) {
 		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
-		return -ENODEV;
+		return -EREMOTEIO;
 	}
 
 	em28xx_warn("unknown i2c error (status=%i)\n", ret);
@@ -325,7 +325,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		return len;
 	else if (ret > 0) {
 		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
-		return -ENODEV;
+		return -EREMOTEIO;
 	}
 
 	return ret;
@@ -364,8 +364,6 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	 * bytes if we are on bus B AND there was no write attempt to the
 	 * specified slave address before AND no device is present at the
 	 * requested slave address.
-	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
-	 * spamming the system log on device probing and do nothing here.
 	 */
 
 	/* Check success */
@@ -378,7 +376,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		return len;
 	else if (ret > 0) {
 		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
-		return -ENODEV;
+		return -EREMOTEIO;
 	}
 
 	return ret;
@@ -420,7 +418,7 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
 		rc = em2800_i2c_check_for_device(dev, addr);
 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
 		rc = em25xx_bus_B_check_for_device(dev, addr);
-	if (rc == -ENODEV) {
+	if (rc < 0) {
 		if (i2c_debug)
 			printk(" no device\n");
 	}
@@ -510,7 +508,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 			       addr, msgs[i].len);
 		if (!msgs[i].len) { /* no len: check only for device presence */
 			rc = i2c_check_for_device(i2c_bus, addr);
-			if (rc == -ENODEV) {
+			if (rc < 0) {
 				rt_mutex_unlock(&dev->i2c_bus_lock);
 				return rc;
 			}
-- 
1.8.3.1


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

* [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (17 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 20:54   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

The I2C output messages is too polluted. Clean it a little
bit, by:
	- use the proper core support for memory dumps;
	- hide most stuff under the i2c_debug umbrella;
	- add the missing KERN_CONT where needed;
	- use 2 levels or verbosity. Only the second one
	  will show the I2C transfer data.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 94 +++++++++++++++++++----------------
 1 file changed, 50 insertions(+), 44 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index c3ba8ace5c94..e030e0b7d645 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
 static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
 
 /*
  * em2800_i2c_send_bytes()
@@ -80,7 +80,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		if (ret == 0x80 + len - 1)
 			return len;
 		if (ret == 0x94 + len - 1) {
-			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
+			if (i2c_debug)
+				em28xx_warn("R05 returned 0x%02x: I2C timeout",
+					    ret);
 			return -EREMOTEIO;
 		}
 		if (ret < 0) {
@@ -90,7 +92,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		}
 		msleep(5);
 	}
-	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+	if (i2c_debug)
+		em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
 	return -EREMOTEIO;
 }
 
@@ -124,7 +127,9 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		if (ret == 0x84 + len - 1)
 			break;
 		if (ret == 0x94 + len - 1) {
-			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
+			if (i2c_debug)
+				em28xx_warn("R05 returned 0x%02x: I2C timeout",
+					    ret);
 			return -EREMOTEIO;
 		}
 		if (ret < 0) {
@@ -134,8 +139,11 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 		}
 		msleep(5);
 	}
-	if (ret != 0x84 + len - 1)
-		em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
+	if (ret != 0x84 + len - 1) {
+		if (i2c_debug)
+			em28xx_warn("read from i2c device at 0x%x timed out\n",
+				    addr);
+	}
 
 	/* get the received message */
 	ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
@@ -218,7 +226,8 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 		 */
 	}
 
-	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+	if (i2c_debug)
+		em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
 	return -EREMOTEIO;
 }
 
@@ -263,7 +272,9 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 		return ret;
 	}
 	if (ret == 0x10) {
-		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
+		if (i2c_debug)
+			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+				    addr);
 		return -EREMOTEIO;
 	}
 
@@ -324,7 +335,9 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	if (!ret)
 		return len;
 	else if (ret > 0) {
-		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
+		if (i2c_debug)
+			em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+				    ret);
 		return -EREMOTEIO;
 	}
 
@@ -375,7 +388,9 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
 	if (!ret)
 		return len;
 	else if (ret > 0) {
-		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
+		if (i2c_debug)
+			em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+				    ret);
 		return -EREMOTEIO;
 	}
 
@@ -418,10 +433,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
 		rc = em2800_i2c_check_for_device(dev, addr);
 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
 		rc = em25xx_bus_B_check_for_device(dev, addr);
-	if (rc < 0) {
-		if (i2c_debug)
-			printk(" no device\n");
-	}
 	return rc;
 }
 
@@ -430,7 +441,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
 {
 	struct em28xx *dev = i2c_bus->dev;
 	u16 addr = msg.addr << 1;
-	int byte, rc = -EOPNOTSUPP;
+	int rc = -EOPNOTSUPP;
 
 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
 		rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
@@ -438,10 +449,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
 		rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
 		rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
-	if (i2c_debug) {
-		for (byte = 0; byte < msg.len; byte++)
-			printk(" %02x", msg.buf[byte]);
-	}
 	return rc;
 }
 
@@ -450,12 +457,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
 {
 	struct em28xx *dev = i2c_bus->dev;
 	u16 addr = msg.addr << 1;
-	int byte, rc = -EOPNOTSUPP;
+	int rc = -EOPNOTSUPP;
 
-	if (i2c_debug) {
-		for (byte = 0; byte < msg.len; byte++)
-			printk(" %02x", msg.buf[byte]);
-	}
 	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
 		rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
 	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
@@ -500,7 +503,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 	}
 	for (i = 0; i < num; i++) {
 		addr = msgs[i].addr << 1;
-		if (i2c_debug)
+		if (i2c_debug > 1)
 			printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
 			       dev->name, __func__ ,
 			       (msgs[i].flags & I2C_M_RD) ? "read" : "write",
@@ -509,24 +512,33 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 		if (!msgs[i].len) { /* no len: check only for device presence */
 			rc = i2c_check_for_device(i2c_bus, addr);
 			if (rc < 0) {
+				if (i2c_debug > 1)
+					printk(KERN_CONT " no device\n");
 				rt_mutex_unlock(&dev->i2c_bus_lock);
 				return rc;
 			}
 		} else if (msgs[i].flags & I2C_M_RD) {
 			/* read bytes */
 			rc = i2c_recv_bytes(i2c_bus, msgs[i]);
+
+			if (i2c_debug > 1 && rc >= 0)
+				printk(KERN_CONT " %*ph",
+				       msgs[i].len, msgs[i].buf);
 		} else {
+			if (i2c_debug > 1)
+				printk(KERN_CONT " %*ph",
+				       msgs[i].len, msgs[i].buf);
+
 			/* write bytes */
 			rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
 		}
 		if (rc < 0) {
-			if (i2c_debug)
-				printk(" ERROR: %i\n", rc);
+			if (i2c_debug > 1)
+				printk(KERN_CONT " ERROR: %i\n", rc);
 			rt_mutex_unlock(&dev->i2c_bus_lock);
 			return rc;
-		}
-		if (i2c_debug)
-			printk("\n");
+		} else if (i2c_debug > 1)
+			printk(KERN_CONT "\n");
 	}
 
 	rt_mutex_unlock(&dev->i2c_bus_lock);
@@ -609,7 +621,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
 	 * calculation and returned device dataset. Simplifies the code a lot,
 	 * but we might have to deal with multiple sizes in the future !
 	 */
-	int i, err;
+	int err;
 	struct em28xx_eeprom *dev_config;
 	u8 buf, *data;
 
@@ -640,20 +652,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
 		goto error;
 	}
 
-	/* Display eeprom content */
-	for (i = 0; i < len; i++) {
-		if (0 == (i % 16)) {
-			if (dev->eeprom_addrwidth_16bit)
-				em28xx_info("i2c eeprom %04x:", i);
-			else
-				em28xx_info("i2c eeprom %02x:", i);
-		}
-		printk(" %02x", data[i]);
-		if (15 == (i % 16))
-			printk("\n");
+	if (i2c_debug) {
+		/* Display eeprom content */
+		print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
+			       16, 1, data, len, true);
+
+		if (dev->eeprom_addrwidth_16bit)
+			em28xx_info("eeprom %06x: ... (skipped)\n", 256);
 	}
-	if (dev->eeprom_addrwidth_16bit)
-		em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
 
 	if (dev->eeprom_addrwidth_16bit &&
 	    data[0] == 0x26 && data[3] == 0x00) {
-- 
1.8.3.1


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

* [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (18 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 20:57   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init Mauro Carvalho Chehab
  2014-01-04 10:55 ` [PATCH v4 22/22] [media] em28xx: retry read operation if it fails Mauro Carvalho Chehab
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Instead of allocating transfer buffers with kmalloc() use
usb_alloc_coherent().

That makes it work also with arm CPUs.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index a6eef06ffdcd..e5120430ec80 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -64,16 +64,22 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
 
 	dprintk("Stopping isoc\n");
 	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		struct urb *urb = dev->adev.urb[i];
+
 		if (!irqs_disabled())
-			usb_kill_urb(dev->adev.urb[i]);
+			usb_kill_urb(urb);
 		else
-			usb_unlink_urb(dev->adev.urb[i]);
+			usb_unlink_urb(urb);
 
-		usb_free_urb(dev->adev.urb[i]);
-		dev->adev.urb[i] = NULL;
+		usb_free_coherent(dev->udev,
+				  urb->transfer_buffer_length,
+				  dev->adev.transfer_buffer[i],
+				  urb->transfer_dma);
 
-		kfree(dev->adev.transfer_buffer[i]);
 		dev->adev.transfer_buffer[i] = NULL;
+
+		usb_free_urb(urb);
+		dev->adev.urb[i] = NULL;
 	}
 
 	return 0;
@@ -176,12 +182,8 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
 	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
 		struct urb *urb;
 		int j, k;
+		void *buf;
 
-		dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
-		if (!dev->adev.transfer_buffer[i])
-			return -ENOMEM;
-
-		memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
 		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
 		if (!urb) {
 			em28xx_errdev("usb_alloc_urb failed!\n");
@@ -192,10 +194,17 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
 			return -ENOMEM;
 		}
 
+		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
+					 &urb->transfer_dma);
+		if (!buf)
+			return -ENOMEM;
+		dev->adev.transfer_buffer[i] = buf;
+		memset(buf, 0x80, sb_size);
+
 		urb->dev = dev->udev;
 		urb->context = dev;
 		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
-		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 		urb->transfer_buffer = dev->adev.transfer_buffer[i];
 		urb->interval = 1;
 		urb->complete = em28xx_audio_isocirq;
-- 
1.8.3.1


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

* [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (19 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 21:02   ` Frank Schäfer
  2014-01-04 10:55 ` [PATCH v4 22/22] [media] em28xx: retry read operation if it fails Mauro Carvalho Chehab
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List,
	Mauro Carvalho Chehab, Mauro Carvalho Chehab

From: Mauro Carvalho Chehab <mchehab@redhat.com>

Instead of allocating/deallocating URBs and transfer buffers
every time stream is started/stopped, just do it once.

That reduces the memory allocation pressure and makes the
code that start/stop streaming a way simpler.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
 1 file changed, 73 insertions(+), 55 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index e5120430ec80..30ee389a07f0 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
  *
- *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
  *	- Port to work with the in-kernel driver
  *	- Cleanups, fixes, alsa-controls, etc.
  *
@@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
 			usb_kill_urb(urb);
 		else
 			usb_unlink_urb(urb);
-
-		usb_free_coherent(dev->udev,
-				  urb->transfer_buffer_length,
-				  dev->adev.transfer_buffer[i],
-				  urb->transfer_dma);
-
-		dev->adev.transfer_buffer[i] = NULL;
-
-		usb_free_urb(urb);
-		dev->adev.urb[i] = NULL;
 	}
 
 	return 0;
@@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
 static int em28xx_init_audio_isoc(struct em28xx *dev)
 {
 	int       i, errCode;
-	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
-			    EM28XX_AUDIO_MAX_PACKET_SIZE;
 
 	dprintk("Starting isoc transfers\n");
 
+	/* Start streaming */
 	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-		struct urb *urb;
-		int j, k;
-		void *buf;
-
-		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
-		if (!urb) {
-			em28xx_errdev("usb_alloc_urb failed!\n");
-			for (j = 0; j < i; j++) {
-				usb_free_urb(dev->adev.urb[j]);
-				kfree(dev->adev.transfer_buffer[j]);
-			}
-			return -ENOMEM;
-		}
-
-		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
-					 &urb->transfer_dma);
-		if (!buf)
-			return -ENOMEM;
-		dev->adev.transfer_buffer[i] = buf;
-		memset(buf, 0x80, sb_size);
-
-		urb->dev = dev->udev;
-		urb->context = dev;
-		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
-		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-		urb->transfer_buffer = dev->adev.transfer_buffer[i];
-		urb->interval = 1;
-		urb->complete = em28xx_audio_isocirq;
-		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
-		urb->transfer_buffer_length = sb_size;
-
-		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
-			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
-			urb->iso_frame_desc[j].offset = k;
-			urb->iso_frame_desc[j].length =
-			    EM28XX_AUDIO_MAX_PACKET_SIZE;
-		}
-		dev->adev.urb[i] = urb;
-	}
+		memset(dev->adev.transfer_buffer[i], 0x80,
+		       dev->adev.urb[i]->transfer_buffer_length);
 
-	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
 		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
 		if (errCode) {
 			em28xx_errdev("submit of audio urb failed\n");
@@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
 	.page      = snd_pcm_get_vmalloc_page,
 };
 
+static void em28xx_audio_free_urb(struct em28xx *dev)
+{
+	int i;
+
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		struct urb *urb = dev->adev.urb[i];
+
+		if (!dev->adev.urb[i])
+			continue;
+
+		usb_free_coherent(dev->udev,
+				  urb->transfer_buffer_length,
+				  dev->adev.transfer_buffer[i],
+				  urb->transfer_dma);
+
+		usb_free_urb(urb);
+		dev->adev.urb[i] = NULL;
+		dev->adev.transfer_buffer[i] = NULL;
+	}
+}
+
 static int em28xx_audio_init(struct em28xx *dev)
 {
 	struct em28xx_audio *adev = &dev->adev;
 	struct snd_pcm      *pcm;
 	struct snd_card     *card;
 	static int          devnr;
-	int                 err;
+	int                 err, i;
+	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
 
 	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
 		/* This device does not support the extension (in this case
@@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
 
 	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
 			 "Rechberger\n");
-	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+	printk(KERN_INFO
+	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
 
 	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
 			      &card);
@@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
 		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
 	}
 
+	/* Alloc URB and transfer buffers */
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		struct urb *urb;
+		int j, k;
+		void *buf;
+
+		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+		if (!urb) {
+			em28xx_errdev("usb_alloc_urb failed!\n");
+			em28xx_audio_free_urb(dev);
+			return -ENOMEM;
+		}
+		dev->adev.urb[i] = urb;
+
+		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
+					 &urb->transfer_dma);
+		if (!buf) {
+			em28xx_errdev("usb_alloc_coherent failed!\n");
+			em28xx_audio_free_urb(dev);
+			return -ENOMEM;
+		}
+		dev->adev.transfer_buffer[i] = buf;
+
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->transfer_buffer = dev->adev.transfer_buffer[i];
+		urb->interval = 1;
+		urb->complete = em28xx_audio_isocirq;
+		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+		urb->transfer_buffer_length = sb_size;
+
+		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
+		}
+	}
+
 	err = snd_card_register(card);
 	if (err < 0) {
 		snd_card_free(card);
@@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
 		return 0;
 	}
 
+	em28xx_audio_free_urb(dev);
+
 	if (dev->adev.sndcard) {
 		snd_card_free(dev->adev.sndcard);
 		dev->adev.sndcard = NULL;
-- 
1.8.3.1


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

* [PATCH v4 22/22] [media] em28xx: retry read operation if it fails
  2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
                   ` (20 preceding siblings ...)
  2014-01-04 10:55 ` [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init Mauro Carvalho Chehab
@ 2014-01-04 10:55 ` Mauro Carvalho Chehab
  2014-01-05 21:06   ` Frank Schäfer
  21 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-04 10:55 UTC (permalink / raw)
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

I2C read operations can also take some time to happen.

Try again, if it fails with return code different than 0x10
until timeout.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
 drivers/media/usb/em28xx/em28xx-i2c.c | 62 +++++++++++++++++++----------------
 1 file changed, 34 insertions(+), 28 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index e030e0b7d645..6cd3d909bb3a 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -237,6 +237,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
  */
 static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 {
+	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
 	int ret;
 
 	if (len < 1 || len > 64)
@@ -246,39 +247,44 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
 	 * Zero length reads always succeed, even if no device is connected
 	 */
 
-	/* Read data from i2c device */
-	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
-	if (ret < 0) {
-		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
-			    addr, ret);
-		return ret;
-	}
-	/*
-	 * NOTE: some devices with two i2c busses have the bad habit to return 0
-	 * bytes if we are on bus B AND there was no write attempt to the
-	 * specified slave address before AND no device is present at the
-	 * requested slave address.
-	 * Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
-	 * spamming the system log on device probing and do nothing here.
-	 */
+	do {
+		/* Read data from i2c device */
+		ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+		if (ret < 0) {
+			em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
+				    addr, ret);
+			return ret;
+		}
+		/*
+		 * NOTE: some devices with two i2c busses have the bad habit to return 0
+		* bytes if we are on bus B AND there was no write attempt to the
+		* specified slave address before AND no device is present at the
+		* requested slave address.
+		* Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
+		* spamming the system log on device probing and do nothing here.
+		*/
+
+		/* Check success of the i2c operation */
+		ret = dev->em28xx_read_reg(dev, 0x05);
+		if (ret == 0) /* success */
+			return len;
+		if (ret < 0) {
+			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
+				    ret);
+			return ret;
+		}
+		if (ret != 0x10)
+			break;
+		msleep(5);
+	} while (time_is_after_jiffies(timeout));
 
-	/* Check success of the i2c operation */
-	ret = dev->em28xx_read_reg(dev, 0x05);
-	if (ret == 0) /* success */
-		return len;
-	if (ret < 0) {
-		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
-			    ret);
-		return ret;
-	}
 	if (ret == 0x10) {
 		if (i2c_debug)
-			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+			em28xx_warn("I2C transfer timeout on reading from addr 0x%02x",
 				    addr);
-		return -EREMOTEIO;
+	} else {
+		em28xx_warn("unknown i2c error (status=%i)\n", ret);
 	}
-
-	em28xx_warn("unknown i2c error (status=%i)\n", ret);
 	return -EREMOTEIO;
 }
 
-- 
1.8.3.1


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

* Re: [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video
  2014-01-04 10:55 ` [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video Mauro Carvalho Chehab
@ 2014-01-05 10:11   ` Frank Schäfer
  2014-01-05 13:28     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:11 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Now that we want to split the video handling to a separate
> module, move all video-specific functions to em28xx-video.
>
> No functional changes.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c | 107 ---------
>  drivers/media/usb/em28xx/em28xx-core.c  | 259 ----------------------
>  drivers/media/usb/em28xx/em28xx-video.c | 374 +++++++++++++++++++++++++++++++-
>  drivers/media/usb/em28xx/em28xx.h       |   1 +
>  4 files changed, 371 insertions(+), 370 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 36853f16bf97..19827e79cf53 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2529,113 +2529,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>  }
>  
> -static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> -{
> -	memset(ctl, 0, sizeof(*ctl));
> -
> -	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
> -	ctl->max_len = 64;
> -	ctl->mts = em28xx_boards[dev->model].mts_firmware;
> -
> -	switch (dev->model) {
> -	case EM2880_BOARD_EMPIRE_DUAL_TV:
> -	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
> -	case EM2882_BOARD_TERRATEC_HYBRID_XS:
> -		ctl->demod = XC3028_FE_ZARLINK456;
> -		break;
> -	case EM2880_BOARD_TERRATEC_HYBRID_XS:
> -	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
> -	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
> -		ctl->demod = XC3028_FE_ZARLINK456;
> -		break;
> -	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
> -	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
> -		ctl->demod = XC3028_FE_DEFAULT;
> -		break;
> -	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
> -		ctl->demod = XC3028_FE_DEFAULT;
> -		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> -		break;
> -	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
> -	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
> -	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
> -		/* FIXME: Better to specify the needed IF */
> -		ctl->demod = XC3028_FE_DEFAULT;
> -		break;
> -	case EM2883_BOARD_KWORLD_HYBRID_330U:
> -	case EM2882_BOARD_DIKOM_DK300:
> -	case EM2882_BOARD_KWORLD_VS_DVBT:
> -		ctl->demod = XC3028_FE_CHINA;
> -		ctl->fname = XC2028_DEFAULT_FIRMWARE;
> -		break;
> -	case EM2882_BOARD_EVGA_INDTUBE:
> -		ctl->demod = XC3028_FE_CHINA;
> -		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> -		break;
> -	default:
> -		ctl->demod = XC3028_FE_OREN538;
> -	}
> -}
> -
> -static void em28xx_tuner_setup(struct em28xx *dev)
> -{
> -	struct tuner_setup           tun_setup;
> -	struct v4l2_frequency        f;
> -
> -	if (dev->tuner_type == TUNER_ABSENT)
> -		return;
> -
> -	memset(&tun_setup, 0, sizeof(tun_setup));
> -
> -	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
> -	tun_setup.tuner_callback = em28xx_tuner_callback;
> -
> -	if (dev->board.radio.type) {
> -		tun_setup.type = dev->board.radio.type;
> -		tun_setup.addr = dev->board.radio_addr;
> -
> -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> -	}
> -
> -	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
> -		tun_setup.type   = dev->tuner_type;
> -		tun_setup.addr   = dev->tuner_addr;
> -
> -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> -	}
> -
> -	if (dev->tda9887_conf) {
> -		struct v4l2_priv_tun_config tda9887_cfg;
> -
> -		tda9887_cfg.tuner = TUNER_TDA9887;
> -		tda9887_cfg.priv = &dev->tda9887_conf;
> -
> -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
> -	}
> -
> -	if (dev->tuner_type == TUNER_XC2028) {
> -		struct v4l2_priv_tun_config  xc2028_cfg;
> -		struct xc2028_ctrl           ctl;
> -
> -		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
> -		memset(&ctl, 0, sizeof(ctl));
> -
> -		em28xx_setup_xc3028(dev, &ctl);
> -
> -		xc2028_cfg.tuner = TUNER_XC2028;
> -		xc2028_cfg.priv  = &ctl;
> -
> -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
> -	}
> -
> -	/* configure tuner */
> -	f.tuner = 0;
> -	f.type = V4L2_TUNER_ANALOG_TV;
> -	f.frequency = 9076;     /* just a magic number */
> -	dev->ctl_freq = f.frequency;
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> -}
> -
>  static int em28xx_hint_board(struct em28xx *dev)
>  {
>  	int i;
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index f6076a512e8f..3012912d2997 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -53,14 +53,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
>  		printk(KERN_INFO "%s %s :"fmt, \
>  			 dev->name, __func__ , ##arg); } while (0)
>  
> -static int alt;
> -module_param(alt, int, 0644);
> -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
> -
> -static unsigned int disable_vbi;
> -module_param(disable_vbi, int, 0644);
> -MODULE_PARM_DESC(disable_vbi, "disable vbi support");
> -
>  /* FIXME */
>  #define em28xx_isocdbg(fmt, arg...) do {\
>  	if (core_debug) \
> @@ -603,24 +595,6 @@ init_audio:
>  }
>  EXPORT_SYMBOL_GPL(em28xx_audio_setup);
>  
> -int em28xx_colorlevels_set_default(struct em28xx *dev)
> -{
> -	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> -	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> -	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
> -	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
> -	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
> -	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
> -
> -	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
> -	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
> -	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
> -	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
> -	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
> -	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
> -	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> -}
> -
>  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
>  					 enum em28xx_led_role role)
>  {
> @@ -696,227 +670,6 @@ int em28xx_capture_start(struct em28xx *dev, int start)
>  	return rc;
>  }
>  
> -int em28xx_vbi_supported(struct em28xx *dev)
> -{
> -	/* Modprobe option to manually disable */
> -	if (disable_vbi == 1)
> -		return 0;
> -
> -	if (dev->board.is_webcam)
> -		return 0;
> -
> -	/* FIXME: check subdevices for VBI support */
> -
> -	if (dev->chip_id == CHIP_ID_EM2860 ||
> -	    dev->chip_id == CHIP_ID_EM2883)
> -		return 1;
> -
> -	/* Version of em28xx that does not support VBI */
> -	return 0;
> -}
> -
> -int em28xx_set_outfmt(struct em28xx *dev)
> -{
> -	int ret;
> -	u8 fmt, vinctrl;
> -
> -	fmt = dev->format->reg;
> -	if (!dev->is_em25xx)
> -		fmt |= 0x20;
> -	/*
> -	 * NOTE: it's not clear if this is really needed !
> -	 * The datasheets say bit 5 is a reserved bit and devices seem to work
> -	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
> -	 * devices and we've always been setting it, too.
> -	 *
> -	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
> -	 * it's likely used for an additional (compressed ?) format there.
> -	 */
> -	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
> -	if (ret < 0)
> -		return ret;
> -
> -	vinctrl = dev->vinctl;
> -	if (em28xx_vbi_supported(dev) == 1) {
> -		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
> -		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
> -		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
> -		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
> -		if (dev->norm & V4L2_STD_525_60) {
> -			/* NTSC */
> -			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
> -		} else if (dev->norm & V4L2_STD_625_50) {
> -			/* PAL */
> -			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
> -		}
> -	}
> -
> -	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
> -}
> -
> -static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
> -				  u8 ymin, u8 ymax)
> -{
> -	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
> -			xmin, ymin, xmax, ymax);
> -
> -	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
> -	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
> -	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
> -	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
> -}
> -
> -static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
> -				   u16 width, u16 height)
> -{
> -	u8 cwidth = width >> 2;
> -	u8 cheight = height >> 2;
> -	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
> -	/* NOTE: size limit: 2047x1023 = 2MPix */
> -
> -	em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
> -		       hstart, vstart,
> -		       ((overflow & 2) << 9 | cwidth << 2),
> -		       ((overflow & 1) << 10 | cheight << 2));
> -
> -	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
> -	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
> -	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
> -	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
> -	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
> -
> -	/* FIXME: function/meaning of these registers ? */
> -	/* FIXME: align width+height to multiples of 4 ?! */
> -	if (dev->is_em25xx) {
> -		em28xx_write_reg(dev, 0x34, width >> 4);
> -		em28xx_write_reg(dev, 0x35, height >> 4);
> -	}
> -}
> -
> -static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> -{
> -	u8 mode;
> -	/* the em2800 scaler only supports scaling down to 50% */
> -
> -	if (dev->board.is_em2800) {
> -		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
> -	} else {
> -		u8 buf[2];
> -
> -		buf[0] = h;
> -		buf[1] = h >> 8;
> -		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
> -
> -		buf[0] = v;
> -		buf[1] = v >> 8;
> -		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
> -		/* it seems that both H and V scalers must be active
> -		   to work correctly */
> -		mode = (h || v) ? 0x30 : 0x00;
> -	}
> -	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
> -}
> -
> -/* FIXME: this only function read values from dev */
> -int em28xx_resolution_set(struct em28xx *dev)
> -{
> -	int width, height;
> -	width = norm_maxw(dev);
> -	height = norm_maxh(dev);
> -
> -	/* Properly setup VBI */
> -	dev->vbi_width = 720;
> -	if (dev->norm & V4L2_STD_525_60)
> -		dev->vbi_height = 12;
> -	else
> -		dev->vbi_height = 18;
> -
> -	em28xx_set_outfmt(dev);
> -
> -	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
> -
> -	/* If we don't set the start position to 2 in VBI mode, we end up
> -	   with line 20/21 being YUYV encoded instead of being in 8-bit
> -	   greyscale.  The core of the issue is that line 21 (and line 23 for
> -	   PAL WSS) are inside of active video region, and as a result they
> -	   get the pixelformatting associated with that area.  So by cropping
> -	   it out, we end up with the same format as the rest of the VBI
> -	   region */
> -	if (em28xx_vbi_supported(dev) == 1)
> -		em28xx_capture_area_set(dev, 0, 2, width, height);
> -	else
> -		em28xx_capture_area_set(dev, 0, 0, width, height);
> -
> -	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> -}
> -
> -/* Set USB alternate setting for analog video */
> -int em28xx_set_alternate(struct em28xx *dev)
> -{
> -	int errCode;
> -	int i;
> -	unsigned int min_pkt_size = dev->width * 2 + 4;
> -
> -	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
> -		 bulk transfers seem to work only with alt=0 ! */
> -	dev->alt = 0;
> -	if ((alt > 0) && (alt < dev->num_alt)) {
> -		em28xx_coredbg("alternate forced to %d\n", dev->alt);
> -		dev->alt = alt;
> -		goto set_alt;
> -	}
> -	if (dev->analog_xfer_bulk)
> -		goto set_alt;
> -
> -	/* When image size is bigger than a certain value,
> -	   the frame size should be increased, otherwise, only
> -	   green screen will be received.
> -	 */
> -	if (dev->width * 2 * dev->height > 720 * 240 * 2)
> -		min_pkt_size *= 2;
> -
> -	for (i = 0; i < dev->num_alt; i++) {
> -		/* stop when the selected alt setting offers enough bandwidth */
> -		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
> -			dev->alt = i;
> -			break;
> -		/* otherwise make sure that we end up with the maximum bandwidth
> -		   because the min_pkt_size equation might be wrong...
> -		*/
> -		} else if (dev->alt_max_pkt_size_isoc[i] >
> -			   dev->alt_max_pkt_size_isoc[dev->alt])
> -			dev->alt = i;
> -	}
> -
> -set_alt:
> -	/* NOTE: for bulk transfers, we need to call usb_set_interface()
> -	 * even if the previous settings were the same. Otherwise streaming
> -	 * fails with all urbs having status = -EOVERFLOW ! */
> -	if (dev->analog_xfer_bulk) {
> -		dev->max_pkt_size = 512; /* USB 2.0 spec */
> -		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
> -	} else { /* isoc */
> -		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
> -			       min_pkt_size, dev->alt);
> -		dev->max_pkt_size =
> -				  dev->alt_max_pkt_size_isoc[dev->alt];
> -		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
> -	}
> -	em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
> -		       dev->alt, dev->max_pkt_size);
> -	errCode = usb_set_interface(dev->udev, 0, dev->alt);
> -	if (errCode < 0) {
> -		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
> -			      dev->alt, errCode);
> -		return errCode;
> -	}
> -	return 0;
> -}
> -
>  int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
>  {
>  	int rc = 0;
> @@ -1282,18 +1035,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
>  EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
>  
>  /*
> - * em28xx_wake_i2c()
> - * configure i2c attached devices
> - */
> -void em28xx_wake_i2c(struct em28xx *dev)
> -{
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> -			INPUT(dev->ctl_input)->vmux, 0, 0);
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> -}
> -
> -/*
>   * Device control list
>   */
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index dd19c9ff76e0..70ffe259df5b 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -53,15 +53,23 @@
>  
>  #define EM28XX_VERSION "0.2.0"
>  
> +static unsigned int isoc_debug;
> +module_param(isoc_debug, int, 0644);
> +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> +
> +static unsigned int disable_vbi;
> +module_param(disable_vbi, int, 0644);
> +MODULE_PARM_DESC(disable_vbi, "disable vbi support");
> +
> +static int alt;
> +module_param(alt, int, 0644);
> +MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
> +
>  #define em28xx_videodbg(fmt, arg...) do {\
>  	if (video_debug) \
>  		printk(KERN_INFO "%s %s :"fmt, \
>  			 dev->name, __func__ , ##arg); } while (0)
>  
> -static unsigned int isoc_debug;
> -module_param(isoc_debug, int, 0644);
> -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> -
>  #define em28xx_isocdbg(fmt, arg...) \
>  do {\
>  	if (isoc_debug) { \
> @@ -135,6 +143,257 @@ static struct em28xx_fmt format[] = {
>  	},
>  };
>  
> +/*
> + * em28xx_wake_i2c()
> + * configure i2c attached devices
> + */
> +void em28xx_wake_i2c(struct em28xx *dev)
> +{
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> +			INPUT(dev->ctl_input)->vmux, 0, 0);
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> +}
> +
> +int em28xx_colorlevels_set_default(struct em28xx *dev)
> +{
> +	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> +	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> +	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
> +	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
> +	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
> +	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
> +
> +	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
> +	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
> +	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
> +	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
> +	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
> +	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
> +	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> +}
> +
> +int em28xx_set_outfmt(struct em28xx *dev)
> +{
> +	int ret;
> +	u8 fmt, vinctrl;
> +
> +	fmt = dev->format->reg;
> +	if (!dev->is_em25xx)
> +		fmt |= 0x20;
> +	/*
> +	 * NOTE: it's not clear if this is really needed !
> +	 * The datasheets say bit 5 is a reserved bit and devices seem to work
> +	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
> +	 * devices and we've always been setting it, too.
> +	 *
> +	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
> +	 * it's likely used for an additional (compressed ?) format there.
> +	 */
> +	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
> +	if (ret < 0)
> +		return ret;
> +
> +	vinctrl = dev->vinctl;
> +	if (em28xx_vbi_supported(dev) == 1) {
> +		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
> +		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
> +		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
> +		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
> +		if (dev->norm & V4L2_STD_525_60) {
> +			/* NTSC */
> +			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
> +		} else if (dev->norm & V4L2_STD_625_50) {
> +			/* PAL */
> +			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
> +		}
> +	}
> +
> +	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
> +}
> +
> +static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
> +				  u8 ymin, u8 ymax)
> +{
> +	em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
> +			xmin, ymin, xmax, ymax);
> +
> +	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
> +	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
> +	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
> +	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
> +}
> +
> +static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
> +				   u16 width, u16 height)
> +{
> +	u8 cwidth = width >> 2;
> +	u8 cheight = height >> 2;
> +	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
> +	/* NOTE: size limit: 2047x1023 = 2MPix */
> +
> +	em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
> +		       hstart, vstart,
> +		       ((overflow & 2) << 9 | cwidth << 2),
> +		       ((overflow & 1) << 10 | cheight << 2));
> +
> +	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
> +	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
> +	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
> +	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
> +	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
> +
> +	/* FIXME: function/meaning of these registers ? */
> +	/* FIXME: align width+height to multiples of 4 ?! */
> +	if (dev->is_em25xx) {
> +		em28xx_write_reg(dev, 0x34, width >> 4);
> +		em28xx_write_reg(dev, 0x35, height >> 4);
> +	}
> +}
> +
> +static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> +{
> +	u8 mode;
> +	/* the em2800 scaler only supports scaling down to 50% */
> +
> +	if (dev->board.is_em2800) {
> +		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
> +	} else {
> +		u8 buf[2];
> +
> +		buf[0] = h;
> +		buf[1] = h >> 8;
> +		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
> +
> +		buf[0] = v;
> +		buf[1] = v >> 8;
> +		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
> +		/* it seems that both H and V scalers must be active
> +		   to work correctly */
> +		mode = (h || v) ? 0x30 : 0x00;
> +	}
> +	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
> +}
> +
> +/* FIXME: this only function read values from dev */
> +int em28xx_resolution_set(struct em28xx *dev)
> +{
> +	int width, height;
> +	width = norm_maxw(dev);
> +	height = norm_maxh(dev);
> +
> +	/* Properly setup VBI */
> +	dev->vbi_width = 720;
> +	if (dev->norm & V4L2_STD_525_60)
> +		dev->vbi_height = 12;
> +	else
> +		dev->vbi_height = 18;
> +
> +	em28xx_set_outfmt(dev);
> +
> +	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
> +
> +	/* If we don't set the start position to 2 in VBI mode, we end up
> +	   with line 20/21 being YUYV encoded instead of being in 8-bit
> +	   greyscale.  The core of the issue is that line 21 (and line 23 for
> +	   PAL WSS) are inside of active video region, and as a result they
> +	   get the pixelformatting associated with that area.  So by cropping
> +	   it out, we end up with the same format as the rest of the VBI
> +	   region */
> +	if (em28xx_vbi_supported(dev) == 1)
> +		em28xx_capture_area_set(dev, 0, 2, width, height);
> +	else
> +		em28xx_capture_area_set(dev, 0, 0, width, height);
> +
> +	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> +}
> +
> +int em28xx_vbi_supported(struct em28xx *dev)
> +{
> +	/* Modprobe option to manually disable */
> +	if (disable_vbi == 1)
> +		return 0;
> +
> +	if (dev->board.is_webcam)
> +		return 0;
> +
> +	/* FIXME: check subdevices for VBI support */
> +
> +	if (dev->chip_id == CHIP_ID_EM2860 ||
> +	    dev->chip_id == CHIP_ID_EM2883)
> +		return 1;
> +
> +	/* Version of em28xx that does not support VBI */
> +	return 0;
> +}
> +
> +/* Set USB alternate setting for analog video */
> +int em28xx_set_alternate(struct em28xx *dev)
> +{
> +	int errCode;
> +	int i;
> +	unsigned int min_pkt_size = dev->width * 2 + 4;
> +
> +	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
> +		 bulk transfers seem to work only with alt=0 ! */
> +	dev->alt = 0;
> +	if ((alt > 0) && (alt < dev->num_alt)) {
> +		em28xx_videodbg("alternate forced to %d\n", dev->alt);
> +		dev->alt = alt;
> +		goto set_alt;
> +	}
> +	if (dev->analog_xfer_bulk)
> +		goto set_alt;
> +
> +	/* When image size is bigger than a certain value,
> +	   the frame size should be increased, otherwise, only
> +	   green screen will be received.
> +	 */
> +	if (dev->width * 2 * dev->height > 720 * 240 * 2)
> +		min_pkt_size *= 2;
> +
> +	for (i = 0; i < dev->num_alt; i++) {
> +		/* stop when the selected alt setting offers enough bandwidth */
> +		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
> +			dev->alt = i;
> +			break;
> +		/* otherwise make sure that we end up with the maximum bandwidth
> +		   because the min_pkt_size equation might be wrong...
> +		*/
> +		} else if (dev->alt_max_pkt_size_isoc[i] >
> +			   dev->alt_max_pkt_size_isoc[dev->alt])
> +			dev->alt = i;
> +	}
> +
> +set_alt:
> +	/* NOTE: for bulk transfers, we need to call usb_set_interface()
> +	 * even if the previous settings were the same. Otherwise streaming
> +	 * fails with all urbs having status = -EOVERFLOW ! */
> +	if (dev->analog_xfer_bulk) {
> +		dev->max_pkt_size = 512; /* USB 2.0 spec */
> +		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
> +	} else { /* isoc */
> +		em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
> +			       min_pkt_size, dev->alt);
> +		dev->max_pkt_size =
> +				  dev->alt_max_pkt_size_isoc[dev->alt];
> +		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
> +	}
> +	em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
> +		       dev->alt, dev->max_pkt_size);
> +	errCode = usb_set_interface(dev->udev, 0, dev->alt);
> +	if (errCode < 0) {
> +		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
> +			      dev->alt, errCode);
> +		return errCode;
> +	}
> +	return 0;
> +}
> +
>  /* ------------------------------------------------------------------
>  	DMA and thread functions
>     ------------------------------------------------------------------*/
> @@ -1817,6 +2076,113 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>  	return vfd;
>  }
>  
> +static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> +{
> +	memset(ctl, 0, sizeof(*ctl));
> +
> +	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
> +	ctl->max_len = 64;
> +	ctl->mts = em28xx_boards[dev->model].mts_firmware;
> +
> +	switch (dev->model) {
> +	case EM2880_BOARD_EMPIRE_DUAL_TV:
> +	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
> +	case EM2882_BOARD_TERRATEC_HYBRID_XS:
> +		ctl->demod = XC3028_FE_ZARLINK456;
> +		break;
> +	case EM2880_BOARD_TERRATEC_HYBRID_XS:
> +	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
> +	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
> +		ctl->demod = XC3028_FE_ZARLINK456;
> +		break;
> +	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
> +	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
> +		ctl->demod = XC3028_FE_DEFAULT;
> +		break;
> +	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
> +		ctl->demod = XC3028_FE_DEFAULT;
> +		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> +		break;
> +	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
> +	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
> +	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
> +		/* FIXME: Better to specify the needed IF */
> +		ctl->demod = XC3028_FE_DEFAULT;
> +		break;
> +	case EM2883_BOARD_KWORLD_HYBRID_330U:
> +	case EM2882_BOARD_DIKOM_DK300:
> +	case EM2882_BOARD_KWORLD_VS_DVBT:
> +		ctl->demod = XC3028_FE_CHINA;
> +		ctl->fname = XC2028_DEFAULT_FIRMWARE;
> +		break;
> +	case EM2882_BOARD_EVGA_INDTUBE:
> +		ctl->demod = XC3028_FE_CHINA;
> +		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> +		break;
> +	default:
> +		ctl->demod = XC3028_FE_OREN538;
> +	}
> +}
> +
> +void em28xx_tuner_setup(struct em28xx *dev)
> +{
> +	struct tuner_setup           tun_setup;
> +	struct v4l2_frequency        f;
> +
> +	if (dev->tuner_type == TUNER_ABSENT)
> +		return;
> +
> +	memset(&tun_setup, 0, sizeof(tun_setup));
> +
> +	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
> +	tun_setup.tuner_callback = em28xx_tuner_callback;
> +
> +	if (dev->board.radio.type) {
> +		tun_setup.type = dev->board.radio.type;
> +		tun_setup.addr = dev->board.radio_addr;
> +
> +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> +	}
> +
> +	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
> +		tun_setup.type   = dev->tuner_type;
> +		tun_setup.addr   = dev->tuner_addr;
> +
> +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> +	}
> +
> +	if (dev->tda9887_conf) {
> +		struct v4l2_priv_tun_config tda9887_cfg;
> +
> +		tda9887_cfg.tuner = TUNER_TDA9887;
> +		tda9887_cfg.priv = &dev->tda9887_conf;
> +
> +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
> +	}
> +
> +	if (dev->tuner_type == TUNER_XC2028) {
> +		struct v4l2_priv_tun_config  xc2028_cfg;
> +		struct xc2028_ctrl           ctl;
> +
> +		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
> +		memset(&ctl, 0, sizeof(ctl));
> +
> +		em28xx_setup_xc3028(dev, &ctl);
> +
> +		xc2028_cfg.tuner = TUNER_XC2028;
> +		xc2028_cfg.priv  = &ctl;
> +
> +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
> +	}
> +
> +	/* configure tuner */
> +	f.tuner = 0;
> +	f.type = V4L2_TUNER_ANALOG_TV;
> +	f.frequency = 9076;     /* just a magic number */
> +	dev->ctl_freq = f.frequency;
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> +}
> +
>  int em28xx_register_analog_devices(struct em28xx *dev)
>  {
>  	u8 val;
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 191ef3593891..0259270dda46 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -748,6 +748,7 @@ void em28xx_init_extension(struct em28xx *dev);
>  void em28xx_close_extension(struct em28xx *dev);
>  
>  /* Provided by em28xx-video.c */
> +void em28xx_tuner_setup(struct em28xx *dev);
>  int em28xx_vb2_setup(struct em28xx *dev);
>  int em28xx_register_analog_devices(struct em28xx *dev);
>  void em28xx_release_analog_resources(struct em28xx *dev);

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 02/22] [media] em28xx: some cosmetic changes
  2014-01-04 10:55 ` [PATCH v4 02/22] [media] em28xx: some cosmetic changes Mauro Carvalho Chehab
@ 2014-01-05 10:13   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:13 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> In order to make easier for the next patches, do some
> cosmetic changes.
>
> No functional changes.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c |  2 +-
>  drivers/media/usb/em28xx/em28xx-video.c |  2 --
>  drivers/media/usb/em28xx/em28xx.h       | 11 ++++++-----
>  3 files changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 19827e79cf53..551cbc294190 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2106,7 +2106,7 @@ struct em28xx_board em28xx_boards[] = {
>  	},
>  	/* 1b80:e1cc Delock 61959
>  	 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
> -         * mostly the same as MaxMedia UB-425-TC but different remote */
> +	 * mostly the same as MaxMedia UB-425-TC but different remote */
>  	[EM2874_BOARD_DELOCK_61959] = {
>  		.name          = "Delock 61959",
>  		.tuner_type    = TUNER_ABSENT,
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 70ffe259df5b..8b8a4eb96875 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -51,8 +51,6 @@
>  
>  #define DRIVER_DESC         "Empia em28xx based USB video device driver"
>  
> -#define EM28XX_VERSION "0.2.0"
> -
>  static unsigned int isoc_debug;
>  module_param(isoc_debug, int, 0644);
>  MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 0259270dda46..7ae05ebc13c1 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -26,6 +26,8 @@
>  #ifndef _EM28XX_H
>  #define _EM28XX_H
>  
> +#define EM28XX_VERSION "0.2.0"
> +
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>
>  #include <linux/mutex.h>
> @@ -522,9 +524,12 @@ struct em28xx {
>  	int model;		/* index in the device_data struct */
>  	int devno;		/* marks the number of this device */
>  	enum em28xx_chip_id chip_id;
> -	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>  
> +	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>  	unsigned char disconnected:1;	/* device has been diconnected */
> +	unsigned int has_audio_class:1;
> +	unsigned int has_alsa_audio:1;
> +	unsigned int is_audio_only:1;
>  
>  	int audio_ifnum;
>  
> @@ -544,10 +549,6 @@ struct em28xx {
>  	/* Vinmode/Vinctl used at the driver */
>  	int vinmode, vinctl;
>  
> -	unsigned int has_audio_class:1;
> -	unsigned int has_alsa_audio:1;
> -	unsigned int is_audio_only:1;
> -
>  	/* Controls audio streaming */
>  	struct work_struct wq_trigger;	/* Trigger to start/stop audio for alsa module */
>  	atomic_t       stream_started;	/* stream should be running if true */

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video
  2014-01-04 10:55 ` [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video Mauro Carvalho Chehab
@ 2014-01-05 10:26   ` Frank Schäfer
  2014-01-05 14:40     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:26 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> There are several init code inside em28xx-cards that are actually
> part of analog initialization. Move the code to em28x-video, in
> order to remove part of the mess.
>
> In thesis, no functional changes so far.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c | 71 -------------------------
>  drivers/media/usb/em28xx/em28xx-video.c | 91 ++++++++++++++++++++++++++++++---
>  2 files changed, 84 insertions(+), 78 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 551cbc294190..175cd776e0a1 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2907,7 +2907,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  			   struct usb_interface *interface,
>  			   int minor)
>  {
> -	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>  	int retval;
>  	static const char *default_chip_name = "em28xx";
>  	const char *chip_name = default_chip_name;
> @@ -3034,15 +3033,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		}
>  	}
>  
> -	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
> -	if (retval < 0) {
> -		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> -		return retval;
> -	}
> -
> -	v4l2_ctrl_handler_init(hdl, 8);
> -	dev->v4l2_dev.ctrl_handler = hdl;
> -
>  	rt_mutex_init(&dev->i2c_bus_lock);
>  
>  	/* register i2c bus 0 */
> @@ -3071,72 +3061,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		}
>  	}
>  
> -	/*
> -	 * Default format, used for tvp5150 or saa711x output formats
> -	 */
> -	dev->vinmode = 0x10;
> -	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> -		       EM28XX_VINCTRL_CCIR656_ENABLE;
> -
>  	/* Do board specific init and eeprom reading */
>  	em28xx_card_setup(dev);
>  
em28xx_card_setup() initializes some v4l2 subdevices, but now the v4l2
device (dev->v4l2_dev) isn't ready at this point, because
v4l2_device_register() isn't called yet.
This introduces oopses.
You are fixing this with patch 5/22 later, but patches should never
introduce any oopses.
The simplest soultion is to move patch 5/22 before this patch.

> -	/* Configure audio */
> -	retval = em28xx_audio_setup(dev);
> -	if (retval < 0) {
> -		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> -			__func__, retval);
> -		goto fail;
> -	}
> -	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> -	} else {
> -		/* install the em28xx notify callback */
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> -				em28xx_ctrl_notify, dev);
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> -				em28xx_ctrl_notify, dev);
> -	}
> -
> -	/* wake i2c devices */
> -	em28xx_wake_i2c(dev);
> -
> -	/* init video dma queues */
> -	INIT_LIST_HEAD(&dev->vidq.active);
> -	INIT_LIST_HEAD(&dev->vbiq.active);
> -
> -	if (dev->board.has_msp34xx) {
> -		/* Send a reset to other chips via gpio */
> -		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
> -		if (retval < 0) {
> -			em28xx_errdev("%s: em28xx_write_reg - "
> -				      "msp34xx(1) failed! error [%d]\n",
> -				      __func__, retval);
> -			goto fail;
> -		}
> -		msleep(3);
> -
> -		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
> -		if (retval < 0) {
> -			em28xx_errdev("%s: em28xx_write_reg - "
> -				      "msp34xx(2) failed! error [%d]\n",
> -				      __func__, retval);
> -			goto fail;
> -		}
> -		msleep(3);
> -	}
> -
>  	retval = em28xx_register_analog_devices(dev);
>  	if (retval < 0) {
>  		goto fail;
>  	}
>  
> -	/* Save some power by putting tuner to sleep */
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> -
>  	return 0;
>  
>  fail:
You also need to move the v4l2_ctrl_handler_free() and
v4l2_device_unregister() calls to the error path of
em28xx_register_analog_devices() and rework its error path.

> @@ -3388,9 +3320,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	/* save our data pointer in this interface device */
>  	usb_set_intfdata(interface, dev);
>  
> -	/* initialize videobuf2 stuff */
> -	em28xx_vb2_setup(dev);
> -
>  	/* allocate device struct */
>  	mutex_init(&dev->lock);
>  	mutex_lock(&dev->lock);
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 8b8a4eb96875..85284626dbd6 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -2186,10 +2186,78 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	u8 val;
>  	int ret;
>  	unsigned int maxw;
> +	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
> +
> +	if (!dev->is_audio_only) {
> +		/* This device does not support the v4l2 extension */
> +		return 0;
> +	}

>   	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>  		dev->name, EM28XX_VERSION);
>  
> +	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> +	if (ret < 0) {
> +		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> +		goto err;
> +	}
> +
> +	v4l2_ctrl_handler_init(hdl, 8);
> +	dev->v4l2_dev.ctrl_handler = hdl;
> +
> +	/*
> +	 * Default format, used for tvp5150 or saa711x output formats
> +	 */
> +	dev->vinmode = 0x10;
> +	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> +		       EM28XX_VINCTRL_CCIR656_ENABLE;
> +
> +	/* Configure audio */
> +	ret = em28xx_audio_setup(dev);
> +	if (ret < 0) {
> +		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> +			__func__, ret);
> +		goto err;
> +	}
> +	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> +	} else {
> +		/* install the em28xx notify callback */
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> +				em28xx_ctrl_notify, dev);
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> +				em28xx_ctrl_notify, dev);
> +	}
> +
> +	/* wake i2c devices */
> +	em28xx_wake_i2c(dev);
> +
> +	/* init video dma queues */
> +	INIT_LIST_HEAD(&dev->vidq.active);
> +	INIT_LIST_HEAD(&dev->vbiq.active);
> +
> +	if (dev->board.has_msp34xx) {
> +		/* Send a reset to other chips via gpio */
> +		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
> +		if (ret < 0) {
> +			em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
> +				      __func__, ret);
> +			goto err;
> +		}
> +		msleep(3);
> +
> +		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
> +		if (ret < 0) {
> +			em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
> +				      __func__, ret);
> +			goto err;
> +		}
> +		msleep(3);
> +	}
> +
>  	/* set default norm */
>  	dev->norm = V4L2_STD_PAL;
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
> @@ -2252,14 +2320,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	/* Reset image controls */
>  	em28xx_colorlevels_set_default(dev);
>  	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
> -	if (dev->ctrl_handler.error)
> -		return dev->ctrl_handler.error;
> +	ret = dev->ctrl_handler.error;
> +	if (ret)
> +		goto err;
>  
>  	/* allocate and fill video video_device struct */
>  	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
>  	if (!dev->vdev) {
>  		em28xx_errdev("cannot allocate video_device.\n");
> -		return -ENODEV;
> +		ret = -ENODEV;
> +		goto err;
>  	}
>  	dev->vdev->queue = &dev->vb_vidq;
>  	dev->vdev->queue->lock = &dev->vb_queue_lock;
> @@ -2289,7 +2359,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	if (ret) {
>  		em28xx_errdev("unable to register video device (error=%i).\n",
>  			      ret);
> -		return ret;
> +		goto err;
>  	}
>  
>  	/* Allocate and fill vbi video_device struct */
> @@ -2318,7 +2388,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  					    vbi_nr[dev->devno]);
>  		if (ret < 0) {
>  			em28xx_errdev("unable to register vbi device\n");
> -			return ret;
> +			goto err;
>  		}
>  	}
>  
> @@ -2327,13 +2397,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  						  "radio");
>  		if (!dev->radio_dev) {
>  			em28xx_errdev("cannot allocate video_device.\n");
> -			return -ENODEV;
> +			ret = -ENODEV;
> +			goto err;
>  		}
>  		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
>  					    radio_nr[dev->devno]);
>  		if (ret < 0) {
>  			em28xx_errdev("can't register radio device\n");
> -			return ret;
> +			goto err;
>  		}
>  		em28xx_info("Registered radio device as %s\n",
>  			    video_device_node_name(dev->radio_dev));
> @@ -2346,5 +2417,11 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  		em28xx_info("V4L2 VBI device registered as %s\n",
>  			    video_device_node_name(dev->vbi_dev));
>  
> +	/* Save some power by putting tuner to sleep */
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> +
> +	/* initialize videobuf2 stuff */
> +	em28xx_vb2_setup(dev);
> +err:
>  	return 0;
>  }
Please return the error code. We are not checking it at the moment, but
we don't want to introduce new bugs.
As mentioned above, you also need to rework the error path and move the
v4l2_ctrl_handler_free() and v4l2_device_unregister() calls from
em28xx_init_dev() here.



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

* Re: [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-04 10:55 ` [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module Mauro Carvalho Chehab
@ 2014-01-05 10:47   ` Frank Schäfer
  2014-01-05 12:56     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:47 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Now that all analog-specific code are at em28xx-video, convert
> it into an em28xx extension and load it as a separate module.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/Kconfig         |  6 ++-
>  drivers/media/usb/em28xx/Makefile        |  5 ++-
>  drivers/media/usb/em28xx/em28xx-camera.c |  1 +
>  drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
>  drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
>  drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
>  drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
>  drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
>  drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
>  9 files changed, 107 insertions(+), 80 deletions(-)
>  create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h
>
> diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
> index d6ba514d31eb..838fc9dbb747 100644
> --- a/drivers/media/usb/em28xx/Kconfig
> +++ b/drivers/media/usb/em28xx/Kconfig
> @@ -1,8 +1,12 @@
>  config VIDEO_EM28XX
> -	tristate "Empia EM28xx USB video capture support"
> +	tristate "Empia EM28xx USB devices support"
>  	depends on VIDEO_DEV && I2C
>  	select VIDEO_TUNER
>  	select VIDEO_TVEEPROM
> +
> +config VIDEO_EM28XX_V4L2
> +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
> +	depends on VIDEO_EM28XX && I2C
VIDEO_EM28XX already depends on I2C.

>  	select VIDEOBUF2_VMALLOC
>  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
>  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
> diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
> index ad6d48557940..3f850d5063d0 100644
> --- a/drivers/media/usb/em28xx/Makefile
> +++ b/drivers/media/usb/em28xx/Makefile
> @@ -1,10 +1,11 @@
> -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
> -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
> +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
>  
> +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
>  em28xx-alsa-objs := em28xx-audio.o
>  em28xx-rc-objs := em28xx-input.o
>  
>  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
> +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
>  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
>  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
>  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
> index d666741797d4..c29f5c4e7b40 100644
> --- a/drivers/media/usb/em28xx/em28xx-camera.c
> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
>  
>  	return ret;
>  }
> +EXPORT_SYMBOL_GPL(em28xx_init_camera);
em28xx-camera should also be part of the em28xx-v4l module.

> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 175cd776e0a1..938daaabd8e0 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
>  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
>  	},
>  };
> +EXPORT_SYMBOL_GPL(em28xx_boards);
> +
>  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
>  
>  /* table of devices that work with this driver */
> @@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
>  				"tuner", dev->tuner_addr, NULL);
>  		}
>  	}
> -
> -	em28xx_tuner_setup(dev);
> -
> -	em28xx_init_camera(dev);
>  }
Here you are fixing half of the em28xx_card_setup() oopses which you've
introduced with patch 3/22.
This needs to be done together with patch 5/22 before patch 3/22.

> @@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
>  	em28xx_init_extension(dev);
>  
>  #if defined(CONFIG_MODULES) && defined(MODULE)
> +	if (dev->has_video)
> +		request_module("em28xx-v4l");
>  	if (dev->has_audio_class)
>  		request_module("snd-usb-audio");
>  	else if (dev->has_alsa_audio)
>  		request_module("em28xx-alsa");
> -
>  	if (dev->board.has_dvb)
>  		request_module("em28xx-dvb");
>  	if (dev->board.buttons ||
> @@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
>  {
>  	/*FIXME: I2C IR should be disconnected */
>  
> -	em28xx_release_analog_resources(dev);
> -
>  	if (dev->def_i2c_bus)
>  		em28xx_i2c_unregister(dev, 1);
>  	em28xx_i2c_unregister(dev, 0);
>  	if (dev->clk)
>  		v4l2_clk_unregister_fixed(dev->clk);
>  
> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> -
> -	v4l2_device_unregister(&dev->v4l2_dev);
> -
>  	usb_put_dev(dev->udev);
>  
>  	/* Mark device as unused */
> @@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  	if (retval < 0) {
>  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
>  			__func__, retval);
> -		goto unregister_dev;
> +		return retval;
>  	}
>  
>  	/* register i2c bus 1 */
> @@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		if (retval < 0) {
>  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
>  				__func__, retval);
> -			goto unregister_dev;
> +			return retval;
>  		}
>  	}
Hmm... if registering of bus 1 fails, we need to unregister bus 0.
But that's an old bug which we can fix later...

>  	/* Do board specific init and eeprom reading */
>  	em28xx_card_setup(dev);
>  
> -	retval = em28xx_register_analog_devices(dev);
> -	if (retval < 0) {
> -		goto fail;
> -	}
> -
>  	return 0;
> -
> -fail:
> -	if (dev->def_i2c_bus)
> -		em28xx_i2c_unregister(dev, 1);
> -	em28xx_i2c_unregister(dev, 0);
> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> -
> -unregister_dev:
> -	v4l2_device_unregister(&dev->v4l2_dev);
> -
> -	return retval;
>  }
>  
>  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
> @@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	dev->alt   = -1;
>  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
>  	dev->has_alsa_audio = has_audio;
> +	dev->has_video = has_video;
>  	dev->audio_ifnum = ifnum;
>  
>  	/* Checks if audio is provided by some interface */
> @@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  
>  	/* allocate device struct */
>  	mutex_init(&dev->lock);
> -	mutex_lock(&dev->lock);
>  	retval = em28xx_init_dev(dev, udev, interface, nr);
>  	if (retval) {
> -		goto unlock_and_free;
> +		goto err_free;
>  	}
>  
>  	if (usb_xfer_mode < 0) {
> @@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  		if (retval) {
>  			printk(DRIVER_NAME
>  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
> -			goto unlock_and_free;
> +			goto err_free;
>  		}
>  	}
>  
> @@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	/* Should be the last thing to do, to avoid newer udev's to
>  	   open the device before fully initializing it
>  	 */
> -	mutex_unlock(&dev->lock);
>  
>  	return 0;
>  
> -unlock_and_free:
> -	mutex_unlock(&dev->lock);
> -
>  err_free:
>  	kfree(dev->alt_max_pkt_size_isoc);
>  	kfree(dev);
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 3012912d2997..1113d4e107d8 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -33,6 +33,18 @@
>  
>  #include "em28xx.h"
>  
> +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
> +		      "Markus Rechberger <mrechberger@gmail.com>, " \
> +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
> +		      "Sascha Sommer <saschasommer@freenet.de>"
> +
> +#define DRIVER_DESC         "Empia em28xx based USB core driver"
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(EM28XX_VERSION);
> +
>  /* #define ENABLE_DEBUG_ISOC_FRAMES */
>  
>  static unsigned int core_debug;
> diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
> new file mode 100644
> index 000000000000..bce438691e0e
> --- /dev/null
> +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
> @@ -0,0 +1,20 @@
> +/*
> +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
> +		    video capture devices
The information about supported chips is outdated everywhere in the driver,
but if you introduce a new header file it should really be up to date.
Just talk about EM27xx/EM28xx.

> +
> +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> + */
> +
> +
> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> +extern struct vb2_ops em28xx_vbi_qops;
> diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
> index 39f39c527c13..db3d655600df 100644
> --- a/drivers/media/usb/em28xx/em28xx-vbi.c
> +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
> @@ -27,6 +27,7 @@
>  #include <linux/init.h>
>  
>  #include "em28xx.h"
> +#include "em28xx-v4l.h"
>  
>  static unsigned int vbibufs = 5;
>  module_param(vbibufs, int, 0644);
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 85284626dbd6..d615bff8ac09 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -38,6 +38,7 @@
>  #include <linux/slab.h>
>  
>  #include "em28xx.h"
> +#include "em28xx-v4l.h"
>  #include <media/v4l2-common.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-event.h>
> @@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
>  	},
>  };
>  
> +static int em28xx_vbi_supported(struct em28xx *dev);
> +
Or move em28xx_vbi_supported() before em28xx_set_outfmt() and
em28xx_resolution_set() again.
If you had not changed the functions order in patch 1/22, this wouldn't
be necessary.

>  /*
>   * em28xx_wake_i2c()
>   * configure i2c attached devices
>   */
> -void em28xx_wake_i2c(struct em28xx *dev)
> +static void em28xx_wake_i2c(struct em28xx *dev)
>  {
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> @@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
>  }
>  
> -int em28xx_colorlevels_set_default(struct em28xx *dev)
> +static int em28xx_colorlevels_set_default(struct em28xx *dev)
>  {
>  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
>  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> @@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
>  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
>  }
>  
> -int em28xx_set_outfmt(struct em28xx *dev)
> +static int em28xx_set_outfmt(struct em28xx *dev)
>  {
>  	int ret;
>  	u8 fmt, vinctrl;
> @@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
>  }
>  
>  /* FIXME: this only function read values from dev */
> -int em28xx_resolution_set(struct em28xx *dev)
> +static int em28xx_resolution_set(struct em28xx *dev)
>  {
>  	int width, height;
>  	width = norm_maxw(dev);
> @@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
>  	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
>  }
>  
> -int em28xx_vbi_supported(struct em28xx *dev)
> +static int em28xx_vbi_supported(struct em28xx *dev)
>  {
>  	/* Modprobe option to manually disable */
>  	if (disable_vbi == 1)
> @@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
>  }
>  
>  /* Set USB alternate setting for analog video */
> -int em28xx_set_alternate(struct em28xx *dev)
> +static int em28xx_set_alternate(struct em28xx *dev)
>  {
>  	int errCode;
>  	int i;
> @@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
>  	.wait_finish    = vb2_ops_wait_finish,
>  };
>  
> -int em28xx_vb2_setup(struct em28xx *dev)
> +static int em28xx_vb2_setup(struct em28xx *dev)
>  {
>  	int rc;
>  	struct vb2_queue *q;
> @@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
>  	em28xx_audio_analog_set(dev);
>  }
>  
> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>  {
>  	struct em28xx *dev = priv;
>  
> @@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
>  		reg->val = ret;
>  	} else {
>  		__le16 val = 0;
> -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>  						   reg->reg, (char *)&val, 2);
Urgh... is it really necessary to start using these pointers again ?
Ok... keep it as is, I'll send a patch to clean this up later.

>  		if (ret < 0)
>  			return ret;
> @@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
>  }
>  
>  /*
> - * em28xx_realease_resources()
> + * em28xx_v4l2_fini()
>   * unregisters the v4l2,i2c and usb devices
>   * called when the device gets disconected or at module unload
>  */
> -void em28xx_release_analog_resources(struct em28xx *dev)
> +static int em28xx_v4l2_fini(struct em28xx *dev)
>  {
>  
>  	/*FIXME: I2C IR should be disconnected */
> @@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
>  			video_device_release(dev->vdev);
>  		dev->vdev = NULL;
>  	}
> +
> +	return 0;
>  }
>  
>  /*
> @@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
>  	if (dev->users == 1) {
>  		/* the device is already disconnect,
>  		   free the remaining resources */
> +
>  		if (dev->disconnected) {
> -			em28xx_release_resources(dev);
Who releases the resources now ?

> +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> +			v4l2_device_unregister(&dev->v4l2_dev);
>  			kfree(dev->alt_max_pkt_size_isoc);
> -			mutex_unlock(&dev->lock);
> -			kfree(dev);
> -			return 0;
> +			goto exit;
>  		}
>  
>  		/* Save some power by putting tuner to sleep */
> @@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
>  		}
>  	}
>  
> +exit:
>  	dev->users--;
Nice bugfix.

>  	mutex_unlock(&dev->lock);
>  	return 0;
> @@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
>  
>  /******************************** usb interface ******************************/
>  
> -
> -
>  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>  					const struct video_device *template,
>  					const char *type_name)
> @@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
>  	}
>  }
>  
> -void em28xx_tuner_setup(struct em28xx *dev)
> +static void em28xx_tuner_setup(struct em28xx *dev)
>  {
>  	struct tuner_setup           tun_setup;
>  	struct v4l2_frequency        f;
> @@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
>  }
>  
> -int em28xx_register_analog_devices(struct em28xx *dev)
> +static int em28xx_v4l2_init(struct em28xx *dev)
>  {
>  	u8 val;
>  	int ret;
>  	unsigned int maxw;
>  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>  
> -	if (!dev->is_audio_only) {
> +	if (!dev->has_video) {
>  		/* This device does not support the v4l2 extension */
>  		return 0;
>  	}
> @@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>  		dev->name, EM28XX_VERSION);
>  
> +	mutex_lock(&dev->lock);
> +
>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>  	if (ret < 0) {
>  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> @@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
>  		       EM28XX_VINCTRL_CCIR656_ENABLE;
>  
> +	/* Initialize tuner and camera */
> +	em28xx_tuner_setup(dev);
> +	em28xx_init_camera(dev);
> +
>  	/* Configure audio */
>  	ret = em28xx_audio_setup(dev);
>  	if (ret < 0) {
> @@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  
>  	/* initialize videobuf2 stuff */
>  	em28xx_vb2_setup(dev);
> +
>  err:
> -	return 0;
> +	mutex_unlock(&dev->lock);
> +	return ret;
> +}
> +
> +static struct em28xx_ops v4l2_ops = {
> +	.id   = EM28XX_V4L2,
> +	.name = "Em28xx v4l2 Extension",
> +	.init = em28xx_v4l2_init,
> +	.fini = em28xx_v4l2_fini,
> +};
> +
> +static int __init em28xx_video_register(void)
> +{
> +	return em28xx_register_extension(&v4l2_ops);
>  }
> +
> +static void __exit em28xx_video_unregister(void)
> +{
> +	em28xx_unregister_extension(&v4l2_ops);
> +}
> +
> +module_init(em28xx_video_register);
> +module_exit(em28xx_video_unregister);
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 7ae05ebc13c1..9d6f43e4681f 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -26,7 +26,7 @@
>  #ifndef _EM28XX_H
>  #define _EM28XX_H
>  
> -#define EM28XX_VERSION "0.2.0"
> +#define EM28XX_VERSION "0.2.1"
>  
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>
> @@ -474,6 +474,7 @@ struct em28xx_eeprom {
>  #define EM28XX_AUDIO   0x10
>  #define EM28XX_DVB     0x20
>  #define EM28XX_RC      0x30
> +#define EM28XX_V4L2    0x40
>  
>  /* em28xx resource types (used for res_get/res_lock etc */
>  #define EM28XX_RESOURCE_VIDEO 0x01
> @@ -527,6 +528,7 @@ struct em28xx {
>  
>  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>  	unsigned char disconnected:1;	/* device has been diconnected */
> +	unsigned int has_video:1;
>  	unsigned int has_audio_class:1;
>  	unsigned int has_alsa_audio:1;
>  	unsigned int is_audio_only:1;
> @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
>  int em28xx_audio_analog_set(struct em28xx *dev);
>  int em28xx_audio_setup(struct em28xx *dev);
>  
> -int em28xx_colorlevels_set_default(struct em28xx *dev);
>  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
>  					 enum em28xx_led_role role);
>  int em28xx_capture_start(struct em28xx *dev, int start);
> -int em28xx_vbi_supported(struct em28xx *dev);
> -int em28xx_set_outfmt(struct em28xx *dev);
> -int em28xx_resolution_set(struct em28xx *dev);
> -int em28xx_set_alternate(struct em28xx *dev);
>  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
>  		      int num_bufs, int max_pkt_size, int packet_multiplier);
>  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
> @@ -742,31 +739,17 @@ 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);
> -void em28xx_wake_i2c(struct em28xx *dev);
>  int em28xx_register_extension(struct em28xx_ops *dev);
>  void em28xx_unregister_extension(struct em28xx_ops *dev);
>  void em28xx_init_extension(struct em28xx *dev);
>  void em28xx_close_extension(struct em28xx *dev);
>  
> -/* Provided by em28xx-video.c */
> -void em28xx_tuner_setup(struct em28xx *dev);
> -int em28xx_vb2_setup(struct em28xx *dev);
> -int em28xx_register_analog_devices(struct em28xx *dev);
> -void em28xx_release_analog_resources(struct em28xx *dev);
> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
> -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
> -
>  /* Provided by em28xx-cards.c */
>  extern 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_release_resources(struct em28xx *dev);
>  
> -/* Provided by em28xx-vbi.c */
> -extern struct vb2_ops em28xx_vbi_qops;
> -
>  /* Provided by em28xx-camera.c */
>  int em28xx_detect_sensor(struct em28xx *dev);
>  int em28xx_init_camera(struct em28xx *dev);
Nice clean-up ! :)


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

* Re: [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place
  2014-01-04 10:55 ` [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place Mauro Carvalho Chehab
@ 2014-01-05 10:48   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:48 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> In order to initialize the analog tuner, v4l2 should be registere
> first, or otherwise we get an oops:
>
> [   51.783537] BUG: unable to handle kernel NULL pointer dereference at        )
> [   51.784479] IP: [<ffffffff81319fbb>] __list_add+0x1b/0xc0
> [   51.784479] PGD 0
> [   51.784479] Oops: 0000 [#1] SMP
> [   51.784479] Modules linked in: tvp5150 em28xx(+) tveeprom v4l2_common videode
> [   51.784479] CPU: 0 PID: 946 Comm: systemd-udevd Not tainted 3.13.0-rc1+ #38
> [   51.784479] Hardware name: PCCHIPS P17G/P17G, BIOS 080012  05/14/2008
> [   51.784479] task: ffff880027482080 ti: ffff88003c9b6000 task.ti: ffff88003c90
> [   51.784479] RIP: 0010:[<ffffffff81319fbb>]  [<ffffffff81319fbb>] __list_add+0
> [   51.784479] RSP: 0018:ffff88003c9b7a10  EFLAGS: 00010246
> [   51.784479] RAX: 0000000000000000 RBX: ffff880036d12428 RCX: 0000000000000000
> [   51.784479] RDX: ffff880036ce6040 RSI: 0000000000000000 RDI: ffff880036d12428
> [   51.784479] RBP: ffff88003c9b7a28 R08: 0000000000000000 R09: 0000000000000001
> [   51.784479] R10: 0000000000000001 R11: 0000000000000000 R12: ffff880036ce6040
> [   51.784479] R13: 0000000000000000 R14: ffff880036ce62c0 R15: ffffffffa045c176
> [   51.784479] FS:  00007fba89124880(0000) GS:ffff88003f400000(0000) knlGS:00000
> [   51.784479] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> [   51.784479] CR2: 0000000000000000 CR3: 000000003bccf000 CR4: 00000000000007f0
> [   51.784479] Stack:
> [   51.784479]  ffff880036d12428 ffff880036ce6038 0000000000000000 ffff88003c9b0
> [   51.784479]  ffffffffa0425bbc ffff880028246800 ffff880036d12428 ffff880036ce8
> [   51.784479]  ffff88003c9b7a80 ffffffffa044d733 ffff88003c9b7a90 ffff880036ce8
> [   51.784479] Call Trace:
> [   51.784479]  [<ffffffffa0425bbc>] v4l2_device_register_subdev+0xdc/0x120 [vi]
> [   51.784479]  [<ffffffffa044d733>] v4l2_i2c_new_subdev_board+0xa3/0x100 [v4l2]
> [   51.784479]  [<ffffffffa044d7fa>] v4l2_i2c_new_subdev+0x6a/0x90 [v4l2_common]
> [   51.784479]  [<ffffffffa0455dcb>] em28xx_usb_probe+0xd3b/0x10a0 [em28xx]
> [   51.784479]  [<ffffffff81478f74>] usb_probe_interface+0x1c4/0x2f0
> [   51.784479]  [<ffffffff81400127>] driver_probe_device+0x87/0x390
> [   51.784479]  [<ffffffff81400503>] __driver_attach+0x93/0xa0
> [   51.784479]  [<ffffffff81400470>] ? __device_attach+0x40/0x40
> [   51.784479]  [<ffffffff813fe153>] bus_for_each_dev+0x63/0xa0
> [   51.784479]  [<ffffffff813ffb7e>] driver_attach+0x1e/0x20
> [   51.784479]  [<ffffffff813ff760>] bus_add_driver+0x180/0x250
> [   51.784479]  [<ffffffff81400b34>] driver_register+0x64/0xf0
> [   51.784479]  [<ffffffff81477751>] usb_register_driver+0x81/0x160
> [   51.784479]  [<ffffffffa0467000>] ? 0xffffffffa0466fff
> [   51.784479]  [<ffffffffa046701e>] em28xx_usb_driver_init+0x1e/0x1000 [em28xx]
> [   51.784479]  [<ffffffff8100214a>] do_one_initcall+0xfa/0x1b0
> [   51.784479]  [<ffffffff81053793>] ? set_memory_nx+0x43/0x50
> [   51.784479]  [<ffffffff810d9926>] load_module+0x1bc6/0x24b0
> [   51.784479]  [<ffffffff810d5940>] ? store_uevent+0x40/0x40
> [   51.784479]  [<ffffffff810da386>] SyS_finit_module+0x86/0xb0
> [   51.784479]  [<ffffffff81666529>] system_call_fastpath+0x16/0x1b
> [   51.784479] Code: ff ff 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 1f 00 55 48 89 e
> [   51.784479] RIP  [<ffffffff81319fbb>] __list_add+0x1b/0xc0
> [   51.784479]  RSP <ffff88003c9b7a10>
> [   51.784479] CR2: 0000000000000000
> [   52.218397] ---[ end trace 0bd601544e51b8a3 ]---
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c | 64 --------------------------------
>  drivers/media/usb/em28xx/em28xx-video.c | 65 +++++++++++++++++++++++++++++++++
>  2 files changed, 65 insertions(+), 64 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 938daaabd8e0..d1c75e66554c 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2362,24 +2362,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
>  };
>  /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
>  
> -/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
> -static unsigned short saa711x_addrs[] = {
> -	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
> -	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
> -	I2C_CLIENT_END };
> -
> -static unsigned short tvp5150_addrs[] = {
> -	0xb8 >> 1,
> -	0xba >> 1,
> -	I2C_CLIENT_END
> -};
> -
> -static unsigned short msp3400_addrs[] = {
> -	0x80 >> 1,
> -	0x88 >> 1,
> -	I2C_CLIENT_END
> -};
> -
>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
>  {
>  	struct em28xx_i2c_bus *i2c_bus = ptr;
> @@ -2784,54 +2766,8 @@ static void em28xx_card_setup(struct em28xx *dev)
>  	/* Allow override tuner type by a module parameter */
>  	if (tuner >= 0)
>  		dev->tuner_type = tuner;
> -
> -	/* request some modules */
> -	if (dev->board.has_msp34xx)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"msp3400", 0, msp3400_addrs);
> -
> -	if (dev->board.decoder == EM28XX_SAA711X)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"saa7115_auto", 0, saa711x_addrs);
> -
> -	if (dev->board.decoder == EM28XX_TVP5150)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"tvp5150", 0, tvp5150_addrs);
> -
> -	if (dev->board.adecoder == EM28XX_TVAUDIO)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"tvaudio", dev->board.tvaudio_addr, NULL);
> -
> -	if (dev->board.tuner_type != TUNER_ABSENT) {
> -		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
> -
> -		if (dev->board.radio.type)
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -				"tuner", dev->board.radio_addr, NULL);
> -
> -		if (has_demod)
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev,
> -				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> -				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
> -		if (dev->tuner_addr == 0) {
> -			enum v4l2_i2c_tuner_type type =
> -				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
> -			struct v4l2_subdev *sd;
> -
> -			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
> -				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> -				0, v4l2_i2c_tuner_addrs(type));
> -
> -			if (sd)
> -				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
> -		} else {
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -				"tuner", dev->tuner_addr, NULL);
> -		}
> -	}
>  }
>  
> -
>  static void request_module_async(struct work_struct *work)
>  {
>  	struct em28xx *dev = container_of(work,
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index d615bff8ac09..56d1b46164a0 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -2051,6 +2051,24 @@ static struct video_device em28xx_radio_template = {
>  	.ioctl_ops 	      = &radio_ioctl_ops,
>  };
>  
> +/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
> +static unsigned short saa711x_addrs[] = {
> +	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
> +	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
> +	I2C_CLIENT_END };
> +
> +static unsigned short tvp5150_addrs[] = {
> +	0xb8 >> 1,
> +	0xba >> 1,
> +	I2C_CLIENT_END
> +};
> +
> +static unsigned short msp3400_addrs[] = {
> +	0x80 >> 1,
> +	0x88 >> 1,
> +	I2C_CLIENT_END
> +};
> +
>  /******************************** usb interface ******************************/
>  
>  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
> @@ -2218,7 +2236,54 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
>  		       EM28XX_VINCTRL_CCIR656_ENABLE;
>  
> +	/* request some modules */
> +
> +	if (dev->board.has_msp34xx)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"msp3400", 0, msp3400_addrs);
> +
> +	if (dev->board.decoder == EM28XX_SAA711X)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"saa7115_auto", 0, saa711x_addrs);
> +
> +	if (dev->board.decoder == EM28XX_TVP5150)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"tvp5150", 0, tvp5150_addrs);
> +
> +	if (dev->board.adecoder == EM28XX_TVAUDIO)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"tvaudio", dev->board.tvaudio_addr, NULL);
> +
>  	/* Initialize tuner and camera */
> +
> +	if (dev->board.tuner_type != TUNER_ABSENT) {
> +		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
> +
> +		if (dev->board.radio.type)
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +				"tuner", dev->board.radio_addr, NULL);
> +
> +		if (has_demod)
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev,
> +				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> +				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
> +		if (dev->tuner_addr == 0) {
> +			enum v4l2_i2c_tuner_type type =
> +				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
> +			struct v4l2_subdev *sd;
> +
> +			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
> +				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> +				0, v4l2_i2c_tuner_addrs(type));
> +
> +			if (sd)
> +				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
> +		} else {
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +				"tuner", dev->tuner_addr, NULL);
> +		}
> +	}
> +
>  	em28xx_tuner_setup(dev);
>  	em28xx_init_camera(dev);
>  

Also move em28xx_tuner_setup(dev) and em28xx_init_camera(dev) and do the
whole thing before patch 3 to avoid introducing oopses.


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

* Re: [PATCH v4 06/22] [media] em28xx: add warn messages for timeout
  2014-01-04 10:55 ` [PATCH v4 06/22] [media] em28xx: add warn messages for timeout Mauro Carvalho Chehab
@ 2014-01-05 10:51   ` Frank Schäfer
  2014-01-05 13:05     ` Mauro Carvalho Chehab
  2014-01-05 13:25     ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> changeset 45f04e82d035 added a logic to check if em28xx got
> a timeout on an I2C transfer.
>
> That patch started to produce a series of errors that is present
> with HVR-950, like:
>
> [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
>
> However, as there are several places where -ENODEV is produced,
> there's no way to know what's happening.
>
> So, let's add a printk to report what error condition was reached:
>
> [ 4032.218652] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
>
> Interesting enough, when connected to an USB3 port, the number of
> errors increase:
>
> [ 4249.941375] em2882/3 #0: I2C transfer timeout on writing to addr 0xb8
> [ 4249.941378] tvp5150 19-005c: i2c i/o error: rc == -19 (should be 2)
> [ 4250.023854] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> [ 4250.023857] xc2028 19-0061: Error on line 1299: -19
>
> Due to that, I suspect that the logic in the driver is wrong: instead
> of just returning an error if 0x10 is returned, it should be waiting for
> a while and read the I2C status register again.
>
> However, more tests are needed.
The patch description isn't up-to-date.
It turned out that the bug is in the xc2028 driver.

See
http://www.spinics.net/lists/linux-media/msg71107.html

>
> For now, instead of just returning -ENODEV, output an error message
> to help debug what's happening.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index c4ff9739a7ae..9e6a11d01858 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -80,6 +80,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		if (ret == 0x80 + len - 1) {
>  			return len;
>  		} else if (ret == 0x94 + len - 1) {
> +			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>  			return -ENODEV;
>  		} else if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> @@ -123,6 +124,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		if (ret == 0x84 + len - 1) {
>  			break;
>  		} else if (ret == 0x94 + len - 1) {
> +			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>  			return -ENODEV;
>  		} else if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> @@ -198,6 +200,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		if (ret == 0) { /* success */
>  			return len;
>  		} else if (ret == 0x10) {
> +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
>  			return -ENODEV;
>  		} else if (ret < 0) {
>  			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> @@ -255,6 +258,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  	}
>  	if (ret > 0) {
>  		if (ret == 0x10) {
> +			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
>  			return -ENODEV;
>  		} else {
>  			em28xx_warn("unknown i2c error (status=%i)\n", ret);
> @@ -316,8 +320,10 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	 */
>  	if (!ret)
>  		return len;
> -	else if (ret > 0)
> +	else if (ret > 0) {
> +		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
>  		return -ENODEV;
> +	}
>  
>  	return ret;
>  	/*
> @@ -367,8 +373,10 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	 */
>  	if (!ret)
>  		return len;
> -	else if (ret > 0)
> +	else if (ret > 0) {
> +		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
>  		return -ENODEV;
> +	}
>  
>  	return ret;
>  	/*
NACK.
This will spam the system log on i2c device probing (especially with
sensors).


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

* Re: [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-04 10:55 ` [PATCH v4 07/22] [media] em28xx: improve extension information messages Mauro Carvalho Chehab
@ 2014-01-05 10:55   ` Frank Schäfer
  2014-01-05 13:08     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 10:55 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Add a message with consistent prints before and after each
> extension initialization, and provide a better text for module
> load.
>
> While here, add a missing sanity check for extension finish
> code at em28xx-v4l extension.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
>  drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
>  drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
>  drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
>  drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
>  5 files changed, 20 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 2fdb66ee44ab..263886adcf26 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>  		return 0;
>  	}
>  
> -	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
> +	em28xx_info("Binding audio extension\n");
> +
>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>  			 "Rechberger\n");
>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> @@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
>  	adev->sndcard = card;
>  	adev->udev = dev->udev;
>  
> +	em28xx_info("Audio extension successfully initialized\n");
>  	return 0;
>  }
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 1113d4e107d8..33cf26e106b5 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
>  		ops->init(dev);
>  	}
>  	mutex_unlock(&em28xx_devlist_mutex);
> -	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
> +	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
>  	return 0;
>  }
>  EXPORT_SYMBOL(em28xx_register_extension);
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index ddc0e609065d..f72663a9b5c5 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
>  static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
>  {
>  	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
> -        struct em28xx *dev = i2c_bus->dev;
> +	struct em28xx *dev = i2c_bus->dev;
>  
>  	if (acquire)
>  		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
> @@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  
>  	if (!dev->board.has_dvb) {
>  		/* This device does not support the extension */
> -		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
>  		return 0;
>  	}
>  
> +	em28xx_info("Binding DVB extension\n");
> +
>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>  
>  	if (dvb == NULL) {
> @@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>  	/* MFE lock */
>  	dvb->adapter.mfe_shared = mfe_shared;
>  
> -	em28xx_info("Successfully loaded em28xx-dvb\n");
> +	em28xx_info("DVB extension successfully initialized\n");
>  ret:
>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>  	mutex_unlock(&dev->lock);
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index 93a7d02b9cb4..eed7dd79f734 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>  		return 0;
>  	}
>  
> +	em28xx_info("Registering input extension\n");
> +
>  	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
>  	rc = rc_allocate_device();
>  	if (!ir || !rc)
> @@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>  	if (err)
>  		goto error;
>  
> +	em28xx_info("Input extension successfully initalized\n");
> +
>  	return 0;
>  
>  error:
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 56d1b46164a0..b767262c642b 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>  
>  	/*FIXME: I2C IR should be disconnected */
>  
> +	if (!dev->has_video) {
> +		/* This device does not support the v4l2 extension */
> +		return 0;
> +	}
> +
That's a separate change and AFAICS it's not needed.

>  	if (dev->radio_dev) {
>  		if (video_is_registered(dev->radio_dev))
>  			video_unregister_device(dev->radio_dev);
> @@ -2215,8 +2220,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  		return 0;
>  	}
>  
> -	printk(KERN_INFO "%s: v4l2 driver version %s\n",
> -		dev->name, EM28XX_VERSION);
> +	em28xx_info("Registering V4L2 extension\n");
>  
>  	mutex_lock(&dev->lock);
>  
> @@ -2498,6 +2502,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  	/* initialize videobuf2 stuff */
>  	em28xx_vb2_setup(dev);
>  
> +	em28xx_info("V4L2 extension successfully initialized\n");
> +
>  err:
>  	mutex_unlock(&dev->lock);
>  	return ret;


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

* Re: [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies
  2014-01-04 10:55 ` [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies Mauro Carvalho Chehab
@ 2014-01-05 11:03   ` Frank Schäfer
  2014-01-05 13:10     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:03 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> The I2C wait completion/timeout logic currently assumes that
> msleep(5) will wait exaclty 5 ms. This is not true at all,
> as it depends on CONFIG_HZ.
>
> Convert it to use jiffies, in order to not wait for more time
> than needed.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 65 ++++++++++++++++++-----------------
>  1 file changed, 34 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index 9e6a11d01858..9fa7ed51e5b1 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -26,6 +26,7 @@
>  #include <linux/kernel.h>
>  #include <linux/usb.h>
>  #include <linux/i2c.h>
> +#include <linux/jiffies.h>
>  
>  #include "em28xx.h"
>  #include "tuner-xc2028.h"
> @@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
>   */
>  static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  {
> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
>  	int ret;
> -	int write_timeout;
>  	u8 b2[6];
>  
>  	if (len < 1 || len > 4)
> @@ -74,15 +75,15 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		return (ret < 0) ? ret : -EIO;
>  	}
>  	/* wait for completion */
> -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
> -	     write_timeout -= 5) {
> +	while (time_is_after_jiffies(timeout)) {
AFAIU, it must be time_is_before_jiffies(timeout).

>  		ret = dev->em28xx_read_reg(dev, 0x05);
> -		if (ret == 0x80 + len - 1) {
> +		if (ret == 0x80 + len - 1)
>  			return len;
> -		} else if (ret == 0x94 + len - 1) {
> +		if (ret == 0x94 + len - 1) {
>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>  			return -ENODEV;
> -		} else if (ret < 0) {
> +		}
> +		if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>  				    ret);
>  			return ret;
> @@ -99,9 +100,9 @@ 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(EM2800_I2C_XFER_TIMEOUT);
>  	u8 buf2[4];
>  	int ret;
> -	int read_timeout;
>  	int i;
>  
>  	if (len < 1 || len > 4)
> @@ -118,15 +119,15 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  	}
>  
>  	/* wait for completion */
> -	for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
> -	     read_timeout -= 5) {
> +	while (time_is_after_jiffies(timeout)) {
The same here...

>  		ret = dev->em28xx_read_reg(dev, 0x05);
> -		if (ret == 0x84 + len - 1) {
> +		if (ret == 0x84 + len - 1)
>  			break;
> -		} else if (ret == 0x94 + len - 1) {
> +		if (ret == 0x94 + len - 1) {
>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>  			return -ENODEV;
> -		} else if (ret < 0) {
> +		}
> +		if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>  				    ret);
>  			return ret;
> @@ -170,7 +171,8 @@ 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)
>  {
> -	int write_timeout, ret;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
> +	int ret;
>  
>  	if (len < 1 || len > 64)
>  		return -EOPNOTSUPP;
> @@ -193,17 +195,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		}
>  	}
>  
> -	/* Check success of the i2c operation */
> -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
> -	     write_timeout -= 5) {
> +	/* wait for completion */
> +	while (time_is_after_jiffies(timeout)) {
... and here.

>  		ret = dev->em28xx_read_reg(dev, 0x05);
> -		if (ret == 0) { /* success */
> +		if (ret == 0) /* success */
>  			return len;
> -		} else if (ret == 0x10) {
> -			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
> +		if (ret == 0x10) {
> +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
> +				    addr);
>  			return -ENODEV;
> -		} else if (ret < 0) {
> -			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> +		}
> +		if (ret < 0) {
> +			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>  				    ret);
>  			return ret;
>  		}
> @@ -214,6 +217,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		 * (even with high payload) ...
>  		 */
>  	}
> +
>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>  	return -EIO;
>  }
> @@ -251,21 +255,20 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  
>  	/* Check success of the i2c operation */
>  	ret = dev->em28xx_read_reg(dev, 0x05);
> +	if (ret == 0) /* success */
> +		return len;
>  	if (ret < 0) {
> -		em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> +		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>  			    ret);
>  		return ret;
>  	}
> -	if (ret > 0) {
> -		if (ret == 0x10) {
> -			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> -			return -ENODEV;
> -		} else {
> -			em28xx_warn("unknown i2c error (status=%i)\n", ret);
> -			return -EIO;
> -		}
> +	if (ret == 0x10) {
> +		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> +		return -ENODEV;
>  	}
> -	return len;
> +
> +	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> +	return -EIO;
>  }
>  
>  /*


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

* Re: [PATCH v4 09/22] [media] tvp5150: make read operations atomic
  2014-01-04 10:55 ` [PATCH v4 09/22] [media] tvp5150: make read operations atomic Mauro Carvalho Chehab
@ 2014-01-05 11:07   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Instead of using two I2C operations between write and read,
> use just one i2c_transfer. That allows I2C mutexes to not
> let any other I2C transfer between the two.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/i2c/tvp5150.c | 26 +++++++++++---------------
>  1 file changed, 11 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 89c0b13463b7..2ed05b67218b 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -58,21 +58,17 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
>  	struct i2c_client *c = v4l2_get_subdevdata(sd);
>  	unsigned char buffer[1];
>  	int rc;
> -
> -	buffer[0] = addr;
> -
> -	rc = i2c_master_send(c, buffer, 1);
> -	if (rc < 0) {
> -		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
> -		return rc;
> -	}
> -
> -	msleep(10);
> -
> -	rc = i2c_master_recv(c, buffer, 1);
> -	if (rc < 0) {
> -		v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
> -		return rc;
> +	struct i2c_msg msg[] = {
> +		{ .addr = c->addr, .flags = 0,
> +		  .buf = &addr, .len = 1 },
> +		{ .addr = c->addr, .flags = I2C_M_RD,
> +		  .buf = buffer, .len = 1 }
> +	};
> +
> +	rc = i2c_transfer(c->adapter, msg, 2);
> +	if (rc < 0 || rc != 2) {
> +		v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
> +		return rc < 0 ? rc : -EIO;
>  	}
>  
>  	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Tested-by: Frank Schäfer <fschaefer.oss@googlemail.com>



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

* Re: [PATCH v4 10/22] [media] tuner-xc2028: remove unused code
  2014-01-04 10:55 ` [PATCH v4 10/22] [media] tuner-xc2028: remove unused code Mauro Carvalho Chehab
@ 2014-01-05 11:07   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> This macro is not used. remove it.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/tuners/tuner-xc2028.c | 9 ---------
>  1 file changed, 9 deletions(-)
>
> diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
> index 4be5cf808a40..1057da54c6e0 100644
> --- a/drivers/media/tuners/tuner-xc2028.c
> +++ b/drivers/media/tuners/tuner-xc2028.c
> @@ -134,15 +134,6 @@ struct xc2028_data {
>  	_rc;								\
>  })
>  
> -#define i2c_rcv(priv, buf, size) ({					\
> -	int _rc;							\
> -	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
> -	if (size != _rc)						\
> -		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
> -			   _rc, (int)size); 				\
> -	_rc;								\
> -})
> -
>  #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
>  	int _rc;							\
>  	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier
  2014-01-04 10:55 ` [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier Mauro Carvalho Chehab
@ 2014-01-05 11:12   ` Frank Schäfer
  2014-01-05 13:22     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:12 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Better to split chipset detection from the audio setup. So, move the
> detection code to em28xx_init_dev().
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c | 11 +++++++++++
>  drivers/media/usb/em28xx/em28xx-core.c  | 12 +-----------
>  2 files changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index d1c75e66554c..4fe742429f2c 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2930,6 +2930,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		}
>  	}
>  
> +	if (dev->chip_id == CHIP_ID_EM2870 ||
> +	    dev->chip_id == CHIP_ID_EM2874 ||
> +	    dev->chip_id == CHIP_ID_EM28174 ||
> +	    dev->chip_id == CHIP_ID_EM28178) {
> +		/* Digital only device - don't load any alsa module */
> +		dev->audio_mode.has_audio = false;
> +		dev->has_audio_class = false;
> +		dev->has_alsa_audio = false;
> +	}
> +
>  	if (chip_name != default_chip_name)
>  		printk(KERN_INFO DRIVER_NAME
>  		       ": chip ID is %s\n", chip_name);
> @@ -3196,6 +3206,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	dev->alt   = -1;
>  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
>  	dev->has_alsa_audio = has_audio;
> +	dev->audio_mode.has_audio = has_audio;
>  	dev->has_video = has_video;
>  	dev->audio_ifnum = ifnum;
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 33cf26e106b5..818248d3fd28 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -505,18 +505,8 @@ int em28xx_audio_setup(struct em28xx *dev)
>  	int vid1, vid2, feat, cfg;
>  	u32 vid;
>  
> -	if (dev->chip_id == CHIP_ID_EM2870 ||
> -	    dev->chip_id == CHIP_ID_EM2874 ||
> -	    dev->chip_id == CHIP_ID_EM28174 ||
> -	    dev->chip_id == CHIP_ID_EM28178) {
> -		/* Digital only device - don't load any alsa module */
> -		dev->audio_mode.has_audio = false;
> -		dev->has_audio_class = false;
> -		dev->has_alsa_audio = false;
> +	if (!dev->audio_mode.has_audio)
>  		return 0;
> -	}
> -
> -	dev->audio_mode.has_audio = true;
>  
>  	/* See how this device is configured */
>  	cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
It's not clear to me how one of these audio variables could ever become
true with these chip types, so this code should probably just be removed.


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

* Re: [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code
  2014-01-04 10:55 ` [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code Mauro Carvalho Chehab
@ 2014-01-05 11:19   ` Frank Schäfer
  2014-01-05 13:20     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:19 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Instead of assuming that msleep() is precise, use a jiffies
> based code to wait for AC97 to be available.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-core.c | 7 +++++--
>  drivers/media/usb/em28xx/em28xx.h      | 5 ++++-
>  2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 818248d3fd28..36b2f1ab4474 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -23,6 +23,7 @@
>   */
>  
>  #include <linux/init.h>
> +#include <linux/jiffies.h>
>  #include <linux/list.h>
>  #include <linux/module.h>
>  #include <linux/slab.h>
> @@ -254,16 +255,18 @@ EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
>   */
>  static int em28xx_is_ac97_ready(struct em28xx *dev)
>  {
> -	int ret, i;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_AC97_XFER_TIMEOUT);
> +	int ret;
>  
>  	/* Wait up to 50 ms for AC97 command to complete */
> -	for (i = 0; i < 10; i++, msleep(5)) {
> +	while (time_is_after_jiffies(timeout)) {
time_is_before_jiffies(timeout)

>  		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
>  		if (ret < 0)
>  			return ret;
>  
>  		if (!(ret & 0x01))
>  			return 0;
> +		msleep (5);
>  	}
>  
>  	em28xx_warn("AC97 command still being executed: not handled properly!\n");
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 9d6f43e4681f..ac79501f5d9f 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -182,9 +182,12 @@
>  
>  #define EM28XX_INTERLACED_DEFAULT 1
>  
> -/* time in msecs to wait for i2c writes to finish */
> +/* time in msecs to wait for i2c xfers to finish */
>  #define EM2800_I2C_XFER_TIMEOUT		20
>  
> +/* time in msecs to wait for AC97 xfers to finish */
> +#define EM2800_AC97_XFER_TIMEOUT	100
> +
I applies to all chips supporting AC97 audio, so call it
EM28XX_AC97_XFER_TIMEOUT.

Why did you increase the timeout from 50ms to 100ms ?
50ms already seems to be a lot !

IIRC, the problem you are trying to fix is that the chip sometimes is
not yet ready when probing.
But that should be solved with a single sleep before accessing the AC97
chip for the first time instead ?!

>  /* max. number of button state polling addresses */
>  #define EM28XX_NUM_BUTTON_ADDRESSES_MAX		5
>  


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

* Re: [PATCH v4 13/22] [media] em28xx: initialize audio latter
  2014-01-04 10:55 ` [PATCH v4 13/22] [media] em28xx: initialize audio latter Mauro Carvalho Chehab
@ 2014-01-05 11:29   ` Frank Schäfer
  2014-01-05 13:17     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:29 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Better to first write the GPIOs of the input mux, before initializing
> the audio.
Why are you making this change ?

> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-video.c | 40 ++++++++++++++++-----------------
>  1 file changed, 20 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index b767262c642b..328d724a13ea 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -2291,26 +2291,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  	em28xx_tuner_setup(dev);
>  	em28xx_init_camera(dev);
>  
> -	/* Configure audio */
> -	ret = em28xx_audio_setup(dev);
> -	if (ret < 0) {
> -		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> -			__func__, ret);
> -		goto err;
> -	}
> -	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> -	} else {
> -		/* install the em28xx notify callback */
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> -				em28xx_ctrl_notify, dev);
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> -				em28xx_ctrl_notify, dev);
> -	}
> -
>  	/* wake i2c devices */
>  	em28xx_wake_i2c(dev);
>  
> @@ -2356,6 +2336,26 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>  
>  	video_mux(dev, 0);
>  
> +	/* Configure audio */
> +	ret = em28xx_audio_setup(dev);
> +	if (ret < 0) {
> +		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> +			__func__, ret);
> +		goto err;
> +	}
> +	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> +	} else {
> +		/* install the em28xx notify callback */
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> +				em28xx_ctrl_notify, dev);
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> +				em28xx_ctrl_notify, dev);
> +	}
> +
>  	/* Audio defaults */
>  	dev->mute = 1;
>  	dev->volume = 0x1f;
Well, the v4l/core split didn't change the order.
And if the current order would be wrong, then you would also have to
call audio_setup() each time the user switches the input.

So unless you are trying to fix a real bug, I wouldn't change it.
The current order is sane and we likely could never change it back later
without risking regressions...



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

* Re: [PATCH v4 14/22] [media] em28xx: unify module version
  2014-01-04 10:55 ` [PATCH v4 14/22] [media] em28xx: unify module version Mauro Carvalho Chehab
@ 2014-01-05 11:33   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:33 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Use the same module version on all em28xx sub-modules, and use
> the same naming convention to describe the driver.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-audio.c | 3 ++-
>  drivers/media/usb/em28xx/em28xx-core.c  | 2 --
>  drivers/media/usb/em28xx/em28xx-dvb.c   | 4 +++-
>  drivers/media/usb/em28xx/em28xx-input.c | 3 ++-
>  drivers/media/usb/em28xx/em28xx-video.c | 4 +---
>  drivers/media/usb/em28xx/em28xx.h       | 1 +
>  6 files changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index 263886adcf26..a6eef06ffdcd 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -747,7 +747,8 @@ static void __exit em28xx_alsa_unregister(void)
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
>  MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
> -MODULE_DESCRIPTION("Em28xx Audio driver");
> +MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
> +MODULE_VERSION(EM28XX_VERSION);
>  
>  module_init(em28xx_alsa_register);
>  module_exit(em28xx_alsa_unregister);
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 36b2f1ab4474..2ad84ff1fc4f 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -39,8 +39,6 @@
>  		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
>  		      "Sascha Sommer <saschasommer@freenet.de>"
>  
> -#define DRIVER_DESC         "Empia em28xx based USB core driver"
> -
>  MODULE_AUTHOR(DRIVER_AUTHOR);
>  MODULE_DESCRIPTION(DRIVER_DESC);
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> index f72663a9b5c5..7fa1c804c34c 100644
> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> @@ -54,9 +54,11 @@
>  #include "m88ds3103.h"
>  #include "m88ts2022.h"
>  
> -MODULE_DESCRIPTION("driver for em28xx based DVB cards");
>  MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
>  MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
> +MODULE_VERSION(EM28XX_VERSION);
> +
>  
>  static unsigned int debug;
>  module_param(debug, int, 0644);
> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> index eed7dd79f734..f3b629dd57ae 100644
> --- a/drivers/media/usb/em28xx/em28xx-input.c
> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> @@ -836,7 +836,8 @@ static void __exit em28xx_rc_unregister(void)
>  
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
> -MODULE_DESCRIPTION("Em28xx Input driver");
> +MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
> +MODULE_VERSION(EM28XX_VERSION);
>  
>  module_init(em28xx_rc_register);
>  module_exit(em28xx_rc_unregister);
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 328d724a13ea..999cbfe766a3 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -50,8 +50,6 @@
>  		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
>  		      "Sascha Sommer <saschasommer@freenet.de>"
>  
> -#define DRIVER_DESC         "Empia em28xx based USB video device driver"
> -
>  static unsigned int isoc_debug;
>  module_param(isoc_debug, int, 0644);
>  MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> @@ -78,7 +76,7 @@ do {\
>    } while (0)
>  
>  MODULE_AUTHOR(DRIVER_AUTHOR);
> -MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
>  MODULE_LICENSE("GPL");
>  MODULE_VERSION(EM28XX_VERSION);
>  
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index ac79501f5d9f..db47c2236ca4 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -27,6 +27,7 @@
>  #define _EM28XX_H
>  
>  #define EM28XX_VERSION "0.2.1"
> +#define DRIVER_DESC    "Empia em28xx device driver"
>  
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>

Looks much better now. :)

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock
  2014-01-04 10:55 ` [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock Mauro Carvalho Chehab
@ 2014-01-05 11:38   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 11:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> When em28xx extensions are loaded/removed, there are two locks:
>
> a single static em28xx_devlist_mutex that registers each extension
> and the struct em28xx dev->lock.
>
> When extensions are registered, em28xx_devlist_mutex is taken first,
> and then dev->lock.
>
> Be sure that, when extensions are being removed, the same order
> will be used.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-cards.c | 5 +++--
>  drivers/media/usb/em28xx/em28xx-core.c  | 2 ++
>  2 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 4fe742429f2c..36aec50e5c3b 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -3334,9 +3334,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>  	dev->disconnected = 1;
>  
>  	if (dev->is_audio_only) {
> -		mutex_lock(&dev->lock);
>  		em28xx_close_extension(dev);
> -		mutex_unlock(&dev->lock);
>  		return;
>  	}
>  
> @@ -3355,10 +3353,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
>  		em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
>  		em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
>  	}
> +	mutex_unlock(&dev->lock);
>  
>  	em28xx_close_extension(dev);
> +
>  	/* NOTE: must be called BEFORE the resources are released */
>  
> +	mutex_lock(&dev->lock);
>  	if (!dev->users)
>  		em28xx_release_resources(dev);
>  
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index 2ad84ff1fc4f..97cc83c3c287 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -1097,10 +1097,12 @@ void em28xx_close_extension(struct em28xx *dev)
>  	const struct em28xx_ops *ops = NULL;
>  
>  	mutex_lock(&em28xx_devlist_mutex);
> +	mutex_lock(&dev->lock);
>  	list_for_each_entry(ops, &em28xx_extension_devlist, next) {
>  		if (ops->fini)
>  			ops->fini(dev);
>  	}
> +	mutex_unlock(&dev->lock);
>  	list_del(&dev->devlist);
>  	mutex_unlock(&em28xx_devlist_mutex);
>  }

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>

Thank you for fixing this issue.

I will review the remaining patches this evening.


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

* Re: [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-05 10:47   ` Frank Schäfer
@ 2014-01-05 12:56     ` Mauro Carvalho Chehab
  2014-01-05 15:18       ` Mauro Carvalho Chehab
  2014-01-06 17:38       ` Frank Schäfer
  0 siblings, 2 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 12:56 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:47:00 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Now that all analog-specific code are at em28xx-video, convert
> > it into an em28xx extension and load it as a separate module.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/Kconfig         |  6 ++-
> >  drivers/media/usb/em28xx/Makefile        |  5 ++-
> >  drivers/media/usb/em28xx/em28xx-camera.c |  1 +
> >  drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
> >  drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
> >  drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
> >  drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
> >  drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
> >  drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
> >  9 files changed, 107 insertions(+), 80 deletions(-)
> >  create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h
> >
> > diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
> > index d6ba514d31eb..838fc9dbb747 100644
> > --- a/drivers/media/usb/em28xx/Kconfig
> > +++ b/drivers/media/usb/em28xx/Kconfig
> > @@ -1,8 +1,12 @@
> >  config VIDEO_EM28XX
> > -	tristate "Empia EM28xx USB video capture support"
> > +	tristate "Empia EM28xx USB devices support"
> >  	depends on VIDEO_DEV && I2C
> >  	select VIDEO_TUNER
> >  	select VIDEO_TVEEPROM
> > +
> > +config VIDEO_EM28XX_V4L2
> > +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
> > +	depends on VIDEO_EM28XX && I2C
> VIDEO_EM28XX already depends on I2C.
> 
> >  	select VIDEOBUF2_VMALLOC
> >  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
> >  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
> > diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
> > index ad6d48557940..3f850d5063d0 100644
> > --- a/drivers/media/usb/em28xx/Makefile
> > +++ b/drivers/media/usb/em28xx/Makefile
> > @@ -1,10 +1,11 @@
> > -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
> > -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
> > +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
> >  
> > +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
> >  em28xx-alsa-objs := em28xx-audio.o
> >  em28xx-rc-objs := em28xx-input.o
> >  
> >  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
> > +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
> >  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
> >  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
> >  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
> > diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
> > index d666741797d4..c29f5c4e7b40 100644
> > --- a/drivers/media/usb/em28xx/em28xx-camera.c
> > +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> > @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
> >  
> >  	return ret;
> >  }
> > +EXPORT_SYMBOL_GPL(em28xx_init_camera);
> em28xx-camera should also be part of the em28xx-v4l module.

I tried that. Moving em28xx-camera to em28xx-v4l would cause a recursive
dependency, due to the camera probing logic, that should be called by
em28xx-cards.c.

Moving that probing part to em28xx-v4l is too complex, due to the code
that detects the board.

One solution would be to break em28xx-camera into two parts: the detection
code, to be merged with the core, and the sensor part, to be merged with
em28xx-v4l, but that sounds ugly.

Other solution would be to use something like the dvb_attach() macro,
to avoid the recursive dependency, but that would be a dirty solution.

As the code there is not big, the amount of overhead of having everything
at em28xx-core is not high. So, I opted to keep the simplest path here,
avoiding the risk of breaking something with a complex changeset.

> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index 175cd776e0a1..938daaabd8e0 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
> >  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
> >  	},
> >  };
> > +EXPORT_SYMBOL_GPL(em28xx_boards);
> > +
> >  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
> >  
> >  /* table of devices that work with this driver */
> > @@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
> >  				"tuner", dev->tuner_addr, NULL);
> >  		}
> >  	}
> > -
> > -	em28xx_tuner_setup(dev);
> > -
> > -	em28xx_init_camera(dev);
> >  }
> Here you are fixing half of the em28xx_card_setup() oopses which you've
> introduced with patch 3/22.
> This needs to be done together with patch 5/22 before patch 3/22.

Ok.

> > @@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
> >  	em28xx_init_extension(dev);
> >  
> >  #if defined(CONFIG_MODULES) && defined(MODULE)
> > +	if (dev->has_video)
> > +		request_module("em28xx-v4l");
> >  	if (dev->has_audio_class)
> >  		request_module("snd-usb-audio");
> >  	else if (dev->has_alsa_audio)
> >  		request_module("em28xx-alsa");
> > -
> >  	if (dev->board.has_dvb)
> >  		request_module("em28xx-dvb");
> >  	if (dev->board.buttons ||
> > @@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
> >  {
> >  	/*FIXME: I2C IR should be disconnected */
> >  
> > -	em28xx_release_analog_resources(dev);
> > -
> >  	if (dev->def_i2c_bus)
> >  		em28xx_i2c_unregister(dev, 1);
> >  	em28xx_i2c_unregister(dev, 0);
> >  	if (dev->clk)
> >  		v4l2_clk_unregister_fixed(dev->clk);
> >  
> > -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > -
> > -	v4l2_device_unregister(&dev->v4l2_dev);
> > -
> >  	usb_put_dev(dev->udev);
> >  
> >  	/* Mark device as unused */
> > @@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  	if (retval < 0) {
> >  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
> >  			__func__, retval);
> > -		goto unregister_dev;
> > +		return retval;
> >  	}
> >  
> >  	/* register i2c bus 1 */
> > @@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  		if (retval < 0) {
> >  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
> >  				__func__, retval);
> > -			goto unregister_dev;
> > +			return retval;
> >  		}
> >  	}
> Hmm... if registering of bus 1 fails, we need to unregister bus 0.
> But that's an old bug which we can fix later...

Good point. Yes, this should be on a separate patch.

> >  	/* Do board specific init and eeprom reading */
> >  	em28xx_card_setup(dev);
> >  
> > -	retval = em28xx_register_analog_devices(dev);
> > -	if (retval < 0) {
> > -		goto fail;
> > -	}
> > -
> >  	return 0;
> > -
> > -fail:
> > -	if (dev->def_i2c_bus)
> > -		em28xx_i2c_unregister(dev, 1);
> > -	em28xx_i2c_unregister(dev, 0);
> > -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > -
> > -unregister_dev:
> > -	v4l2_device_unregister(&dev->v4l2_dev);
> > -
> > -	return retval;
> >  }
> >  
> >  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
> > @@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  	dev->alt   = -1;
> >  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
> >  	dev->has_alsa_audio = has_audio;
> > +	dev->has_video = has_video;
> >  	dev->audio_ifnum = ifnum;
> >  
> >  	/* Checks if audio is provided by some interface */
> > @@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  
> >  	/* allocate device struct */
> >  	mutex_init(&dev->lock);
> > -	mutex_lock(&dev->lock);
> >  	retval = em28xx_init_dev(dev, udev, interface, nr);
> >  	if (retval) {
> > -		goto unlock_and_free;
> > +		goto err_free;
> >  	}
> >  
> >  	if (usb_xfer_mode < 0) {
> > @@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  		if (retval) {
> >  			printk(DRIVER_NAME
> >  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
> > -			goto unlock_and_free;
> > +			goto err_free;
> >  		}
> >  	}
> >  
> > @@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  	/* Should be the last thing to do, to avoid newer udev's to
> >  	   open the device before fully initializing it
> >  	 */
> > -	mutex_unlock(&dev->lock);
> >  
> >  	return 0;
> >  
> > -unlock_and_free:
> > -	mutex_unlock(&dev->lock);
> > -
> >  err_free:
> >  	kfree(dev->alt_max_pkt_size_isoc);
> >  	kfree(dev);
> > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > index 3012912d2997..1113d4e107d8 100644
> > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > @@ -33,6 +33,18 @@
> >  
> >  #include "em28xx.h"
> >  
> > +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
> > +		      "Markus Rechberger <mrechberger@gmail.com>, " \
> > +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
> > +		      "Sascha Sommer <saschasommer@freenet.de>"
> > +
> > +#define DRIVER_DESC         "Empia em28xx based USB core driver"
> > +
> > +MODULE_AUTHOR(DRIVER_AUTHOR);
> > +MODULE_DESCRIPTION(DRIVER_DESC);
> > +MODULE_LICENSE("GPL");
> > +MODULE_VERSION(EM28XX_VERSION);
> > +
> >  /* #define ENABLE_DEBUG_ISOC_FRAMES */
> >  
> >  static unsigned int core_debug;
> > diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
> > new file mode 100644
> > index 000000000000..bce438691e0e
> > --- /dev/null
> > +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
> > @@ -0,0 +1,20 @@
> > +/*
> > +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
> > +		    video capture devices
> The information about supported chips is outdated everywhere in the driver,
> but if you introduce a new header file it should really be up to date.
> Just talk about EM27xx/EM28xx.

We need to do a cleanup on all those headers: they don't follow Kernel
CodingStyle and the old headers use my previous email.

For the sake of keeping a coherency, I deliberately opted to just use the
same way as the other headers.

My plan is to write a patch series fixing this and other CodingStyle
issues on em28xx after merging this changeset.

> > +
> > +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
> > +
> > +   This program is free software; you can redistribute it and/or modify
> > +   it under the terms of the GNU General Public License as published by
> > +   the Free Software Foundation version 2 of the License.
> > +
> > +   This program is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +   GNU General Public License for more details.
> > + */
> > +
> > +
> > +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> > +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> > +extern struct vb2_ops em28xx_vbi_qops;
> > diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
> > index 39f39c527c13..db3d655600df 100644
> > --- a/drivers/media/usb/em28xx/em28xx-vbi.c
> > +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
> > @@ -27,6 +27,7 @@
> >  #include <linux/init.h>
> >  
> >  #include "em28xx.h"
> > +#include "em28xx-v4l.h"
> >  
> >  static unsigned int vbibufs = 5;
> >  module_param(vbibufs, int, 0644);
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index 85284626dbd6..d615bff8ac09 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -38,6 +38,7 @@
> >  #include <linux/slab.h>
> >  
> >  #include "em28xx.h"
> > +#include "em28xx-v4l.h"
> >  #include <media/v4l2-common.h>
> >  #include <media/v4l2-ioctl.h>
> >  #include <media/v4l2-event.h>
> > @@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
> >  	},
> >  };
> >  
> > +static int em28xx_vbi_supported(struct em28xx *dev);
> > +
> Or move em28xx_vbi_supported() before em28xx_set_outfmt() and
> em28xx_resolution_set() again.
> If you had not changed the functions order in patch 1/22, this wouldn't
> be necessary.

True. I'll put an extra cleanup patch to remove this reference on the
CodingStyle cleanup patchset I'm planning to do.

> >  /*
> >   * em28xx_wake_i2c()
> >   * configure i2c attached devices
> >   */
> > -void em28xx_wake_i2c(struct em28xx *dev)
> > +static void em28xx_wake_i2c(struct em28xx *dev)
> >  {
> >  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> >  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> > @@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
> >  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> >  }
> >  
> > -int em28xx_colorlevels_set_default(struct em28xx *dev)
> > +static int em28xx_colorlevels_set_default(struct em28xx *dev)
> >  {
> >  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> >  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> > @@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
> >  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> >  }
> >  
> > -int em28xx_set_outfmt(struct em28xx *dev)
> > +static int em28xx_set_outfmt(struct em28xx *dev)
> >  {
> >  	int ret;
> >  	u8 fmt, vinctrl;
> > @@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> >  }
> >  
> >  /* FIXME: this only function read values from dev */
> > -int em28xx_resolution_set(struct em28xx *dev)
> > +static int em28xx_resolution_set(struct em28xx *dev)
> >  {
> >  	int width, height;
> >  	width = norm_maxw(dev);
> > @@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
> >  	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> >  }
> >  
> > -int em28xx_vbi_supported(struct em28xx *dev)
> > +static int em28xx_vbi_supported(struct em28xx *dev)
> >  {
> >  	/* Modprobe option to manually disable */
> >  	if (disable_vbi == 1)
> > @@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
> >  }
> >  
> >  /* Set USB alternate setting for analog video */
> > -int em28xx_set_alternate(struct em28xx *dev)
> > +static int em28xx_set_alternate(struct em28xx *dev)
> >  {
> >  	int errCode;
> >  	int i;
> > @@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
> >  	.wait_finish    = vb2_ops_wait_finish,
> >  };
> >  
> > -int em28xx_vb2_setup(struct em28xx *dev)
> > +static int em28xx_vb2_setup(struct em28xx *dev)
> >  {
> >  	int rc;
> >  	struct vb2_queue *q;
> > @@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
> >  	em28xx_audio_analog_set(dev);
> >  }
> >  
> > -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> > +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> >  {
> >  	struct em28xx *dev = priv;
> >  
> > @@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
> >  		reg->val = ret;
> >  	} else {
> >  		__le16 val = 0;
> > -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> > +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> >  						   reg->reg, (char *)&val, 2);
> Urgh... is it really necessary to start using these pointers again ?
> Ok... keep it as is, I'll send a patch to clean this up later.

This is one of the few places where we weren't using those pointers:

$ git grep em28xx_read_reg_req_len drivers/media/usb/em28xx/
drivers/media/usb/em28xx/em28xx-cards.c:  dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
drivers/media/usb/em28xx/em28xx-core.c:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
drivers/media/usb/em28xx/em28xx-core.c:   ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
drivers/media/usb/em28xx/em28xx-core.c:   ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
drivers/media/usb/em28xx/em28xx-i2c.c:            ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
drivers/media/usb/em28xx/em28xx-video.c:          ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
drivers/media/usb/em28xx/em28xx.h:        int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
drivers/media/usb/em28xx/em28xx.h:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,

For the sake of coherency, we should either use one or the other way.

> 
> >  		if (ret < 0)
> >  			return ret;
> > @@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
> >  }
> >  
> >  /*
> > - * em28xx_realease_resources()
> > + * em28xx_v4l2_fini()
> >   * unregisters the v4l2,i2c and usb devices
> >   * called when the device gets disconected or at module unload
> >  */
> > -void em28xx_release_analog_resources(struct em28xx *dev)
> > +static int em28xx_v4l2_fini(struct em28xx *dev)
> >  {
> >  
> >  	/*FIXME: I2C IR should be disconnected */
> > @@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
> >  			video_device_release(dev->vdev);
> >  		dev->vdev = NULL;
> >  	}
> > +
> > +	return 0;
> >  }
> >  
> >  /*
> > @@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
> >  	if (dev->users == 1) {
> >  		/* the device is already disconnect,
> >  		   free the remaining resources */
> > +
> >  		if (dev->disconnected) {
> > -			em28xx_release_resources(dev);
> Who releases the resources now ?

This is tricky.

The hole idea is that em28xx-v4l release the resources allocated for V4L
only, and not all resources, the same way as the other em28xx modules
do.

If you take a look at the original em28xx_release_resources(), what it does
is to call this function, and then to de-allocate and unregister v4l2:

			v4l2_ctrl_handler_free(&dev->ctrl_handler);
			v4l2_device_unregister(&dev->v4l2_dev);

after that, it deallocates the rest of allocated data.

Now, em28xx_release_resources() is only called when em28xx is removed
from memory or when the device is removed.

The code there first calls em28xx_close_extension(dev). So, at device
removal, em28xx-v4l will release the V4L2 specific resources, and
em28xx_release_resources() will drop the common dev struct.

I suspect that it might still be a bug there, but, if so, this bug is 
also present on em28xx-dvb, em28xx-alsa and em28xx-rc: what happens if 
the device is removed while the file descriptors is still opened?

Maybe the driver core already prevent such things, but I'm not sure.

If there's a bug out there, the proper fix seems to use kref for 
struct em28xx, increasing refcount for every em28xx extension and/or 
file open, decreasing it at either extension fini call, or at file close.

This way, em28xx_release_resources() would be called only after refcount
reaching zero, e. g. after being sure that nobody is using it.

My plan is to take a look on it after having this changeset merged,
as such change, if needed, will be complex and would require lots of
testing. Also, it is independent on those changes.

> 
> > +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > +			v4l2_device_unregister(&dev->v4l2_dev);
> >  			kfree(dev->alt_max_pkt_size_isoc);
> > -			mutex_unlock(&dev->lock);
> > -			kfree(dev);
> > -			return 0;
> > +			goto exit;
> >  		}
> >  
> >  		/* Save some power by putting tuner to sleep */
> > @@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
> >  		}
> >  	}
> >  
> > +exit:
> >  	dev->users--;
> Nice bugfix.
> 
> >  	mutex_unlock(&dev->lock);
> >  	return 0;
> > @@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
> >  
> >  /******************************** usb interface ******************************/
> >  
> > -
> > -
> >  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
> >  					const struct video_device *template,
> >  					const char *type_name)
> > @@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> >  	}
> >  }
> >  
> > -void em28xx_tuner_setup(struct em28xx *dev)
> > +static void em28xx_tuner_setup(struct em28xx *dev)
> >  {
> >  	struct tuner_setup           tun_setup;
> >  	struct v4l2_frequency        f;
> > @@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
> >  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> >  }
> >  
> > -int em28xx_register_analog_devices(struct em28xx *dev)
> > +static int em28xx_v4l2_init(struct em28xx *dev)
> >  {
> >  	u8 val;
> >  	int ret;
> >  	unsigned int maxw;
> >  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
> >  
> > -	if (!dev->is_audio_only) {
> > +	if (!dev->has_video) {
> >  		/* This device does not support the v4l2 extension */
> >  		return 0;
> >  	}
> > @@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> >  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
> >  		dev->name, EM28XX_VERSION);
> >  
> > +	mutex_lock(&dev->lock);
> > +
> >  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> >  	if (ret < 0) {
> >  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> > @@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> >  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> >  		       EM28XX_VINCTRL_CCIR656_ENABLE;
> >  
> > +	/* Initialize tuner and camera */
> > +	em28xx_tuner_setup(dev);
> > +	em28xx_init_camera(dev);
> > +
> >  	/* Configure audio */
> >  	ret = em28xx_audio_setup(dev);
> >  	if (ret < 0) {
> > @@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> >  
> >  	/* initialize videobuf2 stuff */
> >  	em28xx_vb2_setup(dev);
> > +
> >  err:
> > -	return 0;
> > +	mutex_unlock(&dev->lock);
> > +	return ret;
> > +}
> > +
> > +static struct em28xx_ops v4l2_ops = {
> > +	.id   = EM28XX_V4L2,
> > +	.name = "Em28xx v4l2 Extension",
> > +	.init = em28xx_v4l2_init,
> > +	.fini = em28xx_v4l2_fini,
> > +};
> > +
> > +static int __init em28xx_video_register(void)
> > +{
> > +	return em28xx_register_extension(&v4l2_ops);
> >  }
> > +
> > +static void __exit em28xx_video_unregister(void)
> > +{
> > +	em28xx_unregister_extension(&v4l2_ops);
> > +}
> > +
> > +module_init(em28xx_video_register);
> > +module_exit(em28xx_video_unregister);
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index 7ae05ebc13c1..9d6f43e4681f 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -26,7 +26,7 @@
> >  #ifndef _EM28XX_H
> >  #define _EM28XX_H
> >  
> > -#define EM28XX_VERSION "0.2.0"
> > +#define EM28XX_VERSION "0.2.1"
> >  
> >  #include <linux/workqueue.h>
> >  #include <linux/i2c.h>
> > @@ -474,6 +474,7 @@ struct em28xx_eeprom {
> >  #define EM28XX_AUDIO   0x10
> >  #define EM28XX_DVB     0x20
> >  #define EM28XX_RC      0x30
> > +#define EM28XX_V4L2    0x40
> >  
> >  /* em28xx resource types (used for res_get/res_lock etc */
> >  #define EM28XX_RESOURCE_VIDEO 0x01
> > @@ -527,6 +528,7 @@ struct em28xx {
> >  
> >  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
> >  	unsigned char disconnected:1;	/* device has been diconnected */
> > +	unsigned int has_video:1;
> >  	unsigned int has_audio_class:1;
> >  	unsigned int has_alsa_audio:1;
> >  	unsigned int is_audio_only:1;
> > @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
> >  int em28xx_audio_analog_set(struct em28xx *dev);
> >  int em28xx_audio_setup(struct em28xx *dev);
> >  
> > -int em28xx_colorlevels_set_default(struct em28xx *dev);
> >  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
> >  					 enum em28xx_led_role role);
> >  int em28xx_capture_start(struct em28xx *dev, int start);
> > -int em28xx_vbi_supported(struct em28xx *dev);
> > -int em28xx_set_outfmt(struct em28xx *dev);
> > -int em28xx_resolution_set(struct em28xx *dev);
> > -int em28xx_set_alternate(struct em28xx *dev);
> >  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
> >  		      int num_bufs, int max_pkt_size, int packet_multiplier);
> >  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
> > @@ -742,31 +739,17 @@ 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);
> > -void em28xx_wake_i2c(struct em28xx *dev);
> >  int em28xx_register_extension(struct em28xx_ops *dev);
> >  void em28xx_unregister_extension(struct em28xx_ops *dev);
> >  void em28xx_init_extension(struct em28xx *dev);
> >  void em28xx_close_extension(struct em28xx *dev);
> >  
> > -/* Provided by em28xx-video.c */
> > -void em28xx_tuner_setup(struct em28xx *dev);
> > -int em28xx_vb2_setup(struct em28xx *dev);
> > -int em28xx_register_analog_devices(struct em28xx *dev);
> > -void em28xx_release_analog_resources(struct em28xx *dev);
> > -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
> > -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> > -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> > -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
> > -
> >  /* Provided by em28xx-cards.c */
> >  extern 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_release_resources(struct em28xx *dev);
> >  
> > -/* Provided by em28xx-vbi.c */
> > -extern struct vb2_ops em28xx_vbi_qops;
> > -
> >  /* Provided by em28xx-camera.c */
> >  int em28xx_detect_sensor(struct em28xx *dev);
> >  int em28xx_init_camera(struct em28xx *dev);
> Nice clean-up ! :)

Thanks!

-- 

Cheers,
Mauro

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

* Re: [PATCH v4 06/22] [media] em28xx: add warn messages for timeout
  2014-01-05 10:51   ` Frank Schäfer
@ 2014-01-05 13:05     ` Mauro Carvalho Chehab
  2014-01-05 13:25     ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:05 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:51:44 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > changeset 45f04e82d035 added a logic to check if em28xx got
> > a timeout on an I2C transfer.
> >
> > That patch started to produce a series of errors that is present
> > with HVR-950, like:
> >
> > [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
> >
> > However, as there are several places where -ENODEV is produced,
> > there's no way to know what's happening.
> >
> > So, let's add a printk to report what error condition was reached:
> >
> > [ 4032.218652] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> > [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
> >
> > Interesting enough, when connected to an USB3 port, the number of
> > errors increase:
> >
> > [ 4249.941375] em2882/3 #0: I2C transfer timeout on writing to addr 0xb8
> > [ 4249.941378] tvp5150 19-005c: i2c i/o error: rc == -19 (should be 2)
> > [ 4250.023854] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> > [ 4250.023857] xc2028 19-0061: Error on line 1299: -19
> >
> > Due to that, I suspect that the logic in the driver is wrong: instead
> > of just returning an error if 0x10 is returned, it should be waiting for
> > a while and read the I2C status register again.
> >
> > However, more tests are needed.
> The patch description isn't up-to-date.
> It turned out that the bug is in the xc2028 driver.
> 
> See
> http://www.spinics.net/lists/linux-media/msg71107.html
> 
> >
> > For now, instead of just returning -ENODEV, output an error message
> > to help debug what's happening.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-i2c.c | 12 ++++++++++--
> >  1 file changed, 10 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> > index c4ff9739a7ae..9e6a11d01858 100644
> > --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> > +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> > @@ -80,6 +80,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  		if (ret == 0x80 + len - 1) {
> >  			return len;
> >  		} else if (ret == 0x94 + len - 1) {
> > +			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> >  			return -ENODEV;
> >  		} else if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > @@ -123,6 +124,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  		if (ret == 0x84 + len - 1) {
> >  			break;
> >  		} else if (ret == 0x94 + len - 1) {
> > +			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> >  			return -ENODEV;
> >  		} else if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > @@ -198,6 +200,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		if (ret == 0) { /* success */
> >  			return len;
> >  		} else if (ret == 0x10) {
> > +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
> >  			return -ENODEV;
> >  		} else if (ret < 0) {
> >  			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> > @@ -255,6 +258,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >  	}
> >  	if (ret > 0) {
> >  		if (ret == 0x10) {
> > +			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> >  			return -ENODEV;
> >  		} else {
> >  			em28xx_warn("unknown i2c error (status=%i)\n", ret);
> > @@ -316,8 +320,10 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  	 */
> >  	if (!ret)
> >  		return len;
> > -	else if (ret > 0)
> > +	else if (ret > 0) {
> > +		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> >  		return -ENODEV;
> > +	}
> >  
> >  	return ret;
> >  	/*
> > @@ -367,8 +373,10 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  	 */
> >  	if (!ret)
> >  		return len;
> > -	else if (ret > 0)
> > +	else if (ret > 0) {
> > +		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> >  		return -ENODEV;
> > +	}
> >  
> >  	return ret;
> >  	/*
> NACK.
> This will spam the system log on i2c device probing (especially with
> sensors).

A driver returning -ENODEV should really have a log explaining what
happened with the device.

Anyway, see changeset 19/22. 

This is part of a changeset that cleanups the I2C return code and 
printk mess.

After changeset 19/22, the timeout messages will be displayed only
if debug is enabled, and it will return the proper error code for
I2C I/O errors, as described at I2C Documentation/.

Regards,
Mauro

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

* Re: [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-05 10:55   ` Frank Schäfer
@ 2014-01-05 13:08     ` Mauro Carvalho Chehab
  2014-01-05 15:31       ` Mauro Carvalho Chehab
  2014-01-06 17:44       ` Frank Schäfer
  0 siblings, 2 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:08 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:55:34 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Add a message with consistent prints before and after each
> > extension initialization, and provide a better text for module
> > load.
> >
> > While here, add a missing sanity check for extension finish
> > code at em28xx-v4l extension.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
> >  drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
> >  drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
> >  drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
> >  drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
> >  5 files changed, 20 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > index 2fdb66ee44ab..263886adcf26 100644
> > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > @@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >  		return 0;
> >  	}
> >  
> > -	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
> > +	em28xx_info("Binding audio extension\n");
> > +
> >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >  			 "Rechberger\n");
> >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> > @@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
> >  	adev->sndcard = card;
> >  	adev->udev = dev->udev;
> >  
> > +	em28xx_info("Audio extension successfully initialized\n");
> >  	return 0;
> >  }
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > index 1113d4e107d8..33cf26e106b5 100644
> > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > @@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
> >  		ops->init(dev);
> >  	}
> >  	mutex_unlock(&em28xx_devlist_mutex);
> > -	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
> > +	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
> >  	return 0;
> >  }
> >  EXPORT_SYMBOL(em28xx_register_extension);
> > diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> > index ddc0e609065d..f72663a9b5c5 100644
> > --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> > +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> > @@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
> >  static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
> >  {
> >  	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
> > -        struct em28xx *dev = i2c_bus->dev;
> > +	struct em28xx *dev = i2c_bus->dev;
> >  
> >  	if (acquire)
> >  		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
> > @@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >  
> >  	if (!dev->board.has_dvb) {
> >  		/* This device does not support the extension */
> > -		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
> >  		return 0;
> >  	}
> >  
> > +	em28xx_info("Binding DVB extension\n");
> > +
> >  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> >  
> >  	if (dvb == NULL) {
> > @@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >  	/* MFE lock */
> >  	dvb->adapter.mfe_shared = mfe_shared;
> >  
> > -	em28xx_info("Successfully loaded em28xx-dvb\n");
> > +	em28xx_info("DVB extension successfully initialized\n");
> >  ret:
> >  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >  	mutex_unlock(&dev->lock);
> > diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> > index 93a7d02b9cb4..eed7dd79f734 100644
> > --- a/drivers/media/usb/em28xx/em28xx-input.c
> > +++ b/drivers/media/usb/em28xx/em28xx-input.c
> > @@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >  		return 0;
> >  	}
> >  
> > +	em28xx_info("Registering input extension\n");
> > +
> >  	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
> >  	rc = rc_allocate_device();
> >  	if (!ir || !rc)
> > @@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >  	if (err)
> >  		goto error;
> >  
> > +	em28xx_info("Input extension successfully initalized\n");
> > +
> >  	return 0;
> >  
> >  error:
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index 56d1b46164a0..b767262c642b 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >  
> >  	/*FIXME: I2C IR should be disconnected */
> >  
> > +	if (!dev->has_video) {
> > +		/* This device does not support the v4l2 extension */
> > +		return 0;
> > +	}
> > +
> That's a separate change and AFAICS it's not needed.

It is needed. If you plug a device with video first and then a DVB-only device,
as em28xx-v4l will be loaded, it will initialize the extension, if this code got
removed.

I can move it to a separate patch adding the proper description.

> >  	if (dev->radio_dev) {
> >  		if (video_is_registered(dev->radio_dev))
> >  			video_unregister_device(dev->radio_dev);
> > @@ -2215,8 +2220,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >  		return 0;
> >  	}
> >  
> > -	printk(KERN_INFO "%s: v4l2 driver version %s\n",
> > -		dev->name, EM28XX_VERSION);
> > +	em28xx_info("Registering V4L2 extension\n");
> >  
> >  	mutex_lock(&dev->lock);
> >  
> > @@ -2498,6 +2502,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >  	/* initialize videobuf2 stuff */
> >  	em28xx_vb2_setup(dev);
> >  
> > +	em28xx_info("V4L2 extension successfully initialized\n");
> > +
> >  err:
> >  	mutex_unlock(&dev->lock);
> >  	return ret;
> 


-- 

Cheers,
Mauro

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

* Re: [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies
  2014-01-05 11:03   ` Frank Schäfer
@ 2014-01-05 13:10     ` Mauro Carvalho Chehab
  2014-01-06 17:48       ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:10 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 12:03:51 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > The I2C wait completion/timeout logic currently assumes that
> > msleep(5) will wait exaclty 5 ms. This is not true at all,
> > as it depends on CONFIG_HZ.
> >
> > Convert it to use jiffies, in order to not wait for more time
> > than needed.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-i2c.c | 65 ++++++++++++++++++-----------------
> >  1 file changed, 34 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> > index 9e6a11d01858..9fa7ed51e5b1 100644
> > --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> > +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> > @@ -26,6 +26,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/usb.h>
> >  #include <linux/i2c.h>
> > +#include <linux/jiffies.h>
> >  
> >  #include "em28xx.h"
> >  #include "tuner-xc2028.h"
> > @@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
> >   */
> >  static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  {
> > +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
> >  	int ret;
> > -	int write_timeout;
> >  	u8 b2[6];
> >  
> >  	if (len < 1 || len > 4)
> > @@ -74,15 +75,15 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  		return (ret < 0) ? ret : -EIO;
> >  	}
> >  	/* wait for completion */
> > -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
> > -	     write_timeout -= 5) {
> > +	while (time_is_after_jiffies(timeout)) {
> AFAIU, it must be time_is_before_jiffies(timeout).

This is tricky, but it is right. 

See its description at jiffies.h:

	/* time_is_after_jiffies(a) return true if a is after jiffies */
	#define time_is_after_jiffies(a) time_before(jiffies, a)

> 
> >  		ret = dev->em28xx_read_reg(dev, 0x05);
> > -		if (ret == 0x80 + len - 1) {
> > +		if (ret == 0x80 + len - 1)
> >  			return len;
> > -		} else if (ret == 0x94 + len - 1) {
> > +		if (ret == 0x94 + len - 1) {
> >  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> >  			return -ENODEV;
> > -		} else if (ret < 0) {
> > +		}
> > +		if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> >  				    ret);
> >  			return ret;
> > @@ -99,9 +100,9 @@ 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(EM2800_I2C_XFER_TIMEOUT);
> >  	u8 buf2[4];
> >  	int ret;
> > -	int read_timeout;
> >  	int i;
> >  
> >  	if (len < 1 || len > 4)
> > @@ -118,15 +119,15 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  	}
> >  
> >  	/* wait for completion */
> > -	for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
> > -	     read_timeout -= 5) {
> > +	while (time_is_after_jiffies(timeout)) {
> The same here...
> 
> >  		ret = dev->em28xx_read_reg(dev, 0x05);
> > -		if (ret == 0x84 + len - 1) {
> > +		if (ret == 0x84 + len - 1)
> >  			break;
> > -		} else if (ret == 0x94 + len - 1) {
> > +		if (ret == 0x94 + len - 1) {
> >  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> >  			return -ENODEV;
> > -		} else if (ret < 0) {
> > +		}
> > +		if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> >  				    ret);
> >  			return ret;
> > @@ -170,7 +171,8 @@ 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)
> >  {
> > -	int write_timeout, ret;
> > +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
> > +	int ret;
> >  
> >  	if (len < 1 || len > 64)
> >  		return -EOPNOTSUPP;
> > @@ -193,17 +195,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		}
> >  	}
> >  
> > -	/* Check success of the i2c operation */
> > -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
> > -	     write_timeout -= 5) {
> > +	/* wait for completion */
> > +	while (time_is_after_jiffies(timeout)) {
> ... and here.
> 
> >  		ret = dev->em28xx_read_reg(dev, 0x05);
> > -		if (ret == 0) { /* success */
> > +		if (ret == 0) /* success */
> >  			return len;
> > -		} else if (ret == 0x10) {
> > -			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
> > +		if (ret == 0x10) {
> > +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
> > +				    addr);
> >  			return -ENODEV;
> > -		} else if (ret < 0) {
> > -			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> > +		}
> > +		if (ret < 0) {
> > +			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> >  				    ret);
> >  			return ret;
> >  		}
> > @@ -214,6 +217,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		 * (even with high payload) ...
> >  		 */
> >  	}
> > +
> >  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> >  	return -EIO;
> >  }
> > @@ -251,21 +255,20 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >  
> >  	/* Check success of the i2c operation */
> >  	ret = dev->em28xx_read_reg(dev, 0x05);
> > +	if (ret == 0) /* success */
> > +		return len;
> >  	if (ret < 0) {
> > -		em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
> > +		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> >  			    ret);
> >  		return ret;
> >  	}
> > -	if (ret > 0) {
> > -		if (ret == 0x10) {
> > -			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> > -			return -ENODEV;
> > -		} else {
> > -			em28xx_warn("unknown i2c error (status=%i)\n", ret);
> > -			return -EIO;
> > -		}
> > +	if (ret == 0x10) {
> > +		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> > +		return -ENODEV;
> >  	}
> > -	return len;
> > +
> > +	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> > +	return -EIO;
> >  }
> >  
> >  /*
> 


-- 

Cheers,
Mauro

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

* Re: [PATCH v4 13/22] [media] em28xx: initialize audio latter
  2014-01-05 11:29   ` Frank Schäfer
@ 2014-01-05 13:17     ` Mauro Carvalho Chehab
  2014-01-07 17:00       ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:17 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 12:29:11 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Better to first write the GPIOs of the input mux, before initializing
> > the audio.
> Why are you making this change ?
> 
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-video.c | 40 ++++++++++++++++-----------------
> >  1 file changed, 20 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index b767262c642b..328d724a13ea 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -2291,26 +2291,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >  	em28xx_tuner_setup(dev);
> >  	em28xx_init_camera(dev);
> >  
> > -	/* Configure audio */
> > -	ret = em28xx_audio_setup(dev);
> > -	if (ret < 0) {
> > -		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> > -			__func__, ret);
> > -		goto err;
> > -	}
> > -	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> > -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> > -			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> > -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> > -			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> > -	} else {
> > -		/* install the em28xx notify callback */
> > -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> > -				em28xx_ctrl_notify, dev);
> > -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> > -				em28xx_ctrl_notify, dev);
> > -	}
> > -
> >  	/* wake i2c devices */
> >  	em28xx_wake_i2c(dev);
> >  
> > @@ -2356,6 +2336,26 @@ static int em28xx_v4l2_init(struct em28xx *dev)
> >  
> >  	video_mux(dev, 0);
> >  
> > +	/* Configure audio */
> > +	ret = em28xx_audio_setup(dev);
> > +	if (ret < 0) {
> > +		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> > +			__func__, ret);
> > +		goto err;
> > +	}
> > +	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> > +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> > +			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> > +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> > +			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> > +	} else {
> > +		/* install the em28xx notify callback */
> > +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> > +				em28xx_ctrl_notify, dev);
> > +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> > +				em28xx_ctrl_notify, dev);
> > +	}
> > +
> >  	/* Audio defaults */
> >  	dev->mute = 1;
> >  	dev->volume = 0x1f;
> Well, the v4l/core split didn't change the order.
> And if the current order would be wrong, then you would also have to
> call audio_setup() each time the user switches the input.

Maybe this is needed anyway. Btw, there's a bug on xawtv: if you maximize
a window, audio stops playing. I didn't have time yet to identify why.

> So unless you are trying to fix a real bug, I wouldn't change it.
> The current order is sane and we likely could never change it back later
> without risking regressions...

Sometimes, ac97 is not properly detected here with HVR-950. Not sure
what happens. I need to do more tests. Perhaps it happens only on USB 3.0
ports.

In any case, it makes sense to first wake up I2C devices, then to set
the video mux, before start probing for audio, as the audio setting
may depend on the video mux settings.

-- 

Cheers,
Mauro

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

* Re: [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code
  2014-01-05 11:19   ` Frank Schäfer
@ 2014-01-05 13:20     ` Mauro Carvalho Chehab
  2014-01-05 15:44       ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:20 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 12:19:41 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Instead of assuming that msleep() is precise, use a jiffies
> > based code to wait for AC97 to be available.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-core.c | 7 +++++--
> >  drivers/media/usb/em28xx/em28xx.h      | 5 ++++-
> >  2 files changed, 9 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > index 818248d3fd28..36b2f1ab4474 100644
> > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > @@ -23,6 +23,7 @@
> >   */
> >  
> >  #include <linux/init.h>
> > +#include <linux/jiffies.h>
> >  #include <linux/list.h>
> >  #include <linux/module.h>
> >  #include <linux/slab.h>
> > @@ -254,16 +255,18 @@ EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
> >   */
> >  static int em28xx_is_ac97_ready(struct em28xx *dev)
> >  {
> > -	int ret, i;
> > +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_AC97_XFER_TIMEOUT);
> > +	int ret;
> >  
> >  	/* Wait up to 50 ms for AC97 command to complete */
> > -	for (i = 0; i < 10; i++, msleep(5)) {
> > +	while (time_is_after_jiffies(timeout)) {
> time_is_before_jiffies(timeout)
> 
> >  		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
> >  		if (ret < 0)
> >  			return ret;
> >  
> >  		if (!(ret & 0x01))
> >  			return 0;
> > +		msleep (5);
> >  	}
> >  
> >  	em28xx_warn("AC97 command still being executed: not handled properly!\n");
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index 9d6f43e4681f..ac79501f5d9f 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -182,9 +182,12 @@
> >  
> >  #define EM28XX_INTERLACED_DEFAULT 1
> >  
> > -/* time in msecs to wait for i2c writes to finish */
> > +/* time in msecs to wait for i2c xfers to finish */
> >  #define EM2800_I2C_XFER_TIMEOUT		20
> >  
> > +/* time in msecs to wait for AC97 xfers to finish */
> > +#define EM2800_AC97_XFER_TIMEOUT	100
> > +
> I applies to all chips supporting AC97 audio, so call it
> EM28XX_AC97_XFER_TIMEOUT.

Ok.

> Why did you increase the timeout from 50ms to 100ms ?
> 50ms already seems to be a lot !
> 
> IIRC, the problem you are trying to fix is that the chip sometimes is
> not yet ready when probing.

Yes. I was also hoping that would make the code more reliable, as
there are some issues with audio here (with usb 3.0 and with xawtv
when trying to maximize the window).

> But that should be solved with a single sleep before accessing the AC97
> chip for the first time instead ?!

Maybe. I'll try it.

> >  /* max. number of button state polling addresses */
> >  #define EM28XX_NUM_BUTTON_ADDRESSES_MAX		5
> >  
> 


-- 

Cheers,
Mauro

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

* Re: [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier
  2014-01-05 11:12   ` Frank Schäfer
@ 2014-01-05 13:22     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:22 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 12:12:34 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Better to split chipset detection from the audio setup. So, move the
> > detection code to em28xx_init_dev().
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-cards.c | 11 +++++++++++
> >  drivers/media/usb/em28xx/em28xx-core.c  | 12 +-----------
> >  2 files changed, 12 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index d1c75e66554c..4fe742429f2c 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2930,6 +2930,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  		}
> >  	}
> >  
> > +	if (dev->chip_id == CHIP_ID_EM2870 ||
> > +	    dev->chip_id == CHIP_ID_EM2874 ||
> > +	    dev->chip_id == CHIP_ID_EM28174 ||
> > +	    dev->chip_id == CHIP_ID_EM28178) {
> > +		/* Digital only device - don't load any alsa module */
> > +		dev->audio_mode.has_audio = false;
> > +		dev->has_audio_class = false;
> > +		dev->has_alsa_audio = false;
> > +	}
> > +
> >  	if (chip_name != default_chip_name)
> >  		printk(KERN_INFO DRIVER_NAME
> >  		       ": chip ID is %s\n", chip_name);
> > @@ -3196,6 +3206,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> >  	dev->alt   = -1;
> >  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
> >  	dev->has_alsa_audio = has_audio;
> > +	dev->audio_mode.has_audio = has_audio;
> >  	dev->has_video = has_video;
> >  	dev->audio_ifnum = ifnum;
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > index 33cf26e106b5..818248d3fd28 100644
> > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > @@ -505,18 +505,8 @@ int em28xx_audio_setup(struct em28xx *dev)
> >  	int vid1, vid2, feat, cfg;
> >  	u32 vid;
> >  
> > -	if (dev->chip_id == CHIP_ID_EM2870 ||
> > -	    dev->chip_id == CHIP_ID_EM2874 ||
> > -	    dev->chip_id == CHIP_ID_EM28174 ||
> > -	    dev->chip_id == CHIP_ID_EM28178) {
> > -		/* Digital only device - don't load any alsa module */
> > -		dev->audio_mode.has_audio = false;
> > -		dev->has_audio_class = false;
> > -		dev->has_alsa_audio = false;
> > +	if (!dev->audio_mode.has_audio)
> >  		return 0;
> > -	}
> > -
> > -	dev->audio_mode.has_audio = true;
> >  
> >  	/* See how this device is configured */
> >  	cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
> It's not clear to me how one of these audio variables could ever become
> true with these chip types, so this code should probably just be removed.

Maybe. This is part of a quick hack that added support for em2874.
Assuming that the em28xx USB descriptors are ok, the code is not needed.

However, as I'm not 100% sure about that (maybe ancient chips might have
some bugs), I opted to just move the code to be together with the other
detection code, instead of removing and risking a regression.

-- 

Cheers,
Mauro

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

* Re: [PATCH v4 06/22] [media] em28xx: add warn messages for timeout
  2014-01-05 10:51   ` Frank Schäfer
  2014-01-05 13:05     ` Mauro Carvalho Chehab
@ 2014-01-05 13:25     ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:25 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:51:44 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > changeset 45f04e82d035 added a logic to check if em28xx got
> > a timeout on an I2C transfer.
> >
> > That patch started to produce a series of errors that is present
> > with HVR-950, like:
> >
> > [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
> >
> > However, as there are several places where -ENODEV is produced,
> > there's no way to know what's happening.
> >
> > So, let's add a printk to report what error condition was reached:
> >
> > [ 4032.218652] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> > [ 4032.218656] xc2028 19-0061: Error on line 1299: -19
> >
> > Interesting enough, when connected to an USB3 port, the number of
> > errors increase:
> >
> > [ 4249.941375] em2882/3 #0: I2C transfer timeout on writing to addr 0xb8
> > [ 4249.941378] tvp5150 19-005c: i2c i/o error: rc == -19 (should be 2)
> > [ 4250.023854] em2882/3 #0: I2C transfer timeout on writing to addr 0xc2
> > [ 4250.023857] xc2028 19-0061: Error on line 1299: -19
> >
> > Due to that, I suspect that the logic in the driver is wrong: instead
> > of just returning an error if 0x10 is returned, it should be waiting for
> > a while and read the I2C status register again.
> >
> > However, more tests are needed.
> The patch description isn't up-to-date.
> It turned out that the bug is in the xc2028 driver.
> 
> See
> http://www.spinics.net/lists/linux-media/msg71107.html

In time, I'll update the description.

I'll work on the xc2028 driver to fix it. It seems better than applying
a hack there. I prefer to not remove the code that puts it in power down
mode, as some em28xx devices are known to have power heat problems.

So, keeping xc3028 energized can reduce a lot its lifetime on such
devices.

Regards,
Mauro

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

* Re: [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video
  2014-01-05 10:11   ` Frank Schäfer
@ 2014-01-05 13:28     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 13:28 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:11:20 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > Now that we want to split the video handling to a separate
> > module, move all video-specific functions to em28xx-video.
> >
> > No functional changes.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-cards.c | 107 ---------
> >  drivers/media/usb/em28xx/em28xx-core.c  | 259 ----------------------
> >  drivers/media/usb/em28xx/em28xx-video.c | 374 +++++++++++++++++++++++++++++++-
> >  drivers/media/usb/em28xx/em28xx.h       |   1 +
> >  4 files changed, 371 insertions(+), 370 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index 36853f16bf97..19827e79cf53 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2529,113 +2529,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
> >  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >  }
> >  
> > -static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> > -{
> > -	memset(ctl, 0, sizeof(*ctl));
> > -
> > -	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
> > -	ctl->max_len = 64;
> > -	ctl->mts = em28xx_boards[dev->model].mts_firmware;
> > -
> > -	switch (dev->model) {
> > -	case EM2880_BOARD_EMPIRE_DUAL_TV:
> > -	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
> > -	case EM2882_BOARD_TERRATEC_HYBRID_XS:
> > -		ctl->demod = XC3028_FE_ZARLINK456;
> > -		break;
> > -	case EM2880_BOARD_TERRATEC_HYBRID_XS:
> > -	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
> > -	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
> > -		ctl->demod = XC3028_FE_ZARLINK456;
> > -		break;
> > -	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
> > -	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
> > -		ctl->demod = XC3028_FE_DEFAULT;
> > -		break;
> > -	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
> > -		ctl->demod = XC3028_FE_DEFAULT;
> > -		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> > -		break;
> > -	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
> > -	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
> > -	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
> > -		/* FIXME: Better to specify the needed IF */
> > -		ctl->demod = XC3028_FE_DEFAULT;
> > -		break;
> > -	case EM2883_BOARD_KWORLD_HYBRID_330U:
> > -	case EM2882_BOARD_DIKOM_DK300:
> > -	case EM2882_BOARD_KWORLD_VS_DVBT:
> > -		ctl->demod = XC3028_FE_CHINA;
> > -		ctl->fname = XC2028_DEFAULT_FIRMWARE;
> > -		break;
> > -	case EM2882_BOARD_EVGA_INDTUBE:
> > -		ctl->demod = XC3028_FE_CHINA;
> > -		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> > -		break;
> > -	default:
> > -		ctl->demod = XC3028_FE_OREN538;
> > -	}
> > -}
> > -
> > -static void em28xx_tuner_setup(struct em28xx *dev)
> > -{
> > -	struct tuner_setup           tun_setup;
> > -	struct v4l2_frequency        f;
> > -
> > -	if (dev->tuner_type == TUNER_ABSENT)
> > -		return;
> > -
> > -	memset(&tun_setup, 0, sizeof(tun_setup));
> > -
> > -	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
> > -	tun_setup.tuner_callback = em28xx_tuner_callback;
> > -
> > -	if (dev->board.radio.type) {
> > -		tun_setup.type = dev->board.radio.type;
> > -		tun_setup.addr = dev->board.radio_addr;
> > -
> > -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> > -	}
> > -
> > -	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
> > -		tun_setup.type   = dev->tuner_type;
> > -		tun_setup.addr   = dev->tuner_addr;
> > -
> > -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> > -	}
> > -
> > -	if (dev->tda9887_conf) {
> > -		struct v4l2_priv_tun_config tda9887_cfg;
> > -
> > -		tda9887_cfg.tuner = TUNER_TDA9887;
> > -		tda9887_cfg.priv = &dev->tda9887_conf;
> > -
> > -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
> > -	}
> > -
> > -	if (dev->tuner_type == TUNER_XC2028) {
> > -		struct v4l2_priv_tun_config  xc2028_cfg;
> > -		struct xc2028_ctrl           ctl;
> > -
> > -		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
> > -		memset(&ctl, 0, sizeof(ctl));
> > -
> > -		em28xx_setup_xc3028(dev, &ctl);
> > -
> > -		xc2028_cfg.tuner = TUNER_XC2028;
> > -		xc2028_cfg.priv  = &ctl;
> > -
> > -		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
> > -	}
> > -
> > -	/* configure tuner */
> > -	f.tuner = 0;
> > -	f.type = V4L2_TUNER_ANALOG_TV;
> > -	f.frequency = 9076;     /* just a magic number */
> > -	dev->ctl_freq = f.frequency;
> > -	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> > -}
> > -
> >  static int em28xx_hint_board(struct em28xx *dev)
> >  {
> >  	int i;
> > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > index f6076a512e8f..3012912d2997 100644
> > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > @@ -53,14 +53,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
> >  		printk(KERN_INFO "%s %s :"fmt, \
> >  			 dev->name, __func__ , ##arg); } while (0)
> >  
> > -static int alt;
> > -module_param(alt, int, 0644);
> > -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
> > -
> > -static unsigned int disable_vbi;
> > -module_param(disable_vbi, int, 0644);
> > -MODULE_PARM_DESC(disable_vbi, "disable vbi support");
> > -
> >  /* FIXME */
> >  #define em28xx_isocdbg(fmt, arg...) do {\
> >  	if (core_debug) \
> > @@ -603,24 +595,6 @@ init_audio:
> >  }
> >  EXPORT_SYMBOL_GPL(em28xx_audio_setup);
> >  
> > -int em28xx_colorlevels_set_default(struct em28xx *dev)
> > -{
> > -	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> > -	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> > -	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
> > -	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
> > -	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
> > -	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
> > -
> > -	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
> > -	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
> > -	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
> > -	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
> > -	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
> > -	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
> > -	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> > -}
> > -
> >  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
> >  					 enum em28xx_led_role role)
> >  {
> > @@ -696,227 +670,6 @@ int em28xx_capture_start(struct em28xx *dev, int start)
> >  	return rc;
> >  }
> >  
> > -int em28xx_vbi_supported(struct em28xx *dev)
> > -{
> > -	/* Modprobe option to manually disable */
> > -	if (disable_vbi == 1)
> > -		return 0;
> > -
> > -	if (dev->board.is_webcam)
> > -		return 0;
> > -
> > -	/* FIXME: check subdevices for VBI support */
> > -
> > -	if (dev->chip_id == CHIP_ID_EM2860 ||
> > -	    dev->chip_id == CHIP_ID_EM2883)
> > -		return 1;
> > -
> > -	/* Version of em28xx that does not support VBI */
> > -	return 0;
> > -}
> > -
> > -int em28xx_set_outfmt(struct em28xx *dev)
> > -{
> > -	int ret;
> > -	u8 fmt, vinctrl;
> > -
> > -	fmt = dev->format->reg;
> > -	if (!dev->is_em25xx)
> > -		fmt |= 0x20;
> > -	/*
> > -	 * NOTE: it's not clear if this is really needed !
> > -	 * The datasheets say bit 5 is a reserved bit and devices seem to work
> > -	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
> > -	 * devices and we've always been setting it, too.
> > -	 *
> > -	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
> > -	 * it's likely used for an additional (compressed ?) format there.
> > -	 */
> > -	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	vinctrl = dev->vinctl;
> > -	if (em28xx_vbi_supported(dev) == 1) {
> > -		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
> > -		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
> > -		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
> > -		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
> > -		if (dev->norm & V4L2_STD_525_60) {
> > -			/* NTSC */
> > -			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
> > -		} else if (dev->norm & V4L2_STD_625_50) {
> > -			/* PAL */
> > -			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
> > -		}
> > -	}
> > -
> > -	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
> > -}
> > -
> > -static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
> > -				  u8 ymin, u8 ymax)
> > -{
> > -	em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
> > -			xmin, ymin, xmax, ymax);
> > -
> > -	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
> > -	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
> > -	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
> > -	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
> > -}
> > -
> > -static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
> > -				   u16 width, u16 height)
> > -{
> > -	u8 cwidth = width >> 2;
> > -	u8 cheight = height >> 2;
> > -	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
> > -	/* NOTE: size limit: 2047x1023 = 2MPix */
> > -
> > -	em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
> > -		       hstart, vstart,
> > -		       ((overflow & 2) << 9 | cwidth << 2),
> > -		       ((overflow & 1) << 10 | cheight << 2));
> > -
> > -	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
> > -	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
> > -	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
> > -	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
> > -	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
> > -
> > -	/* FIXME: function/meaning of these registers ? */
> > -	/* FIXME: align width+height to multiples of 4 ?! */
> > -	if (dev->is_em25xx) {
> > -		em28xx_write_reg(dev, 0x34, width >> 4);
> > -		em28xx_write_reg(dev, 0x35, height >> 4);
> > -	}
> > -}
> > -
> > -static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> > -{
> > -	u8 mode;
> > -	/* the em2800 scaler only supports scaling down to 50% */
> > -
> > -	if (dev->board.is_em2800) {
> > -		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
> > -	} else {
> > -		u8 buf[2];
> > -
> > -		buf[0] = h;
> > -		buf[1] = h >> 8;
> > -		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
> > -
> > -		buf[0] = v;
> > -		buf[1] = v >> 8;
> > -		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
> > -		/* it seems that both H and V scalers must be active
> > -		   to work correctly */
> > -		mode = (h || v) ? 0x30 : 0x00;
> > -	}
> > -	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
> > -}
> > -
> > -/* FIXME: this only function read values from dev */
> > -int em28xx_resolution_set(struct em28xx *dev)
> > -{
> > -	int width, height;
> > -	width = norm_maxw(dev);
> > -	height = norm_maxh(dev);
> > -
> > -	/* Properly setup VBI */
> > -	dev->vbi_width = 720;
> > -	if (dev->norm & V4L2_STD_525_60)
> > -		dev->vbi_height = 12;
> > -	else
> > -		dev->vbi_height = 18;
> > -
> > -	em28xx_set_outfmt(dev);
> > -
> > -	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
> > -
> > -	/* If we don't set the start position to 2 in VBI mode, we end up
> > -	   with line 20/21 being YUYV encoded instead of being in 8-bit
> > -	   greyscale.  The core of the issue is that line 21 (and line 23 for
> > -	   PAL WSS) are inside of active video region, and as a result they
> > -	   get the pixelformatting associated with that area.  So by cropping
> > -	   it out, we end up with the same format as the rest of the VBI
> > -	   region */
> > -	if (em28xx_vbi_supported(dev) == 1)
> > -		em28xx_capture_area_set(dev, 0, 2, width, height);
> > -	else
> > -		em28xx_capture_area_set(dev, 0, 0, width, height);
> > -
> > -	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> > -}
> > -
> > -/* Set USB alternate setting for analog video */
> > -int em28xx_set_alternate(struct em28xx *dev)
> > -{
> > -	int errCode;
> > -	int i;
> > -	unsigned int min_pkt_size = dev->width * 2 + 4;
> > -
> > -	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
> > -		 bulk transfers seem to work only with alt=0 ! */
> > -	dev->alt = 0;
> > -	if ((alt > 0) && (alt < dev->num_alt)) {
> > -		em28xx_coredbg("alternate forced to %d\n", dev->alt);
> > -		dev->alt = alt;
> > -		goto set_alt;
> > -	}
> > -	if (dev->analog_xfer_bulk)
> > -		goto set_alt;
> > -
> > -	/* When image size is bigger than a certain value,
> > -	   the frame size should be increased, otherwise, only
> > -	   green screen will be received.
> > -	 */
> > -	if (dev->width * 2 * dev->height > 720 * 240 * 2)
> > -		min_pkt_size *= 2;
> > -
> > -	for (i = 0; i < dev->num_alt; i++) {
> > -		/* stop when the selected alt setting offers enough bandwidth */
> > -		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
> > -			dev->alt = i;
> > -			break;
> > -		/* otherwise make sure that we end up with the maximum bandwidth
> > -		   because the min_pkt_size equation might be wrong...
> > -		*/
> > -		} else if (dev->alt_max_pkt_size_isoc[i] >
> > -			   dev->alt_max_pkt_size_isoc[dev->alt])
> > -			dev->alt = i;
> > -	}
> > -
> > -set_alt:
> > -	/* NOTE: for bulk transfers, we need to call usb_set_interface()
> > -	 * even if the previous settings were the same. Otherwise streaming
> > -	 * fails with all urbs having status = -EOVERFLOW ! */
> > -	if (dev->analog_xfer_bulk) {
> > -		dev->max_pkt_size = 512; /* USB 2.0 spec */
> > -		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
> > -	} else { /* isoc */
> > -		em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
> > -			       min_pkt_size, dev->alt);
> > -		dev->max_pkt_size =
> > -				  dev->alt_max_pkt_size_isoc[dev->alt];
> > -		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
> > -	}
> > -	em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
> > -		       dev->alt, dev->max_pkt_size);
> > -	errCode = usb_set_interface(dev->udev, 0, dev->alt);
> > -	if (errCode < 0) {
> > -		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
> > -			      dev->alt, errCode);
> > -		return errCode;
> > -	}
> > -	return 0;
> > -}
> > -
> >  int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
> >  {
> >  	int rc = 0;
> > @@ -1282,18 +1035,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
> >  EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
> >  
> >  /*
> > - * em28xx_wake_i2c()
> > - * configure i2c attached devices
> > - */
> > -void em28xx_wake_i2c(struct em28xx *dev)
> > -{
> > -	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> > -	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> > -			INPUT(dev->ctl_input)->vmux, 0, 0);
> > -	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> > -}
> > -
> > -/*
> >   * Device control list
> >   */
> >  
> > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > index dd19c9ff76e0..70ffe259df5b 100644
> > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > @@ -53,15 +53,23 @@
> >  
> >  #define EM28XX_VERSION "0.2.0"
> >  
> > +static unsigned int isoc_debug;
> > +module_param(isoc_debug, int, 0644);
> > +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> > +
> > +static unsigned int disable_vbi;
> > +module_param(disable_vbi, int, 0644);
> > +MODULE_PARM_DESC(disable_vbi, "disable vbi support");
> > +
> > +static int alt;
> > +module_param(alt, int, 0644);
> > +MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
> > +
> >  #define em28xx_videodbg(fmt, arg...) do {\
> >  	if (video_debug) \
> >  		printk(KERN_INFO "%s %s :"fmt, \
> >  			 dev->name, __func__ , ##arg); } while (0)
> >  
> > -static unsigned int isoc_debug;
> > -module_param(isoc_debug, int, 0644);
> > -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
> > -
> >  #define em28xx_isocdbg(fmt, arg...) \
> >  do {\
> >  	if (isoc_debug) { \
> > @@ -135,6 +143,257 @@ static struct em28xx_fmt format[] = {
> >  	},
> >  };
> >  
> > +/*
> > + * em28xx_wake_i2c()
> > + * configure i2c attached devices
> > + */
> > +void em28xx_wake_i2c(struct em28xx *dev)
> > +{
> > +	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> > +	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> > +			INPUT(dev->ctl_input)->vmux, 0, 0);
> > +	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> > +}
> > +
> > +int em28xx_colorlevels_set_default(struct em28xx *dev)
> > +{
> > +	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> > +	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> > +	em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
> > +	em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
> > +	em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
> > +	em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
> > +
> > +	em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
> > +	em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
> > +	em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
> > +	em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
> > +	em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
> > +	em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
> > +	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> > +}
> > +
> > +int em28xx_set_outfmt(struct em28xx *dev)
> > +{
> > +	int ret;
> > +	u8 fmt, vinctrl;
> > +
> > +	fmt = dev->format->reg;
> > +	if (!dev->is_em25xx)
> > +		fmt |= 0x20;
> > +	/*
> > +	 * NOTE: it's not clear if this is really needed !
> > +	 * The datasheets say bit 5 is a reserved bit and devices seem to work
> > +	 * fine without it. But the Windows driver sets it for em2710/50+em28xx
> > +	 * devices and we've always been setting it, too.
> > +	 *
> > +	 * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
> > +	 * it's likely used for an additional (compressed ?) format there.
> > +	 */
> > +	ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	vinctrl = dev->vinctl;
> > +	if (em28xx_vbi_supported(dev) == 1) {
> > +		vinctrl |= EM28XX_VINCTRL_VBI_RAW;
> > +		em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
> > +		em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
> > +		em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
> > +		if (dev->norm & V4L2_STD_525_60) {
> > +			/* NTSC */
> > +			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
> > +		} else if (dev->norm & V4L2_STD_625_50) {
> > +			/* PAL */
> > +			em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
> > +		}
> > +	}
> > +
> > +	return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
> > +}
> > +
> > +static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
> > +				  u8 ymin, u8 ymax)
> > +{
> > +	em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
> > +			xmin, ymin, xmax, ymax);
> > +
> > +	em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
> > +	em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
> > +	em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
> > +	return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
> > +}
> > +
> > +static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
> > +				   u16 width, u16 height)
> > +{
> > +	u8 cwidth = width >> 2;
> > +	u8 cheight = height >> 2;
> > +	u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
> > +	/* NOTE: size limit: 2047x1023 = 2MPix */
> > +
> > +	em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
> > +		       hstart, vstart,
> > +		       ((overflow & 2) << 9 | cwidth << 2),
> > +		       ((overflow & 1) << 10 | cheight << 2));
> > +
> > +	em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
> > +	em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
> > +	em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
> > +	em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
> > +	em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
> > +
> > +	/* FIXME: function/meaning of these registers ? */
> > +	/* FIXME: align width+height to multiples of 4 ?! */
> > +	if (dev->is_em25xx) {
> > +		em28xx_write_reg(dev, 0x34, width >> 4);
> > +		em28xx_write_reg(dev, 0x35, height >> 4);
> > +	}
> > +}
> > +
> > +static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> > +{
> > +	u8 mode;
> > +	/* the em2800 scaler only supports scaling down to 50% */
> > +
> > +	if (dev->board.is_em2800) {
> > +		mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
> > +	} else {
> > +		u8 buf[2];
> > +
> > +		buf[0] = h;
> > +		buf[1] = h >> 8;
> > +		em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
> > +
> > +		buf[0] = v;
> > +		buf[1] = v >> 8;
> > +		em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
> > +		/* it seems that both H and V scalers must be active
> > +		   to work correctly */
> > +		mode = (h || v) ? 0x30 : 0x00;
> > +	}
> > +	return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
> > +}
> > +
> > +/* FIXME: this only function read values from dev */
> > +int em28xx_resolution_set(struct em28xx *dev)
> > +{
> > +	int width, height;
> > +	width = norm_maxw(dev);
> > +	height = norm_maxh(dev);
> > +
> > +	/* Properly setup VBI */
> > +	dev->vbi_width = 720;
> > +	if (dev->norm & V4L2_STD_525_60)
> > +		dev->vbi_height = 12;
> > +	else
> > +		dev->vbi_height = 18;
> > +
> > +	em28xx_set_outfmt(dev);
> > +
> > +	em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
> > +
> > +	/* If we don't set the start position to 2 in VBI mode, we end up
> > +	   with line 20/21 being YUYV encoded instead of being in 8-bit
> > +	   greyscale.  The core of the issue is that line 21 (and line 23 for
> > +	   PAL WSS) are inside of active video region, and as a result they
> > +	   get the pixelformatting associated with that area.  So by cropping
> > +	   it out, we end up with the same format as the rest of the VBI
> > +	   region */
> > +	if (em28xx_vbi_supported(dev) == 1)
> > +		em28xx_capture_area_set(dev, 0, 2, width, height);
> > +	else
> > +		em28xx_capture_area_set(dev, 0, 0, width, height);
> > +
> > +	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> > +}
> > +
> > +int em28xx_vbi_supported(struct em28xx *dev)
> > +{
> > +	/* Modprobe option to manually disable */
> > +	if (disable_vbi == 1)
> > +		return 0;
> > +
> > +	if (dev->board.is_webcam)
> > +		return 0;
> > +
> > +	/* FIXME: check subdevices for VBI support */
> > +
> > +	if (dev->chip_id == CHIP_ID_EM2860 ||
> > +	    dev->chip_id == CHIP_ID_EM2883)
> > +		return 1;
> > +
> > +	/* Version of em28xx that does not support VBI */
> > +	return 0;
> > +}
> > +
> > +/* Set USB alternate setting for analog video */
> > +int em28xx_set_alternate(struct em28xx *dev)
> > +{
> > +	int errCode;
> > +	int i;
> > +	unsigned int min_pkt_size = dev->width * 2 + 4;
> > +
> > +	/* NOTE: for isoc transfers, only alt settings > 0 are allowed
> > +		 bulk transfers seem to work only with alt=0 ! */
> > +	dev->alt = 0;
> > +	if ((alt > 0) && (alt < dev->num_alt)) {
> > +		em28xx_videodbg("alternate forced to %d\n", dev->alt);
> > +		dev->alt = alt;
> > +		goto set_alt;
> > +	}
> > +	if (dev->analog_xfer_bulk)
> > +		goto set_alt;
> > +
> > +	/* When image size is bigger than a certain value,
> > +	   the frame size should be increased, otherwise, only
> > +	   green screen will be received.
> > +	 */
> > +	if (dev->width * 2 * dev->height > 720 * 240 * 2)
> > +		min_pkt_size *= 2;
> > +
> > +	for (i = 0; i < dev->num_alt; i++) {
> > +		/* stop when the selected alt setting offers enough bandwidth */
> > +		if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
> > +			dev->alt = i;
> > +			break;
> > +		/* otherwise make sure that we end up with the maximum bandwidth
> > +		   because the min_pkt_size equation might be wrong...
> > +		*/
> > +		} else if (dev->alt_max_pkt_size_isoc[i] >
> > +			   dev->alt_max_pkt_size_isoc[dev->alt])
> > +			dev->alt = i;
> > +	}
> > +
> > +set_alt:
> > +	/* NOTE: for bulk transfers, we need to call usb_set_interface()
> > +	 * even if the previous settings were the same. Otherwise streaming
> > +	 * fails with all urbs having status = -EOVERFLOW ! */
> > +	if (dev->analog_xfer_bulk) {
> > +		dev->max_pkt_size = 512; /* USB 2.0 spec */
> > +		dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
> > +	} else { /* isoc */
> > +		em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
> > +			       min_pkt_size, dev->alt);
> > +		dev->max_pkt_size =
> > +				  dev->alt_max_pkt_size_isoc[dev->alt];
> > +		dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
> > +	}
> > +	em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
> > +		       dev->alt, dev->max_pkt_size);
> > +	errCode = usb_set_interface(dev->udev, 0, dev->alt);
> > +	if (errCode < 0) {
> > +		em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
> > +			      dev->alt, errCode);
> > +		return errCode;
> > +	}
> > +	return 0;
> > +}
> > +
> >  /* ------------------------------------------------------------------
> >  	DMA and thread functions
> >     ------------------------------------------------------------------*/
> > @@ -1817,6 +2076,113 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
> >  	return vfd;
> >  }
> >  
> > +static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> > +{
> > +	memset(ctl, 0, sizeof(*ctl));
> > +
> > +	ctl->fname   = XC2028_DEFAULT_FIRMWARE;
> > +	ctl->max_len = 64;
> > +	ctl->mts = em28xx_boards[dev->model].mts_firmware;
> > +
> > +	switch (dev->model) {
> > +	case EM2880_BOARD_EMPIRE_DUAL_TV:
> > +	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
> > +	case EM2882_BOARD_TERRATEC_HYBRID_XS:
> > +		ctl->demod = XC3028_FE_ZARLINK456;
> > +		break;
> > +	case EM2880_BOARD_TERRATEC_HYBRID_XS:
> > +	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
> > +	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
> > +		ctl->demod = XC3028_FE_ZARLINK456;
> > +		break;
> > +	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
> > +	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
> > +		ctl->demod = XC3028_FE_DEFAULT;
> > +		break;
> > +	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
> > +		ctl->demod = XC3028_FE_DEFAULT;
> > +		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> > +		break;
> > +	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
> > +	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
> > +	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
> > +		/* FIXME: Better to specify the needed IF */
> > +		ctl->demod = XC3028_FE_DEFAULT;
> > +		break;
> > +	case EM2883_BOARD_KWORLD_HYBRID_330U:
> > +	case EM2882_BOARD_DIKOM_DK300:
> > +	case EM2882_BOARD_KWORLD_VS_DVBT:
> > +		ctl->demod = XC3028_FE_CHINA;
> > +		ctl->fname = XC2028_DEFAULT_FIRMWARE;
> > +		break;
> > +	case EM2882_BOARD_EVGA_INDTUBE:
> > +		ctl->demod = XC3028_FE_CHINA;
> > +		ctl->fname = XC3028L_DEFAULT_FIRMWARE;
> > +		break;
> > +	default:
> > +		ctl->demod = XC3028_FE_OREN538;
> > +	}
> > +}
> > +
> > +void em28xx_tuner_setup(struct em28xx *dev)
> > +{
> > +	struct tuner_setup           tun_setup;
> > +	struct v4l2_frequency        f;
> > +
> > +	if (dev->tuner_type == TUNER_ABSENT)
> > +		return;
> > +
> > +	memset(&tun_setup, 0, sizeof(tun_setup));
> > +
> > +	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
> > +	tun_setup.tuner_callback = em28xx_tuner_callback;
> > +
> > +	if (dev->board.radio.type) {
> > +		tun_setup.type = dev->board.radio.type;
> > +		tun_setup.addr = dev->board.radio_addr;
> > +
> > +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> > +	}
> > +
> > +	if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
> > +		tun_setup.type   = dev->tuner_type;
> > +		tun_setup.addr   = dev->tuner_addr;
> > +
> > +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
> > +	}
> > +
> > +	if (dev->tda9887_conf) {
> > +		struct v4l2_priv_tun_config tda9887_cfg;
> > +
> > +		tda9887_cfg.tuner = TUNER_TDA9887;
> > +		tda9887_cfg.priv = &dev->tda9887_conf;
> > +
> > +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
> > +	}
> > +
> > +	if (dev->tuner_type == TUNER_XC2028) {
> > +		struct v4l2_priv_tun_config  xc2028_cfg;
> > +		struct xc2028_ctrl           ctl;
> > +
> > +		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
> > +		memset(&ctl, 0, sizeof(ctl));
> > +
> > +		em28xx_setup_xc3028(dev, &ctl);
> > +
> > +		xc2028_cfg.tuner = TUNER_XC2028;
> > +		xc2028_cfg.priv  = &ctl;
> > +
> > +		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
> > +	}
> > +
> > +	/* configure tuner */
> > +	f.tuner = 0;
> > +	f.type = V4L2_TUNER_ANALOG_TV;
> > +	f.frequency = 9076;     /* just a magic number */
> > +	dev->ctl_freq = f.frequency;
> > +	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> > +}
> > +
> >  int em28xx_register_analog_devices(struct em28xx *dev)
> >  {
> >  	u8 val;
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index 191ef3593891..0259270dda46 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -748,6 +748,7 @@ void em28xx_init_extension(struct em28xx *dev);
> >  void em28xx_close_extension(struct em28xx *dev);
> >  
> >  /* Provided by em28xx-video.c */
> > +void em28xx_tuner_setup(struct em28xx *dev);
> >  int em28xx_vb2_setup(struct em28xx *dev);
> >  int em28xx_register_analog_devices(struct em28xx *dev);
> >  void em28xx_release_analog_resources(struct em28xx *dev);
> 
> Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
> 

I'll apply this and the other already reviewed patches. I'll eventually
move the order of em28xx_vbi_supported() on this changeset, keeping your
reviewed by, due to the comments you wrote on patch 4/22, putting it
to be before em28xx_wake_i2c().

-- 

Cheers,
Mauro

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

* Re: [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video
  2014-01-05 10:26   ` Frank Schäfer
@ 2014-01-05 14:40     ` Mauro Carvalho Chehab
  2014-01-06 21:28       ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 14:40 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 11:26:14 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > There are several init code inside em28xx-cards that are actually
> > part of analog initialization. Move the code to em28x-video, in
> > order to remove part of the mess.
> >
> > In thesis, no functional changes so far.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-cards.c | 71 -------------------------
> >  drivers/media/usb/em28xx/em28xx-video.c | 91 ++++++++++++++++++++++++++++++---
> >  2 files changed, 84 insertions(+), 78 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > index 551cbc294190..175cd776e0a1 100644
> > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > @@ -2907,7 +2907,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  			   struct usb_interface *interface,
> >  			   int minor)
> >  {
> > -	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
> >  	int retval;
> >  	static const char *default_chip_name = "em28xx";
> >  	const char *chip_name = default_chip_name;
> > @@ -3034,15 +3033,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  		}
> >  	}
> >  
> > -	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
> > -	if (retval < 0) {
> > -		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> > -		return retval;
> > -	}
> > -
> > -	v4l2_ctrl_handler_init(hdl, 8);
> > -	dev->v4l2_dev.ctrl_handler = hdl;
> > -
> >  	rt_mutex_init(&dev->i2c_bus_lock);
> >  
> >  	/* register i2c bus 0 */
> > @@ -3071,72 +3061,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> >  		}
> >  	}
> >  
> > -	/*
> > -	 * Default format, used for tvp5150 or saa711x output formats
> > -	 */
> > -	dev->vinmode = 0x10;
> > -	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> > -		       EM28XX_VINCTRL_CCIR656_ENABLE;
> > -
> >  	/* Do board specific init and eeprom reading */
> >  	em28xx_card_setup(dev);
> >  
> em28xx_card_setup() initializes some v4l2 subdevices, but now the v4l2
> device (dev->v4l2_dev) isn't ready at this point, because
> v4l2_device_register() isn't called yet.
> This introduces oopses.
> You are fixing this with patch 5/22 later, but patches should never
> introduce any oopses.
> The simplest soultion is to move patch 5/22 before this patch.

After thinking for a while, the better to just fold patch 5 into patch 3,
and do the necessary changes at the error handling logic.

This makes it simpler to review and test. 

New patch enclosed.

Btw, I tested here with HVR-950, without any noticeable changes.

Cheers,
Mauro

-

[PATCH] [media] em28xx: move analog-specific init to em28xx-video

There are several init code inside em28xx-cards that are actually
part of analog initialization. Move the code to em28x-video, in
order to remove part of the mess.

In thesis, no functional changes so far.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>

diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 154e6f028fd2..541de6df127b 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2360,24 +2360,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
 };
 /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
 
-/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
-static unsigned short saa711x_addrs[] = {
-	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
-	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
-	I2C_CLIENT_END };
-
-static unsigned short tvp5150_addrs[] = {
-	0xb8 >> 1,
-	0xba >> 1,
-	I2C_CLIENT_END
-};
-
-static unsigned short msp3400_addrs[] = {
-	0x80 >> 1,
-	0x88 >> 1,
-	I2C_CLIENT_END
-};
-
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 {
 	struct em28xx_i2c_bus *i2c_bus = ptr;
@@ -2782,58 +2764,8 @@ static void em28xx_card_setup(struct em28xx *dev)
 	/* Allow override tuner type by a module parameter */
 	if (tuner >= 0)
 		dev->tuner_type = tuner;
-
-	/* request some modules */
-	if (dev->board.has_msp34xx)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"msp3400", 0, msp3400_addrs);
-
-	if (dev->board.decoder == EM28XX_SAA711X)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"saa7115_auto", 0, saa711x_addrs);
-
-	if (dev->board.decoder == EM28XX_TVP5150)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"tvp5150", 0, tvp5150_addrs);
-
-	if (dev->board.adecoder == EM28XX_TVAUDIO)
-		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-			"tvaudio", dev->board.tvaudio_addr, NULL);
-
-	if (dev->board.tuner_type != TUNER_ABSENT) {
-		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
-
-		if (dev->board.radio.type)
-			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-				"tuner", dev->board.radio_addr, NULL);
-
-		if (has_demod)
-			v4l2_i2c_new_subdev(&dev->v4l2_dev,
-				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
-				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
-		if (dev->tuner_addr == 0) {
-			enum v4l2_i2c_tuner_type type =
-				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
-			struct v4l2_subdev *sd;
-
-			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
-				0, v4l2_i2c_tuner_addrs(type));
-
-			if (sd)
-				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
-		} else {
-			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-				"tuner", dev->tuner_addr, NULL);
-		}
-	}
-
-	em28xx_tuner_setup(dev);
-
-	em28xx_init_camera(dev);
 }
 
-
 static void request_module_async(struct work_struct *work)
 {
 	struct em28xx *dev = container_of(work,
@@ -2907,7 +2839,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 			   struct usb_interface *interface,
 			   int minor)
 {
-	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 	int retval;
 	static const char *default_chip_name = "em28xx";
 	const char *chip_name = default_chip_name;
@@ -3034,15 +2965,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		}
 	}
 
-	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
-	if (retval < 0) {
-		em28xx_errdev("Call to v4l2_device_register() failed!\n");
-		return retval;
-	}
-
-	v4l2_ctrl_handler_init(hdl, 8);
-	dev->v4l2_dev.ctrl_handler = hdl;
-
 	rt_mutex_init(&dev->i2c_bus_lock);
 
 	/* register i2c bus 0 */
@@ -3053,7 +2975,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 	if (retval < 0) {
 		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
 			__func__, retval);
-		goto unregister_dev;
+		return retval;
 	}
 
 	/* register i2c bus 1 */
@@ -3067,75 +2989,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 		if (retval < 0) {
 			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
 				__func__, retval);
-			goto unregister_dev;
+			return retval;
 		}
 	}
 
-	/*
-	 * Default format, used for tvp5150 or saa711x output formats
-	 */
-	dev->vinmode = 0x10;
-	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
-		       EM28XX_VINCTRL_CCIR656_ENABLE;
-
 	/* Do board specific init and eeprom reading */
 	em28xx_card_setup(dev);
 
-	/* Configure audio */
-	retval = em28xx_audio_setup(dev);
-	if (retval < 0) {
-		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
-			__func__, retval);
-		goto fail;
-	}
-	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
-		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
-	} else {
-		/* install the em28xx notify callback */
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
-				em28xx_ctrl_notify, dev);
-		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
-				em28xx_ctrl_notify, dev);
-	}
-
-	/* wake i2c devices */
-	em28xx_wake_i2c(dev);
-
-	/* init video dma queues */
-	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vbiq.active);
-
-	if (dev->board.has_msp34xx) {
-		/* Send a reset to other chips via gpio */
-		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
-		if (retval < 0) {
-			em28xx_errdev("%s: em28xx_write_reg - "
-				      "msp34xx(1) failed! error [%d]\n",
-				      __func__, retval);
-			goto fail;
-		}
-		msleep(3);
-
-		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
-		if (retval < 0) {
-			em28xx_errdev("%s: em28xx_write_reg - "
-				      "msp34xx(2) failed! error [%d]\n",
-				      __func__, retval);
-			goto fail;
-		}
-		msleep(3);
-	}
-
 	retval = em28xx_register_analog_devices(dev);
-	if (retval < 0) {
+	if (retval < 0)
 		goto fail;
-	}
-
-	/* Save some power by putting tuner to sleep */
-	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
 	return 0;
 
@@ -3143,10 +3006,6 @@ fail:
 	if (dev->def_i2c_bus)
 		em28xx_i2c_unregister(dev, 1);
 	em28xx_i2c_unregister(dev, 0);
-	v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-unregister_dev:
-	v4l2_device_unregister(&dev->v4l2_dev);
 
 	return retval;
 }
@@ -3388,9 +3247,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(interface, dev);
 
-	/* initialize videobuf2 stuff */
-	em28xx_vb2_setup(dev);
-
 	/* allocate device struct */
 	mutex_init(&dev->lock);
 	mutex_lock(&dev->lock);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index b3ede856c32e..3726af134f39 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2045,6 +2045,24 @@ static struct video_device em28xx_radio_template = {
 	.ioctl_ops 	      = &radio_ioctl_ops,
 };
 
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+	I2C_CLIENT_END };
+
+static unsigned short tvp5150_addrs[] = {
+	0xb8 >> 1,
+	0xba >> 1,
+	I2C_CLIENT_END
+};
+
+static unsigned short msp3400_addrs[] = {
+	0x80 >> 1,
+	0x88 >> 1,
+	I2C_CLIENT_END
+};
+
 /******************************** usb interface ******************************/
 
 
@@ -2186,10 +2204,129 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	u8 val;
 	int ret;
 	unsigned int maxw;
+	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
+	if (dev->is_audio_only) {
+		/* This device does not support the v4l2 extension */
+		return 0;
+	}
 
 	printk(KERN_INFO "%s: v4l2 driver version %s\n",
 		dev->name, EM28XX_VERSION);
 
+	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+	if (ret < 0) {
+		em28xx_errdev("Call to v4l2_device_register() failed!\n");
+		goto err;
+	}
+
+	v4l2_ctrl_handler_init(hdl, 8);
+	dev->v4l2_dev.ctrl_handler = hdl;
+
+	/*
+	 * Default format, used for tvp5150 or saa711x output formats
+	 */
+	dev->vinmode = 0x10;
+	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
+		       EM28XX_VINCTRL_CCIR656_ENABLE;
+
+	/* request some modules */
+
+	if (dev->board.has_msp34xx)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"msp3400", 0, msp3400_addrs);
+
+	if (dev->board.decoder == EM28XX_SAA711X)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"saa7115_auto", 0, saa711x_addrs);
+
+	if (dev->board.decoder == EM28XX_TVP5150)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"tvp5150", 0, tvp5150_addrs);
+
+	if (dev->board.adecoder == EM28XX_TVAUDIO)
+		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+			"tvaudio", dev->board.tvaudio_addr, NULL);
+
+	/* Initialize tuner and camera */
+
+	if (dev->board.tuner_type != TUNER_ABSENT) {
+		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+		if (dev->board.radio.type)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+				"tuner", dev->board.radio_addr, NULL);
+
+		if (has_demod)
+			v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
+				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+		if (dev->tuner_addr == 0) {
+			enum v4l2_i2c_tuner_type type =
+				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+			struct v4l2_subdev *sd;
+
+			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
+				0, v4l2_i2c_tuner_addrs(type));
+
+			if (sd)
+				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+		} else {
+			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+				"tuner", dev->tuner_addr, NULL);
+		}
+	}
+
+	em28xx_tuner_setup(dev);
+	em28xx_init_camera(dev);
+
+	/* Configure audio */
+	ret = em28xx_audio_setup(dev);
+	if (ret < 0) {
+		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+			__func__, ret);
+		goto unregister_dev;
+	}
+	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+	} else {
+		/* install the em28xx notify callback */
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+				em28xx_ctrl_notify, dev);
+		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+				em28xx_ctrl_notify, dev);
+	}
+
+	/* wake i2c devices */
+	em28xx_wake_i2c(dev);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vbiq.active);
+
+	if (dev->board.has_msp34xx) {
+		/* Send a reset to other chips via gpio */
+		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
+		if (ret < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
+				      __func__, ret);
+			goto unregister_dev;
+		}
+		msleep(3);
+
+		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
+		if (ret < 0) {
+			em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
+				      __func__, ret);
+			goto unregister_dev;
+		}
+		msleep(3);
+	}
+
 	/* set default norm */
 	dev->norm = V4L2_STD_PAL;
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
@@ -2252,14 +2389,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	/* Reset image controls */
 	em28xx_colorlevels_set_default(dev);
 	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-	if (dev->ctrl_handler.error)
-		return dev->ctrl_handler.error;
+	ret = dev->ctrl_handler.error;
+	if (ret)
+		goto unregister_dev;
 
 	/* allocate and fill video video_device struct */
 	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
 	if (!dev->vdev) {
 		em28xx_errdev("cannot allocate video_device.\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto unregister_dev;
 	}
 	dev->vdev->queue = &dev->vb_vidq;
 	dev->vdev->queue->lock = &dev->vb_queue_lock;
@@ -2289,7 +2428,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	if (ret) {
 		em28xx_errdev("unable to register video device (error=%i).\n",
 			      ret);
-		return ret;
+		goto unregister_dev;
 	}
 
 	/* Allocate and fill vbi video_device struct */
@@ -2318,7 +2457,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 					    vbi_nr[dev->devno]);
 		if (ret < 0) {
 			em28xx_errdev("unable to register vbi device\n");
-			return ret;
+			goto unregister_dev;
 		}
 	}
 
@@ -2327,13 +2466,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 						  "radio");
 		if (!dev->radio_dev) {
 			em28xx_errdev("cannot allocate video_device.\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto unregister_dev;
 		}
 		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
 					    radio_nr[dev->devno]);
 		if (ret < 0) {
 			em28xx_errdev("can't register radio device\n");
-			return ret;
+			goto unregister_dev;
 		}
 		em28xx_info("Registered radio device as %s\n",
 			    video_device_node_name(dev->radio_dev));
@@ -2346,5 +2486,17 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 		em28xx_info("V4L2 VBI device registered as %s\n",
 			    video_device_node_name(dev->vbi_dev));
 
+	/* Save some power by putting tuner to sleep */
+	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+	/* initialize videobuf2 stuff */
+	em28xx_vb2_setup(dev);
+
 	return 0;
+
+unregister_dev:
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
+	v4l2_device_unregister(&dev->v4l2_dev);
+err:
+	return ret;
 }


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

* Re: [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-05 12:56     ` Mauro Carvalho Chehab
@ 2014-01-05 15:18       ` Mauro Carvalho Chehab
  2014-01-06 21:35         ` Frank Schäfer
  2014-01-06 17:38       ` Frank Schäfer
  1 sibling, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 15:18 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Frank Schäfer, Linux Media Mailing List

Em Sun, 05 Jan 2014 10:56:33 -0200
Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:

> Em Sun, 05 Jan 2014 11:47:00 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> 
> > Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > > Now that all analog-specific code are at em28xx-video, convert
> > > it into an em28xx extension and load it as a separate module.
> > >
> > > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > > ---
> > >  drivers/media/usb/em28xx/Kconfig         |  6 ++-
> > >  drivers/media/usb/em28xx/Makefile        |  5 ++-
> > >  drivers/media/usb/em28xx/em28xx-camera.c |  1 +
> > >  drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
> > >  drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
> > >  drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
> > >  drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
> > >  drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
> > >  drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
> > >  9 files changed, 107 insertions(+), 80 deletions(-)
> > >  create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h
> > >
> > > diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
> > > index d6ba514d31eb..838fc9dbb747 100644
> > > --- a/drivers/media/usb/em28xx/Kconfig
> > > +++ b/drivers/media/usb/em28xx/Kconfig
> > > @@ -1,8 +1,12 @@
> > >  config VIDEO_EM28XX
> > > -	tristate "Empia EM28xx USB video capture support"
> > > +	tristate "Empia EM28xx USB devices support"
> > >  	depends on VIDEO_DEV && I2C
> > >  	select VIDEO_TUNER
> > >  	select VIDEO_TVEEPROM
> > > +
> > > +config VIDEO_EM28XX_V4L2
> > > +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
> > > +	depends on VIDEO_EM28XX && I2C
> > VIDEO_EM28XX already depends on I2C.
> > 
> > >  	select VIDEOBUF2_VMALLOC
> > >  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
> > >  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
> > > diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
> > > index ad6d48557940..3f850d5063d0 100644
> > > --- a/drivers/media/usb/em28xx/Makefile
> > > +++ b/drivers/media/usb/em28xx/Makefile
> > > @@ -1,10 +1,11 @@
> > > -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
> > > -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
> > > +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
> > >  
> > > +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
> > >  em28xx-alsa-objs := em28xx-audio.o
> > >  em28xx-rc-objs := em28xx-input.o
> > >  
> > >  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
> > > +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
> > >  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
> > >  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
> > >  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
> > > diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
> > > index d666741797d4..c29f5c4e7b40 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-camera.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> > > @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
> > >  
> > >  	return ret;
> > >  }
> > > +EXPORT_SYMBOL_GPL(em28xx_init_camera);
> > em28xx-camera should also be part of the em28xx-v4l module.
> 
> I tried that. Moving em28xx-camera to em28xx-v4l would cause a recursive
> dependency, due to the camera probing logic, that should be called by
> em28xx-cards.c.
> 
> Moving that probing part to em28xx-v4l is too complex, due to the code
> that detects the board.
> 
> One solution would be to break em28xx-camera into two parts: the detection
> code, to be merged with the core, and the sensor part, to be merged with
> em28xx-v4l, but that sounds ugly.
> 
> Other solution would be to use something like the dvb_attach() macro,
> to avoid the recursive dependency, but that would be a dirty solution.
> 
> As the code there is not big, the amount of overhead of having everything
> at em28xx-core is not high. So, I opted to keep the simplest path here,
> avoiding the risk of breaking something with a complex changeset.
> 
> > > diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> > > index 175cd776e0a1..938daaabd8e0 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-cards.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> > > @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
> > >  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
> > >  	},
> > >  };
> > > +EXPORT_SYMBOL_GPL(em28xx_boards);
> > > +
> > >  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
> > >  
> > >  /* table of devices that work with this driver */
> > > @@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
> > >  				"tuner", dev->tuner_addr, NULL);
> > >  		}
> > >  	}
> > > -
> > > -	em28xx_tuner_setup(dev);
> > > -
> > > -	em28xx_init_camera(dev);
> > >  }
> > Here you are fixing half of the em28xx_card_setup() oopses which you've
> > introduced with patch 3/22.
> > This needs to be done together with patch 5/22 before patch 3/22.
> 
> Ok.
> 
> > > @@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
> > >  	em28xx_init_extension(dev);
> > >  
> > >  #if defined(CONFIG_MODULES) && defined(MODULE)
> > > +	if (dev->has_video)
> > > +		request_module("em28xx-v4l");
> > >  	if (dev->has_audio_class)
> > >  		request_module("snd-usb-audio");
> > >  	else if (dev->has_alsa_audio)
> > >  		request_module("em28xx-alsa");
> > > -
> > >  	if (dev->board.has_dvb)
> > >  		request_module("em28xx-dvb");
> > >  	if (dev->board.buttons ||
> > > @@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
> > >  {
> > >  	/*FIXME: I2C IR should be disconnected */
> > >  
> > > -	em28xx_release_analog_resources(dev);
> > > -
> > >  	if (dev->def_i2c_bus)
> > >  		em28xx_i2c_unregister(dev, 1);
> > >  	em28xx_i2c_unregister(dev, 0);
> > >  	if (dev->clk)
> > >  		v4l2_clk_unregister_fixed(dev->clk);
> > >  
> > > -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > > -
> > > -	v4l2_device_unregister(&dev->v4l2_dev);
> > > -
> > >  	usb_put_dev(dev->udev);
> > >  
> > >  	/* Mark device as unused */
> > > @@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> > >  	if (retval < 0) {
> > >  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
> > >  			__func__, retval);
> > > -		goto unregister_dev;
> > > +		return retval;
> > >  	}
> > >  
> > >  	/* register i2c bus 1 */
> > > @@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
> > >  		if (retval < 0) {
> > >  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
> > >  				__func__, retval);
> > > -			goto unregister_dev;
> > > +			return retval;
> > >  		}
> > >  	}
> > Hmm... if registering of bus 1 fails, we need to unregister bus 0.
> > But that's an old bug which we can fix later...
> 
> Good point. Yes, this should be on a separate patch.

Patch sent.

> 
> > >  	/* Do board specific init and eeprom reading */
> > >  	em28xx_card_setup(dev);
> > >  
> > > -	retval = em28xx_register_analog_devices(dev);
> > > -	if (retval < 0) {
> > > -		goto fail;
> > > -	}
> > > -
> > >  	return 0;
> > > -
> > > -fail:
> > > -	if (dev->def_i2c_bus)
> > > -		em28xx_i2c_unregister(dev, 1);
> > > -	em28xx_i2c_unregister(dev, 0);
> > > -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > > -
> > > -unregister_dev:
> > > -	v4l2_device_unregister(&dev->v4l2_dev);
> > > -
> > > -	return retval;
> > >  }
> > >  
> > >  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
> > > @@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> > >  	dev->alt   = -1;
> > >  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
> > >  	dev->has_alsa_audio = has_audio;
> > > +	dev->has_video = has_video;
> > >  	dev->audio_ifnum = ifnum;
> > >  
> > >  	/* Checks if audio is provided by some interface */
> > > @@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> > >  
> > >  	/* allocate device struct */
> > >  	mutex_init(&dev->lock);
> > > -	mutex_lock(&dev->lock);
> > >  	retval = em28xx_init_dev(dev, udev, interface, nr);
> > >  	if (retval) {
> > > -		goto unlock_and_free;
> > > +		goto err_free;
> > >  	}
> > >  
> > >  	if (usb_xfer_mode < 0) {
> > > @@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> > >  		if (retval) {
> > >  			printk(DRIVER_NAME
> > >  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
> > > -			goto unlock_and_free;
> > > +			goto err_free;
> > >  		}
> > >  	}
> > >  
> > > @@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
> > >  	/* Should be the last thing to do, to avoid newer udev's to
> > >  	   open the device before fully initializing it
> > >  	 */
> > > -	mutex_unlock(&dev->lock);
> > >  
> > >  	return 0;
> > >  
> > > -unlock_and_free:
> > > -	mutex_unlock(&dev->lock);
> > > -
> > >  err_free:
> > >  	kfree(dev->alt_max_pkt_size_isoc);
> > >  	kfree(dev);
> > > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > > index 3012912d2997..1113d4e107d8 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > > @@ -33,6 +33,18 @@
> > >  
> > >  #include "em28xx.h"
> > >  
> > > +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
> > > +		      "Markus Rechberger <mrechberger@gmail.com>, " \
> > > +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
> > > +		      "Sascha Sommer <saschasommer@freenet.de>"
> > > +
> > > +#define DRIVER_DESC         "Empia em28xx based USB core driver"
> > > +
> > > +MODULE_AUTHOR(DRIVER_AUTHOR);
> > > +MODULE_DESCRIPTION(DRIVER_DESC);
> > > +MODULE_LICENSE("GPL");
> > > +MODULE_VERSION(EM28XX_VERSION);
> > > +
> > >  /* #define ENABLE_DEBUG_ISOC_FRAMES */
> > >  
> > >  static unsigned int core_debug;
> > > diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
> > > new file mode 100644
> > > index 000000000000..bce438691e0e
> > > --- /dev/null
> > > +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
> > > @@ -0,0 +1,20 @@
> > > +/*
> > > +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
> > > +		    video capture devices
> > The information about supported chips is outdated everywhere in the driver,
> > but if you introduce a new header file it should really be up to date.
> > Just talk about EM27xx/EM28xx.
> 
> We need to do a cleanup on all those headers: they don't follow Kernel
> CodingStyle and the old headers use my previous email.
> 
> For the sake of keeping a coherency, I deliberately opted to just use the
> same way as the other headers.
> 
> My plan is to write a patch series fixing this and other CodingStyle
> issues on em28xx after merging this changeset.
> 
> > > +
> > > +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
> > > +
> > > +   This program is free software; you can redistribute it and/or modify
> > > +   it under the terms of the GNU General Public License as published by
> > > +   the Free Software Foundation version 2 of the License.
> > > +
> > > +   This program is distributed in the hope that it will be useful,
> > > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > +   GNU General Public License for more details.
> > > + */
> > > +
> > > +
> > > +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> > > +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> > > +extern struct vb2_ops em28xx_vbi_qops;
> > > diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
> > > index 39f39c527c13..db3d655600df 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-vbi.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
> > > @@ -27,6 +27,7 @@
> > >  #include <linux/init.h>
> > >  
> > >  #include "em28xx.h"
> > > +#include "em28xx-v4l.h"
> > >  
> > >  static unsigned int vbibufs = 5;
> > >  module_param(vbibufs, int, 0644);
> > > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > > index 85284626dbd6..d615bff8ac09 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > > @@ -38,6 +38,7 @@
> > >  #include <linux/slab.h>
> > >  
> > >  #include "em28xx.h"
> > > +#include "em28xx-v4l.h"
> > >  #include <media/v4l2-common.h>
> > >  #include <media/v4l2-ioctl.h>
> > >  #include <media/v4l2-event.h>
> > > @@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
> > >  	},
> > >  };
> > >  
> > > +static int em28xx_vbi_supported(struct em28xx *dev);
> > > +
> > Or move em28xx_vbi_supported() before em28xx_set_outfmt() and
> > em28xx_resolution_set() again.
> > If you had not changed the functions order in patch 1/22, this wouldn't
> > be necessary.
> 
> True. I'll put an extra cleanup patch to remove this reference on the
> CodingStyle cleanup patchset I'm planning to do.

Ok, I changed the order on patch 1/22, so this line was removed.

> 
> > >  /*
> > >   * em28xx_wake_i2c()
> > >   * configure i2c attached devices
> > >   */
> > > -void em28xx_wake_i2c(struct em28xx *dev)
> > > +static void em28xx_wake_i2c(struct em28xx *dev)
> > >  {
> > >  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
> > >  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> > > @@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
> > >  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
> > >  }
> > >  
> > > -int em28xx_colorlevels_set_default(struct em28xx *dev)
> > > +static int em28xx_colorlevels_set_default(struct em28xx *dev)
> > >  {
> > >  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
> > >  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> > > @@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
> > >  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
> > >  }
> > >  
> > > -int em28xx_set_outfmt(struct em28xx *dev)
> > > +static int em28xx_set_outfmt(struct em28xx *dev)
> > >  {
> > >  	int ret;
> > >  	u8 fmt, vinctrl;
> > > @@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
> > >  }
> > >  
> > >  /* FIXME: this only function read values from dev */
> > > -int em28xx_resolution_set(struct em28xx *dev)
> > > +static int em28xx_resolution_set(struct em28xx *dev)
> > >  {
> > >  	int width, height;
> > >  	width = norm_maxw(dev);
> > > @@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
> > >  	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
> > >  }
> > >  
> > > -int em28xx_vbi_supported(struct em28xx *dev)
> > > +static int em28xx_vbi_supported(struct em28xx *dev)
> > >  {
> > >  	/* Modprobe option to manually disable */
> > >  	if (disable_vbi == 1)
> > > @@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
> > >  }
> > >  
> > >  /* Set USB alternate setting for analog video */
> > > -int em28xx_set_alternate(struct em28xx *dev)
> > > +static int em28xx_set_alternate(struct em28xx *dev)
> > >  {
> > >  	int errCode;
> > >  	int i;
> > > @@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
> > >  	.wait_finish    = vb2_ops_wait_finish,
> > >  };
> > >  
> > > -int em28xx_vb2_setup(struct em28xx *dev)
> > > +static int em28xx_vb2_setup(struct em28xx *dev)
> > >  {
> > >  	int rc;
> > >  	struct vb2_queue *q;
> > > @@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
> > >  	em28xx_audio_analog_set(dev);
> > >  }
> > >  
> > > -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> > > +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> > >  {
> > >  	struct em28xx *dev = priv;
> > >  
> > > @@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
> > >  		reg->val = ret;
> > >  	} else {
> > >  		__le16 val = 0;
> > > -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> > > +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> > >  						   reg->reg, (char *)&val, 2);
> > Urgh... is it really necessary to start using these pointers again ?
> > Ok... keep it as is, I'll send a patch to clean this up later.
> 
> This is one of the few places where we weren't using those pointers:
> 
> $ git grep em28xx_read_reg_req_len drivers/media/usb/em28xx/
> drivers/media/usb/em28xx/em28xx-cards.c:  dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
> drivers/media/usb/em28xx/em28xx-core.c:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
> drivers/media/usb/em28xx/em28xx-core.c:   ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
> drivers/media/usb/em28xx/em28xx-core.c:   ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
> drivers/media/usb/em28xx/em28xx-i2c.c:            ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
> drivers/media/usb/em28xx/em28xx-video.c:          ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> drivers/media/usb/em28xx/em28xx.h:        int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
> drivers/media/usb/em28xx/em28xx.h:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
> 
> For the sake of coherency, we should either use one or the other way.
> 
> > 
> > >  		if (ret < 0)
> > >  			return ret;
> > > @@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
> > >  }
> > >  
> > >  /*
> > > - * em28xx_realease_resources()
> > > + * em28xx_v4l2_fini()
> > >   * unregisters the v4l2,i2c and usb devices
> > >   * called when the device gets disconected or at module unload
> > >  */
> > > -void em28xx_release_analog_resources(struct em28xx *dev)
> > > +static int em28xx_v4l2_fini(struct em28xx *dev)
> > >  {
> > >  
> > >  	/*FIXME: I2C IR should be disconnected */
> > > @@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
> > >  			video_device_release(dev->vdev);
> > >  		dev->vdev = NULL;
> > >  	}
> > > +
> > > +	return 0;
> > >  }
> > >  
> > >  /*
> > > @@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
> > >  	if (dev->users == 1) {
> > >  		/* the device is already disconnect,
> > >  		   free the remaining resources */
> > > +
> > >  		if (dev->disconnected) {
> > > -			em28xx_release_resources(dev);
> > Who releases the resources now ?
> 
> This is tricky.
> 
> The hole idea is that em28xx-v4l release the resources allocated for V4L
> only, and not all resources, the same way as the other em28xx modules
> do.
> 
> If you take a look at the original em28xx_release_resources(), what it does
> is to call this function, and then to de-allocate and unregister v4l2:
> 
> 			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> 			v4l2_device_unregister(&dev->v4l2_dev);
> 
> after that, it deallocates the rest of allocated data.
> 
> Now, em28xx_release_resources() is only called when em28xx is removed
> from memory or when the device is removed.
> 
> The code there first calls em28xx_close_extension(dev). So, at device
> removal, em28xx-v4l will release the V4L2 specific resources, and
> em28xx_release_resources() will drop the common dev struct.
> 
> I suspect that it might still be a bug there, but, if so, this bug is 
> also present on em28xx-dvb, em28xx-alsa and em28xx-rc: what happens if 
> the device is removed while the file descriptors is still opened?
> 
> Maybe the driver core already prevent such things, but I'm not sure.
> 
> If there's a bug out there, the proper fix seems to use kref for 
> struct em28xx, increasing refcount for every em28xx extension and/or 
> file open, decreasing it at either extension fini call, or at file close.
> 
> This way, em28xx_release_resources() would be called only after refcount
> reaching zero, e. g. after being sure that nobody is using it.
> 
> My plan is to take a look on it after having this changeset merged,
> as such change, if needed, will be complex and would require lots of
> testing. Also, it is independent on those changes.
> 
> > 
> > > +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> > > +			v4l2_device_unregister(&dev->v4l2_dev);
> > >  			kfree(dev->alt_max_pkt_size_isoc);
> > > -			mutex_unlock(&dev->lock);
> > > -			kfree(dev);
> > > -			return 0;
> > > +			goto exit;
> > >  		}
> > >  
> > >  		/* Save some power by putting tuner to sleep */
> > > @@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
> > >  		}
> > >  	}
> > >  
> > > +exit:
> > >  	dev->users--;
> > Nice bugfix.
> > 
> > >  	mutex_unlock(&dev->lock);
> > >  	return 0;
> > > @@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
> > >  
> > >  /******************************** usb interface ******************************/
> > >  
> > > -
> > > -
> > >  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
> > >  					const struct video_device *template,
> > >  					const char *type_name)
> > > @@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
> > >  	}
> > >  }
> > >  
> > > -void em28xx_tuner_setup(struct em28xx *dev)
> > > +static void em28xx_tuner_setup(struct em28xx *dev)
> > >  {
> > >  	struct tuner_setup           tun_setup;
> > >  	struct v4l2_frequency        f;
> > > @@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
> > >  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
> > >  }
> > >  
> > > -int em28xx_register_analog_devices(struct em28xx *dev)
> > > +static int em28xx_v4l2_init(struct em28xx *dev)
> > >  {
> > >  	u8 val;
> > >  	int ret;
> > >  	unsigned int maxw;
> > >  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
> > >  
> > > -	if (!dev->is_audio_only) {
> > > +	if (!dev->has_video) {
> > >  		/* This device does not support the v4l2 extension */
> > >  		return 0;
> > >  	}
> > > @@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> > >  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
> > >  		dev->name, EM28XX_VERSION);
> > >  
> > > +	mutex_lock(&dev->lock);
> > > +
> > >  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> > >  	if (ret < 0) {
> > >  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> > > @@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> > >  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> > >  		       EM28XX_VINCTRL_CCIR656_ENABLE;
> > >  
> > > +	/* Initialize tuner and camera */
> > > +	em28xx_tuner_setup(dev);
> > > +	em28xx_init_camera(dev);
> > > +
> > >  	/* Configure audio */
> > >  	ret = em28xx_audio_setup(dev);
> > >  	if (ret < 0) {
> > > @@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
> > >  
> > >  	/* initialize videobuf2 stuff */
> > >  	em28xx_vb2_setup(dev);
> > > +
> > >  err:
> > > -	return 0;
> > > +	mutex_unlock(&dev->lock);
> > > +	return ret;
> > > +}
> > > +
> > > +static struct em28xx_ops v4l2_ops = {
> > > +	.id   = EM28XX_V4L2,
> > > +	.name = "Em28xx v4l2 Extension",
> > > +	.init = em28xx_v4l2_init,
> > > +	.fini = em28xx_v4l2_fini,
> > > +};
> > > +
> > > +static int __init em28xx_video_register(void)
> > > +{
> > > +	return em28xx_register_extension(&v4l2_ops);
> > >  }
> > > +
> > > +static void __exit em28xx_video_unregister(void)
> > > +{
> > > +	em28xx_unregister_extension(&v4l2_ops);
> > > +}
> > > +
> > > +module_init(em28xx_video_register);
> > > +module_exit(em28xx_video_unregister);
> > > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > > index 7ae05ebc13c1..9d6f43e4681f 100644
> > > --- a/drivers/media/usb/em28xx/em28xx.h
> > > +++ b/drivers/media/usb/em28xx/em28xx.h
> > > @@ -26,7 +26,7 @@
> > >  #ifndef _EM28XX_H
> > >  #define _EM28XX_H
> > >  
> > > -#define EM28XX_VERSION "0.2.0"
> > > +#define EM28XX_VERSION "0.2.1"
> > >  
> > >  #include <linux/workqueue.h>
> > >  #include <linux/i2c.h>
> > > @@ -474,6 +474,7 @@ struct em28xx_eeprom {
> > >  #define EM28XX_AUDIO   0x10
> > >  #define EM28XX_DVB     0x20
> > >  #define EM28XX_RC      0x30
> > > +#define EM28XX_V4L2    0x40
> > >  
> > >  /* em28xx resource types (used for res_get/res_lock etc */
> > >  #define EM28XX_RESOURCE_VIDEO 0x01
> > > @@ -527,6 +528,7 @@ struct em28xx {
> > >  
> > >  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
> > >  	unsigned char disconnected:1;	/* device has been diconnected */
> > > +	unsigned int has_video:1;
> > >  	unsigned int has_audio_class:1;
> > >  	unsigned int has_alsa_audio:1;
> > >  	unsigned int is_audio_only:1;
> > > @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
> > >  int em28xx_audio_analog_set(struct em28xx *dev);
> > >  int em28xx_audio_setup(struct em28xx *dev);
> > >  
> > > -int em28xx_colorlevels_set_default(struct em28xx *dev);
> > >  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
> > >  					 enum em28xx_led_role role);
> > >  int em28xx_capture_start(struct em28xx *dev, int start);
> > > -int em28xx_vbi_supported(struct em28xx *dev);
> > > -int em28xx_set_outfmt(struct em28xx *dev);
> > > -int em28xx_resolution_set(struct em28xx *dev);
> > > -int em28xx_set_alternate(struct em28xx *dev);
> > >  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
> > >  		      int num_bufs, int max_pkt_size, int packet_multiplier);
> > >  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
> > > @@ -742,31 +739,17 @@ 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);
> > > -void em28xx_wake_i2c(struct em28xx *dev);
> > >  int em28xx_register_extension(struct em28xx_ops *dev);
> > >  void em28xx_unregister_extension(struct em28xx_ops *dev);
> > >  void em28xx_init_extension(struct em28xx *dev);
> > >  void em28xx_close_extension(struct em28xx *dev);
> > >  
> > > -/* Provided by em28xx-video.c */
> > > -void em28xx_tuner_setup(struct em28xx *dev);
> > > -int em28xx_vb2_setup(struct em28xx *dev);
> > > -int em28xx_register_analog_devices(struct em28xx *dev);
> > > -void em28xx_release_analog_resources(struct em28xx *dev);
> > > -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
> > > -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> > > -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> > > -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
> > > -
> > >  /* Provided by em28xx-cards.c */
> > >  extern 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_release_resources(struct em28xx *dev);
> > >  
> > > -/* Provided by em28xx-vbi.c */
> > > -extern struct vb2_ops em28xx_vbi_qops;
> > > -
> > >  /* Provided by em28xx-camera.c */
> > >  int em28xx_detect_sensor(struct em28xx *dev);
> > >  int em28xx_init_camera(struct em28xx *dev);
> > Nice clean-up ! :)
> 
> Thanks!
> 

Ok, this is the new version of the patch. It is basically a rebase of the
previous one. Btw, I'm adding those patches on this tree:

	http://git.linuxtv.org/mchehab/experimental.git/shortlog/refs/heads/em28xx-v4l2-v5

-

[media] em28xx: make em28xx-video to be a separate module

Now that all analog-specific code are at em28xx-video, convert
it into an em28xx extension and load it as a separate module.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>

diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index d6ba514d31eb..838fc9dbb747 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -1,8 +1,12 @@
 config VIDEO_EM28XX
-	tristate "Empia EM28xx USB video capture support"
+	tristate "Empia EM28xx USB devices support"
 	depends on VIDEO_DEV && I2C
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
+
+config VIDEO_EM28XX_V4L2
+	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
+	depends on VIDEO_EM28XX
 	select VIDEOBUF2_VMALLOC
 	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index ad6d48557940..3f850d5063d0 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,10 +1,11 @@
-em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
+em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
 
+em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
 em28xx-alsa-objs := em28xx-audio.o
 em28xx-rc-objs := em28xx-input.o
 
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
 obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index d666741797d4..c29f5c4e7b40 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(em28xx_init_camera);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index dbce4dc421f9..b25869331284 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
 		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
 	},
 };
+EXPORT_SYMBOL_GPL(em28xx_boards);
+
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
@@ -2780,11 +2782,12 @@ static void request_module_async(struct work_struct *work)
 	em28xx_init_extension(dev);
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
+	if (dev->has_video)
+		request_module("em28xx-v4l");
 	if (dev->has_audio_class)
 		request_module("snd-usb-audio");
 	else if (dev->has_alsa_audio)
 		request_module("em28xx-alsa");
-
 	if (dev->board.has_dvb)
 		request_module("em28xx-dvb");
 	if (dev->board.buttons ||
@@ -2813,18 +2816,12 @@ void em28xx_release_resources(struct em28xx *dev)
 {
 	/*FIXME: I2C IR should be disconnected */
 
-	em28xx_release_analog_resources(dev);
-
 	if (dev->def_i2c_bus)
 		em28xx_i2c_unregister(dev, 1);
 	em28xx_i2c_unregister(dev, 0);
 	if (dev->clk)
 		v4l2_clk_unregister_fixed(dev->clk);
 
-	v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-	v4l2_device_unregister(&dev->v4l2_dev);
-
 	usb_put_dev(dev->udev);
 
 	/* Mark device as unused */
@@ -2999,18 +2996,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
 	/* Do board specific init and eeprom reading */
 	em28xx_card_setup(dev);
 
-	retval = em28xx_register_analog_devices(dev);
-	if (retval < 0)
-		goto fail;
-
 	return 0;
-
-fail:
-	if (dev->def_i2c_bus)
-		em28xx_i2c_unregister(dev, 1);
-	em28xx_i2c_unregister(dev, 0);
-
-	return retval;
 }
 
 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
@@ -3213,6 +3199,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	dev->alt   = -1;
 	dev->is_audio_only = has_audio && !(has_video || has_dvb);
 	dev->has_alsa_audio = has_audio;
+	dev->has_video = has_video;
 	dev->audio_ifnum = ifnum;
 
 	/* Checks if audio is provided by some interface */
@@ -3252,10 +3239,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
 	/* allocate device struct */
 	mutex_init(&dev->lock);
-	mutex_lock(&dev->lock);
 	retval = em28xx_init_dev(dev, udev, interface, nr);
 	if (retval) {
-		goto unlock_and_free;
+		goto err_free;
 	}
 
 	if (usb_xfer_mode < 0) {
@@ -3298,7 +3284,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 		if (retval) {
 			printk(DRIVER_NAME
 			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
-			goto unlock_and_free;
+			goto err_free;
 		}
 	}
 
@@ -3307,13 +3293,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	/* Should be the last thing to do, to avoid newer udev's to
 	   open the device before fully initializing it
 	 */
-	mutex_unlock(&dev->lock);
 
 	return 0;
 
-unlock_and_free:
-	mutex_unlock(&dev->lock);
-
 err_free:
 	kfree(dev->alt_max_pkt_size_isoc);
 	kfree(dev);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index f77301773aee..c416dd33af3f 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -33,6 +33,18 @@
 
 #include "em28xx.h"
 
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+		      "Markus Rechberger <mrechberger@gmail.com>, " \
+		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+		      "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_DESC         "Empia em28xx based USB core driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
 static unsigned int core_debug;
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
new file mode 100644
index 000000000000..bce438691e0e
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -0,0 +1,20 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
+
+   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+ */
+
+
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 39f39c527c13..db3d655600df 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 3726af134f39..78a1bfb97c3d 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
@@ -141,7 +142,7 @@ static struct em28xx_fmt format[] = {
 	},
 };
 
-int em28xx_vbi_supported(struct em28xx *dev)
+static int em28xx_vbi_supported(struct em28xx *dev)
 {
 	/* Modprobe option to manually disable */
 	if (disable_vbi == 1)
@@ -164,7 +165,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
  * em28xx_wake_i2c()
  * configure i2c attached devices
  */
-void em28xx_wake_i2c(struct em28xx *dev)
+static void em28xx_wake_i2c(struct em28xx *dev)
 {
 	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
 	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
@@ -172,7 +173,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
 	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
 }
 
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+static int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
 	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
 	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
@@ -190,7 +191,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
 	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
 }
 
-int em28xx_set_outfmt(struct em28xx *dev)
+static int em28xx_set_outfmt(struct em28xx *dev)
 {
 	int ret;
 	u8 fmt, vinctrl;
@@ -297,7 +298,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 }
 
 /* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
+static int em28xx_resolution_set(struct em28xx *dev)
 {
 	int width, height;
 	width = norm_maxw(dev);
@@ -330,7 +331,7 @@ int em28xx_resolution_set(struct em28xx *dev)
 }
 
 /* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
+static int em28xx_set_alternate(struct em28xx *dev)
 {
 	int errCode;
 	int i;
@@ -1020,7 +1021,7 @@ static struct vb2_ops em28xx_video_qops = {
 	.wait_finish    = vb2_ops_wait_finish,
 };
 
-int em28xx_vb2_setup(struct em28xx *dev)
+static int em28xx_vb2_setup(struct em28xx *dev)
 {
 	int rc;
 	struct vb2_queue *q;
@@ -1088,7 +1089,7 @@ static void video_mux(struct em28xx *dev, int index)
 	em28xx_audio_analog_set(dev);
 }
 
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
+static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 {
 	struct em28xx *dev = priv;
 
@@ -1625,7 +1626,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 		reg->val = ret;
 	} else {
 		__le16 val = 0;
-		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
 						   reg->reg, (char *)&val, 2);
 		if (ret < 0)
 			return ret;
@@ -1872,15 +1873,12 @@ static int em28xx_v4l2_open(struct file *filp)
 }
 
 /*
- * em28xx_realease_resources()
+ * em28xx_v4l2_fini()
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-void em28xx_release_analog_resources(struct em28xx *dev)
+static int em28xx_v4l2_fini(struct em28xx *dev)
 {
-
-	/*FIXME: I2C IR should be disconnected */
-
 	if (dev->radio_dev) {
 		if (video_is_registered(dev->radio_dev))
 			video_unregister_device(dev->radio_dev);
@@ -1906,6 +1904,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
 			video_device_release(dev->vdev);
 		dev->vdev = NULL;
 	}
+
+	return 0;
 }
 
 /*
@@ -1927,12 +1927,12 @@ static int em28xx_v4l2_close(struct file *filp)
 	if (dev->users == 1) {
 		/* the device is already disconnect,
 		   free the remaining resources */
+
 		if (dev->disconnected) {
-			em28xx_release_resources(dev);
+			v4l2_ctrl_handler_free(&dev->ctrl_handler);
+			v4l2_device_unregister(&dev->v4l2_dev);
 			kfree(dev->alt_max_pkt_size_isoc);
-			mutex_unlock(&dev->lock);
-			kfree(dev);
-			return 0;
+			goto exit;
 		}
 
 		/* Save some power by putting tuner to sleep */
@@ -1951,6 +1951,7 @@ static int em28xx_v4l2_close(struct file *filp)
 		}
 	}
 
+exit:
 	dev->users--;
 	mutex_unlock(&dev->lock);
 	return 0;
@@ -2065,8 +2066,6 @@ static unsigned short msp3400_addrs[] = {
 
 /******************************** usb interface ******************************/
 
-
-
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 					const struct video_device *template,
 					const char *type_name)
@@ -2140,7 +2139,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
 	}
 }
 
-void em28xx_tuner_setup(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev)
 {
 	struct tuner_setup           tun_setup;
 	struct v4l2_frequency        f;
@@ -2199,14 +2198,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
 	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
 }
 
-int em28xx_register_analog_devices(struct em28xx *dev)
+static int em28xx_v4l2_init(struct em28xx *dev)
 {
 	u8 val;
 	int ret;
 	unsigned int maxw;
 	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
 
-	if (dev->is_audio_only) {
+	if (!dev->has_video) {
 		/* This device does not support the v4l2 extension */
 		return 0;
 	}
@@ -2214,6 +2213,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	printk(KERN_INFO "%s: v4l2 driver version %s\n",
 		dev->name, EM28XX_VERSION);
 
+	mutex_lock(&dev->lock);
+
 	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
 	if (ret < 0) {
 		em28xx_errdev("Call to v4l2_device_register() failed!\n");
@@ -2492,11 +2493,33 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 	/* initialize videobuf2 stuff */
 	em28xx_vb2_setup(dev);
 
+	mutex_unlock(&dev->lock);
 	return 0;
 
 unregister_dev:
 	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 	v4l2_device_unregister(&dev->v4l2_dev);
 err:
+	mutex_unlock(&dev->lock);
 	return ret;
 }
+
+static struct em28xx_ops v4l2_ops = {
+	.id   = EM28XX_V4L2,
+	.name = "Em28xx v4l2 Extension",
+	.init = em28xx_v4l2_init,
+	.fini = em28xx_v4l2_fini,
+};
+
+static int __init em28xx_video_register(void)
+{
+	return em28xx_register_extension(&v4l2_ops);
+}
+
+static void __exit em28xx_video_unregister(void)
+{
+	em28xx_unregister_extension(&v4l2_ops);
+}
+
+module_init(em28xx_video_register);
+module_exit(em28xx_video_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 7ae05ebc13c1..9d6f43e4681f 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,7 +26,7 @@
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
-#define EM28XX_VERSION "0.2.0"
+#define EM28XX_VERSION "0.2.1"
 
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
@@ -474,6 +474,7 @@ struct em28xx_eeprom {
 #define EM28XX_AUDIO   0x10
 #define EM28XX_DVB     0x20
 #define EM28XX_RC      0x30
+#define EM28XX_V4L2    0x40
 
 /* em28xx resource types (used for res_get/res_lock etc */
 #define EM28XX_RESOURCE_VIDEO 0x01
@@ -527,6 +528,7 @@ struct em28xx {
 
 	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
 	unsigned char disconnected:1;	/* device has been diconnected */
+	unsigned int has_video:1;
 	unsigned int has_audio_class:1;
 	unsigned int has_alsa_audio:1;
 	unsigned int is_audio_only:1;
@@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
 int em28xx_audio_analog_set(struct em28xx *dev);
 int em28xx_audio_setup(struct em28xx *dev);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev);
 const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
 					 enum em28xx_led_role role);
 int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_vbi_supported(struct em28xx *dev);
-int em28xx_set_outfmt(struct em28xx *dev);
-int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_set_alternate(struct em28xx *dev);
 int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
 		      int num_bufs, int max_pkt_size, int packet_multiplier);
 int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
@@ -742,31 +739,17 @@ 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);
-void em28xx_wake_i2c(struct em28xx *dev);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 void em28xx_init_extension(struct em28xx *dev);
 void em28xx_close_extension(struct em28xx *dev);
 
-/* Provided by em28xx-video.c */
-void em28xx_tuner_setup(struct em28xx *dev);
-int em28xx_vb2_setup(struct em28xx *dev);
-int em28xx_register_analog_devices(struct em28xx *dev);
-void em28xx_release_analog_resources(struct em28xx *dev);
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
-int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
-extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
-
 /* Provided by em28xx-cards.c */
 extern 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_release_resources(struct em28xx *dev);
 
-/* Provided by em28xx-vbi.c */
-extern struct vb2_ops em28xx_vbi_qops;
-
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
 int em28xx_init_camera(struct em28xx *dev);


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

* Re: [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-05 13:08     ` Mauro Carvalho Chehab
@ 2014-01-05 15:31       ` Mauro Carvalho Chehab
  2014-01-06 17:44       ` Frank Schäfer
  1 sibling, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 15:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Frank Schäfer, Linux Media Mailing List

Em Sun, 05 Jan 2014 11:08:22 -0200
Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:

> Em Sun, 05 Jan 2014 11:55:34 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> 
> > Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > > Add a message with consistent prints before and after each
> > > extension initialization, and provide a better text for module
> > > load.
> > >
> > > While here, add a missing sanity check for extension finish
> > > code at em28xx-v4l extension.
> > >
> > > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > > ---
> > >  drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
> > >  drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
> > >  drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
> > >  drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
> > >  drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
> > >  5 files changed, 20 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > > index 2fdb66ee44ab..263886adcf26 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > > @@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> > >  		return 0;
> > >  	}
> > >  
> > > -	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
> > > +	em28xx_info("Binding audio extension\n");
> > > +
> > >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> > >  			 "Rechberger\n");
> > >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> > > @@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
> > >  	adev->sndcard = card;
> > >  	adev->udev = dev->udev;
> > >  
> > > +	em28xx_info("Audio extension successfully initialized\n");
> > >  	return 0;
> > >  }
> > >  
> > > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > > index 1113d4e107d8..33cf26e106b5 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > > @@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
> > >  		ops->init(dev);
> > >  	}
> > >  	mutex_unlock(&em28xx_devlist_mutex);
> > > -	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
> > > +	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
> > >  	return 0;
> > >  }
> > >  EXPORT_SYMBOL(em28xx_register_extension);
> > > diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> > > index ddc0e609065d..f72663a9b5c5 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> > > @@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
> > >  static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
> > >  {
> > >  	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
> > > -        struct em28xx *dev = i2c_bus->dev;
> > > +	struct em28xx *dev = i2c_bus->dev;
> > >  
> > >  	if (acquire)
> > >  		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
> > > @@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> > >  
> > >  	if (!dev->board.has_dvb) {
> > >  		/* This device does not support the extension */
> > > -		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
> > >  		return 0;
> > >  	}
> > >  
> > > +	em28xx_info("Binding DVB extension\n");
> > > +
> > >  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> > >  
> > >  	if (dvb == NULL) {
> > > @@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> > >  	/* MFE lock */
> > >  	dvb->adapter.mfe_shared = mfe_shared;
> > >  
> > > -	em28xx_info("Successfully loaded em28xx-dvb\n");
> > > +	em28xx_info("DVB extension successfully initialized\n");
> > >  ret:
> > >  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> > >  	mutex_unlock(&dev->lock);
> > > diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> > > index 93a7d02b9cb4..eed7dd79f734 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-input.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-input.c
> > > @@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> > >  		return 0;
> > >  	}
> > >  
> > > +	em28xx_info("Registering input extension\n");
> > > +
> > >  	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
> > >  	rc = rc_allocate_device();
> > >  	if (!ir || !rc)
> > > @@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> > >  	if (err)
> > >  		goto error;
> > >  
> > > +	em28xx_info("Input extension successfully initalized\n");
> > > +
> > >  	return 0;
> > >  
> > >  error:
> > > diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> > > index 56d1b46164a0..b767262c642b 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-video.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-video.c
> > > @@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> > >  
> > >  	/*FIXME: I2C IR should be disconnected */
> > >  
> > > +	if (!dev->has_video) {
> > > +		/* This device does not support the v4l2 extension */
> > > +		return 0;
> > > +	}
> > > +
> > That's a separate change and AFAICS it's not needed.
> 
> It is needed. If you plug a device with video first and then a DVB-only device,
> as em28xx-v4l will be loaded, it will initialize the extension, if this code got
> removed.
> 
> I can move it to a separate patch adding the proper description.

Better to add it together with patch 4/22:
	http://git.linuxtv.org/mchehab/experimental.git/commitdiff/de93f52d20ba317d8a41614fbf439e956ec2c7d6

Regards,
Mauro

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

* Re: [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code
  2014-01-05 13:20     ` Mauro Carvalho Chehab
@ 2014-01-05 15:44       ` Mauro Carvalho Chehab
  2014-01-07 16:50         ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 15:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Frank Schäfer, Linux Media Mailing List

Em Sun, 05 Jan 2014 11:20:02 -0200
Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:

> Em Sun, 05 Jan 2014 12:19:41 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> 
> > Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > > Instead of assuming that msleep() is precise, use a jiffies
> > > based code to wait for AC97 to be available.
> > >
> > > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > > ---
> > >  drivers/media/usb/em28xx/em28xx-core.c | 7 +++++--
> > >  drivers/media/usb/em28xx/em28xx.h      | 5 ++++-
> > >  2 files changed, 9 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> > > index 818248d3fd28..36b2f1ab4474 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-core.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-core.c
> > > @@ -23,6 +23,7 @@
> > >   */
> > >  
> > >  #include <linux/init.h>
> > > +#include <linux/jiffies.h>
> > >  #include <linux/list.h>
> > >  #include <linux/module.h>
> > >  #include <linux/slab.h>
> > > @@ -254,16 +255,18 @@ EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
> > >   */
> > >  static int em28xx_is_ac97_ready(struct em28xx *dev)
> > >  {
> > > -	int ret, i;
> > > +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_AC97_XFER_TIMEOUT);
> > > +	int ret;
> > >  
> > >  	/* Wait up to 50 ms for AC97 command to complete */
> > > -	for (i = 0; i < 10; i++, msleep(5)) {
> > > +	while (time_is_after_jiffies(timeout)) {
> > time_is_before_jiffies(timeout)
> > 
> > >  		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
> > >  		if (ret < 0)
> > >  			return ret;
> > >  
> > >  		if (!(ret & 0x01))
> > >  			return 0;
> > > +		msleep (5);
> > >  	}
> > >  
> > >  	em28xx_warn("AC97 command still being executed: not handled properly!\n");
> > > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > > index 9d6f43e4681f..ac79501f5d9f 100644
> > > --- a/drivers/media/usb/em28xx/em28xx.h
> > > +++ b/drivers/media/usb/em28xx/em28xx.h
> > > @@ -182,9 +182,12 @@
> > >  
> > >  #define EM28XX_INTERLACED_DEFAULT 1
> > >  
> > > -/* time in msecs to wait for i2c writes to finish */
> > > +/* time in msecs to wait for i2c xfers to finish */
> > >  #define EM2800_I2C_XFER_TIMEOUT		20
> > >  
> > > +/* time in msecs to wait for AC97 xfers to finish */
> > > +#define EM2800_AC97_XFER_TIMEOUT	100
> > > +
> > I applies to all chips supporting AC97 audio, so call it
> > EM28XX_AC97_XFER_TIMEOUT.
> 
> Ok.
> 
> > Why did you increase the timeout from 50ms to 100ms ?
> > 50ms already seems to be a lot !

Err... actually, the code is currently waiting for up to 100ms.

The thing is that msleep(5) will wait for a minimum time of 1/CONFIG_HZ.

If CONFIG_HZ is equal to 100 (the minimum), that means that it will
wait for 10 ms. So,

for (i = 0; i < 10; i++, msleep(5)) {
	...
}

Will actually wait up to 10*10ms = 100ms at the worse case. 

The patch is just keeping the maximum timeout equal for all setups, no
matter what's set at CONFIG_HZ.

Arbitrarily changing it to a lower value seems risky, as it may cause
regressions on some boards.

So, I'll just rename the define here, preserving 100ms as timeout.

Regards,
Mauro

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

* Re: [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts
  2014-01-04 10:55 ` [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts Mauro Carvalho Chehab
@ 2014-01-05 20:38   ` Frank Schäfer
  2014-01-05 20:57     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 20:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> In the lack of a better spec, let's assume the timeout
> values compatible with SMBus spec:
> 	http://smbus.org/specs/smbus110.pdf
>
> at chapter 8 - Electrical Characteristics of SMBus devices
>
> Ok, SMBus is a subset of I2C, and not all devices will be
> following it, but the timeout value before this patch was not
> even following the spec.
>
> So, while we don't have a better guess for it, use 35 + 1
> ms as the timeout.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx.h | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index db47c2236ca4..9af19332b0f1 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -183,8 +183,21 @@
>  
>  #define EM28XX_INTERLACED_DEFAULT 1
>  
> -/* time in msecs to wait for i2c xfers to finish */
> -#define EM2800_I2C_XFER_TIMEOUT		20
> +/*
> + * 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 EM2800_I2C_XFER_TIMEOUT		36
>  
>  /* time in msecs to wait for AC97 xfers to finish */
>  #define EM2800_AC97_XFER_TIMEOUT	100
Mauro...
What exactly are you fixing with this patch ?
Which devices are not working with the current timeout value ?

You really shouldn't increase the timout to 172% for all devices based
on such a fragile pure theory.

NACK.




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

* Re: [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-04 10:55 ` [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers Mauro Carvalho Chehab
@ 2014-01-05 20:40   ` Frank Schäfer
  2014-01-06  9:55     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 20:40 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> The proper error code for I2C errors are EREMOTEIO. The em28xx driver
> is using EIO instead.
>
> Replace all occurrences of EIO at em28xx-i2c, in order to fix it.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index 9fa7ed51e5b1..8b35aa51b9bb 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -72,7 +72,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  	if (ret != 2 + len) {
>  		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
>  			    addr, ret);
> -		return (ret < 0) ? ret : -EIO;
> +		return (ret < 0) ? ret : -EREMOTEIO;
>  	}
>  	/* wait for completion */
>  	while (time_is_after_jiffies(timeout)) {
> @@ -91,7 +91,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		msleep(5);
>  	}
>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> -	return -EIO;
> +	return -EREMOTEIO;
>  }
>  
>  /*
> @@ -115,7 +115,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  	if (ret != 2) {
>  		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
>  			    addr, ret);
> -		return (ret < 0) ? ret : -EIO;
> +		return (ret < 0) ? ret : -EREMOTEIO;
>  	}
>  
>  	/* wait for completion */
> @@ -142,7 +142,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  	if (ret != len) {
>  		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
>  			    addr, ret);
> -		return (ret < 0) ? ret : -EIO;
> +		return (ret < 0) ? ret : -EREMOTEIO;
>  	}
>  	for (i = 0; i < len; i++)
>  		buf[i] = buf2[len - 1 - i];
> @@ -162,7 +162,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
>  	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
>  	if (ret == 1)
>  		return 0;
> -	return (ret < 0) ? ret : -EIO;
> +	return (ret < 0) ? ret : -EREMOTEIO;
>  }
>  
>  /*
> @@ -191,7 +191,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		} else {
>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
>  				    len, addr, ret);
> -			return -EIO;
> +			return -EREMOTEIO;
>  		}
>  	}
>  
> @@ -219,7 +219,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	}
>  
>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> -	return -EIO;
> +	return -EREMOTEIO;
>  }
>  
>  /*
> @@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  	}
>  
>  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> -	return -EIO;
> +	return -EREMOTEIO;
>  }
>  
>  /*
> @@ -283,7 +283,7 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
>  	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
>  	if (ret == 1)
>  		return 0;
> -	return (ret < 0) ? ret : -EIO;
> +	return (ret < 0) ? ret : -EREMOTEIO;
>  }
>  
>  /*
> @@ -312,7 +312,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		} else {
>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
>  				    len, addr, ret);
> -			return -EIO;
> +			return -EREMOTEIO;
>  		}
>  	}
>  	/* Check success */
Why the hell -EREMOTEIO ???
See Documentation/i2c/fault-codes.
It's not even listed there !

What are you trying to fix here ?


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

* Re: [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors
  2014-01-04 10:55 ` [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors Mauro Carvalho Chehab
@ 2014-01-05 20:49   ` Frank Schäfer
  2014-01-06 10:37     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 20:49 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> -ENODEV reports a permanent condition where a device is not found,
> and used only during device probing or device removal, as stated
> at  the V4L2 spec:
> 	http://linuxtv.org/downloads/v4l-dvb-apis/gen_errors.html
>
> Except during device detection, this is not the case of I2C
> transfer timeout errors.
>
> So, change them to return -EREMOTEIO instead.
Mauro,

make a step back and think about this again.
What are you doing here ?

You noticed that your HVR-950 device is working unstable for an unknown
reason.
Your specific device seems to be the only one, nobody could reproduce
your issues so far and with the HVR-900 for example (which is nearly
identical) we don't see any errors.

Then you started playing with the em28xx i2c transfer functions and
noticed, that if you repeat the same i2c operations again and again, you
finally have luck and it succeeds.
>From that you draw the conclusion, that i2c status 0x10 can't be a
permanent error and hence 0x10 can't be -ENODEV.
But that's wrong. Your problems could also be caused by
sporadic/temporary circuit failures (such as loose contacts or whatever).
Hardware errors can always happen and they are no reason for not using
-ENODEV.
Whether -ENODEV is the appropriate error code or not depends on the
devices error detection capabilities.

The second assumption you make is that 0x10 means that a timeout occured.
Which timeout are you talking about ?
The only timeout I can think of can happen with devices which use clock
stretching and hold down SCL too long.
In any case you have no evidence for this theory, too.

What we can say for sure ist that 0x10 includes the NACK error case
because this happens when the slave device isn't present / doesn't respond.
But that's all. We have no idea what 0x10 really means in detail.
Maybe it also covers things like clock stretching timeouts or general
SCL and SDA line errors, but we'll never know that without the datasheet.

Interpreting 0x10 as -ENODEV and all other errors as -EIO has been
working fine for ages now.
Changing it based on such fragile theories is no good idea.

NACK from my side.

> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 20 +++++++++-----------
>  1 file changed, 9 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index 8b35aa51b9bb..c3ba8ace5c94 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -81,7 +81,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  			return len;
>  		if (ret == 0x94 + len - 1) {
>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> -			return -ENODEV;
> +			return -EREMOTEIO;
>  		}
>  		if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> @@ -125,7 +125,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  			break;
>  		if (ret == 0x94 + len - 1) {
>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> -			return -ENODEV;
> +			return -EREMOTEIO;
>  		}
>  		if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> @@ -203,7 +203,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		if (ret == 0x10) {
>  			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
>  				    addr);
> -			return -ENODEV;
> +			return -EREMOTEIO;
>  		}
>  		if (ret < 0) {
>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> @@ -249,7 +249,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  	 * bytes if we are on bus B AND there was no write attempt to the
>  	 * specified slave address before AND no device is present at the
>  	 * requested slave address.
> -	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
> +	 * Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
>  	 * spamming the system log on device probing and do nothing here.
>  	 */
>  
> @@ -264,7 +264,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  	}
>  	if (ret == 0x10) {
>  		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> -		return -ENODEV;
> +		return -EREMOTEIO;
>  	}
>  
>  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> @@ -325,7 +325,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		return len;
>  	else if (ret > 0) {
>  		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> -		return -ENODEV;
> +		return -EREMOTEIO;
>  	}
>  
>  	return ret;
> @@ -364,8 +364,6 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	 * bytes if we are on bus B AND there was no write attempt to the
>  	 * specified slave address before AND no device is present at the
>  	 * requested slave address.
> -	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
> -	 * spamming the system log on device probing and do nothing here.
>  	 */
>  
>  	/* Check success */
> @@ -378,7 +376,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		return len;
>  	else if (ret > 0) {
>  		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> -		return -ENODEV;
> +		return -EREMOTEIO;
>  	}
>  
>  	return ret;
> @@ -420,7 +418,7 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
>  		rc = em2800_i2c_check_for_device(dev, addr);
>  	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
>  		rc = em25xx_bus_B_check_for_device(dev, addr);
> -	if (rc == -ENODEV) {
> +	if (rc < 0) {
>  		if (i2c_debug)
>  			printk(" no device\n");
>  	}
> @@ -510,7 +508,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
>  			       addr, msgs[i].len);
>  		if (!msgs[i].len) { /* no len: check only for device presence */
>  			rc = i2c_check_for_device(i2c_bus, addr);
> -			if (rc == -ENODEV) {
> +			if (rc < 0) {
>  				rt_mutex_unlock(&dev->i2c_bus_lock);
>  				return rc;
>  			}


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

* Re: [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages
  2014-01-04 10:55 ` [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages Mauro Carvalho Chehab
@ 2014-01-05 20:54   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 20:54 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> The I2C output messages is too polluted. Clean it a little
> bit, by:
> 	- use the proper core support for memory dumps;
> 	- hide most stuff under the i2c_debug umbrella;
> 	- add the missing KERN_CONT where needed;
> 	- use 2 levels or verbosity. Only the second one
> 	  will show the I2C transfer data.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 94 +++++++++++++++++++----------------
>  1 file changed, 50 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index c3ba8ace5c94..e030e0b7d645 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -41,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
>  
>  static unsigned int i2c_debug;
>  module_param(i2c_debug, int, 0644);
> -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
> +MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
>  
>  /*
>   * em2800_i2c_send_bytes()
> @@ -80,7 +80,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		if (ret == 0x80 + len - 1)
>  			return len;
>  		if (ret == 0x94 + len - 1) {
> -			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> +			if (i2c_debug)
> +				em28xx_warn("R05 returned 0x%02x: I2C timeout",
> +					    ret);
>  			return -EREMOTEIO;
>  		}
>  		if (ret < 0) {
> @@ -90,7 +92,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		}
>  		msleep(5);
>  	}
> -	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> +	if (i2c_debug)
> +		em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>  	return -EREMOTEIO;
>  }
>  
> @@ -124,7 +127,9 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		if (ret == 0x84 + len - 1)
>  			break;
>  		if (ret == 0x94 + len - 1) {
> -			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> +			if (i2c_debug)
> +				em28xx_warn("R05 returned 0x%02x: I2C timeout",
> +					    ret);
>  			return -EREMOTEIO;
>  		}
>  		if (ret < 0) {
> @@ -134,8 +139,11 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>  		}
>  		msleep(5);
>  	}
> -	if (ret != 0x84 + len - 1)
> -		em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
> +	if (ret != 0x84 + len - 1) {
> +		if (i2c_debug)
> +			em28xx_warn("read from i2c device at 0x%x timed out\n",
> +				    addr);
> +	}
>  
>  	/* get the received message */
>  	ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
> @@ -218,7 +226,8 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  		 */
>  	}
>  
> -	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> +	if (i2c_debug)
> +		em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>  	return -EREMOTEIO;
>  }
>  
> @@ -263,7 +272,9 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  		return ret;
>  	}
>  	if (ret == 0x10) {
> -		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> +		if (i2c_debug)
> +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
> +				    addr);
>  		return -EREMOTEIO;
>  	}
>  
> @@ -324,7 +335,9 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	if (!ret)
>  		return len;
>  	else if (ret > 0) {
> -		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> +		if (i2c_debug)
> +			em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
> +				    ret);
>  		return -EREMOTEIO;
>  	}
>  
> @@ -375,7 +388,9 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>  	if (!ret)
>  		return len;
>  	else if (ret > 0) {
> -		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> +		if (i2c_debug)
> +			em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
> +				    ret);
>  		return -EREMOTEIO;
>  	}
>  
> @@ -418,10 +433,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
>  		rc = em2800_i2c_check_for_device(dev, addr);
>  	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
>  		rc = em25xx_bus_B_check_for_device(dev, addr);
> -	if (rc < 0) {
> -		if (i2c_debug)
> -			printk(" no device\n");
> -	}
>  	return rc;
>  }
>  
> @@ -430,7 +441,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
>  {
>  	struct em28xx *dev = i2c_bus->dev;
>  	u16 addr = msg.addr << 1;
> -	int byte, rc = -EOPNOTSUPP;
> +	int rc = -EOPNOTSUPP;
>  
>  	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
>  		rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
> @@ -438,10 +449,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
>  		rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
>  	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
>  		rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
> -	if (i2c_debug) {
> -		for (byte = 0; byte < msg.len; byte++)
> -			printk(" %02x", msg.buf[byte]);
> -	}
>  	return rc;
>  }
>  
> @@ -450,12 +457,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
>  {
>  	struct em28xx *dev = i2c_bus->dev;
>  	u16 addr = msg.addr << 1;
> -	int byte, rc = -EOPNOTSUPP;
> +	int rc = -EOPNOTSUPP;
>  
> -	if (i2c_debug) {
> -		for (byte = 0; byte < msg.len; byte++)
> -			printk(" %02x", msg.buf[byte]);
> -	}
>  	if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
>  		rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
>  	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
> @@ -500,7 +503,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
>  	}
>  	for (i = 0; i < num; i++) {
>  		addr = msgs[i].addr << 1;
> -		if (i2c_debug)
> +		if (i2c_debug > 1)
>  			printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
>  			       dev->name, __func__ ,
>  			       (msgs[i].flags & I2C_M_RD) ? "read" : "write",
> @@ -509,24 +512,33 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
>  		if (!msgs[i].len) { /* no len: check only for device presence */
>  			rc = i2c_check_for_device(i2c_bus, addr);
>  			if (rc < 0) {
> +				if (i2c_debug > 1)
> +					printk(KERN_CONT " no device\n");
>  				rt_mutex_unlock(&dev->i2c_bus_lock);
>  				return rc;
>  			}
>  		} else if (msgs[i].flags & I2C_M_RD) {
>  			/* read bytes */
>  			rc = i2c_recv_bytes(i2c_bus, msgs[i]);
> +
> +			if (i2c_debug > 1 && rc >= 0)
> +				printk(KERN_CONT " %*ph",
> +				       msgs[i].len, msgs[i].buf);
>  		} else {
> +			if (i2c_debug > 1)
> +				printk(KERN_CONT " %*ph",
> +				       msgs[i].len, msgs[i].buf);
> +
>  			/* write bytes */
>  			rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
>  		}
>  		if (rc < 0) {
> -			if (i2c_debug)
> -				printk(" ERROR: %i\n", rc);
> +			if (i2c_debug > 1)
> +				printk(KERN_CONT " ERROR: %i\n", rc);
>  			rt_mutex_unlock(&dev->i2c_bus_lock);
>  			return rc;
> -		}
> -		if (i2c_debug)
> -			printk("\n");
> +		} else if (i2c_debug > 1)
> +			printk(KERN_CONT "\n");
>  	}
>  
>  	rt_mutex_unlock(&dev->i2c_bus_lock);
> @@ -609,7 +621,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
>  	 * calculation and returned device dataset. Simplifies the code a lot,
>  	 * but we might have to deal with multiple sizes in the future !
>  	 */
> -	int i, err;
> +	int err;
>  	struct em28xx_eeprom *dev_config;
>  	u8 buf, *data;
>  
> @@ -640,20 +652,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
>  		goto error;
>  	}
>  
> -	/* Display eeprom content */
> -	for (i = 0; i < len; i++) {
> -		if (0 == (i % 16)) {
> -			if (dev->eeprom_addrwidth_16bit)
> -				em28xx_info("i2c eeprom %04x:", i);
> -			else
> -				em28xx_info("i2c eeprom %02x:", i);
> -		}
> -		printk(" %02x", data[i]);
> -		if (15 == (i % 16))
> -			printk("\n");
> +	if (i2c_debug) {
> +		/* Display eeprom content */
> +		print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
> +			       16, 1, data, len, true);
> +
> +		if (dev->eeprom_addrwidth_16bit)
> +			em28xx_info("eeprom %06x: ... (skipped)\n", 256);
>  	}
> -	if (dev->eeprom_addrwidth_16bit)
> -		em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
>  
>  	if (dev->eeprom_addrwidth_16bit &&
>  	    data[0] == 0x26 && data[3] == 0x00) {

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>



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

* Re: [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts
  2014-01-05 20:38   ` Frank Schäfer
@ 2014-01-05 20:57     ` Mauro Carvalho Chehab
  2014-01-07 17:15       ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 20:57 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 21:38:31 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > In the lack of a better spec, let's assume the timeout
> > values compatible with SMBus spec:
> > 	http://smbus.org/specs/smbus110.pdf
> >
> > at chapter 8 - Electrical Characteristics of SMBus devices
> >
> > Ok, SMBus is a subset of I2C, and not all devices will be
> > following it, but the timeout value before this patch was not
> > even following the spec.
> >
> > So, while we don't have a better guess for it, use 35 + 1
> > ms as the timeout.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx.h | 17 +++++++++++++++--
> >  1 file changed, 15 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> > index db47c2236ca4..9af19332b0f1 100644
> > --- a/drivers/media/usb/em28xx/em28xx.h
> > +++ b/drivers/media/usb/em28xx/em28xx.h
> > @@ -183,8 +183,21 @@
> >  
> >  #define EM28XX_INTERLACED_DEFAULT 1
> >  
> > -/* time in msecs to wait for i2c xfers to finish */
> > -#define EM2800_I2C_XFER_TIMEOUT		20
> > +/*
> > + * 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 EM2800_I2C_XFER_TIMEOUT		36
> >  
> >  /* time in msecs to wait for AC97 xfers to finish */
> >  #define EM2800_AC97_XFER_TIMEOUT	100
> Mauro...
> What exactly are you fixing with this patch ?

It fixes some of the timeouts I noticed here with HVR-950.

> Which devices are not working with the current timeout value ?
> 
> You really shouldn't increase the timout to 172% for all devices based
> on such a fragile pure theory.

It is not fragile. It is the SMBUS spec. It should _at_least_ wait up to
the timeout specified there.

Btw, it is not increasing the timeout. It is actually reducing it.

See, this is the code before the patch:

for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
	     read_timeout -= 5) {
		ret = dev->em28xx_read_reg(dev, 0x05);
		if (ret == 0x84 + len - 1) {
			break;
		} else if (ret == 0x94 + len - 1) {
			return -ENODEV;
		} else if (ret < 0) {
			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
				    ret);
			return ret;
		}
		msleep(5);
	}

msleep(5) actually sleeps up to 20 ms, as the minimal time is the
schedule() time - being 10 ms a typical value (CONFIG_HZ equal to 100). 

So, the current code has a timeout of up to 100 ms.

This patch is actually reducing from 100 ms to 36 ms.

Regards,
Mauro

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

* Re: [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio
  2014-01-04 10:55 ` [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio Mauro Carvalho Chehab
@ 2014-01-05 20:57   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 20:57 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> Instead of allocating transfer buffers with kmalloc() use
> usb_alloc_coherent().
>
> That makes it work also with arm CPUs.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-audio.c | 31 ++++++++++++++++++++-----------
>  1 file changed, 20 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index a6eef06ffdcd..e5120430ec80 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -64,16 +64,22 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
>  
>  	dprintk("Stopping isoc\n");
>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> +		struct urb *urb = dev->adev.urb[i];
> +
>  		if (!irqs_disabled())
> -			usb_kill_urb(dev->adev.urb[i]);
> +			usb_kill_urb(urb);
>  		else
> -			usb_unlink_urb(dev->adev.urb[i]);
> +			usb_unlink_urb(urb);
>  
> -		usb_free_urb(dev->adev.urb[i]);
> -		dev->adev.urb[i] = NULL;
> +		usb_free_coherent(dev->udev,
> +				  urb->transfer_buffer_length,
> +				  dev->adev.transfer_buffer[i],
> +				  urb->transfer_dma);
>  
> -		kfree(dev->adev.transfer_buffer[i]);
>  		dev->adev.transfer_buffer[i] = NULL;
> +
> +		usb_free_urb(urb);
> +		dev->adev.urb[i] = NULL;
>  	}
>  
>  	return 0;
> @@ -176,12 +182,8 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>  		struct urb *urb;
>  		int j, k;
> +		void *buf;
>  
> -		dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
> -		if (!dev->adev.transfer_buffer[i])
> -			return -ENOMEM;
> -
> -		memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
>  		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>  		if (!urb) {
>  			em28xx_errdev("usb_alloc_urb failed!\n");
> @@ -192,10 +194,17 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
>  			return -ENOMEM;
>  		}
>  
> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> +					 &urb->transfer_dma);
> +		if (!buf)
> +			return -ENOMEM;
> +		dev->adev.transfer_buffer[i] = buf;
> +		memset(buf, 0x80, sb_size);
> +
>  		urb->dev = dev->udev;
>  		urb->context = dev;
>  		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> -		urb->transfer_flags = URB_ISO_ASAP;
> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>  		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>  		urb->interval = 1;
>  		urb->complete = em28xx_audio_isocirq;

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-04 10:55 ` [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init Mauro Carvalho Chehab
@ 2014-01-05 21:02   ` Frank Schäfer
  2014-01-05 21:25     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 21:02 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> From: Mauro Carvalho Chehab <mchehab@redhat.com>
Is this line still correct ? ;)

> Instead of allocating/deallocating URBs and transfer buffers
> every time stream is started/stopped, just do it once.
>
> That reduces the memory allocation pressure and makes the
> code that start/stop streaming a way simpler.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Two Signed-off-by lines ? ;)

> ---
>  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
>  1 file changed, 73 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> index e5120430ec80..30ee389a07f0 100644
> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> @@ -3,7 +3,7 @@
>   *
>   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
>   *
> - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
> + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
>   *	- Port to work with the in-kernel driver
>   *	- Cleanups, fixes, alsa-controls, etc.
>   *
> @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
>  			usb_kill_urb(urb);
>  		else
>  			usb_unlink_urb(urb);
> -
> -		usb_free_coherent(dev->udev,
> -				  urb->transfer_buffer_length,
> -				  dev->adev.transfer_buffer[i],
> -				  urb->transfer_dma);
> -
> -		dev->adev.transfer_buffer[i] = NULL;
> -
> -		usb_free_urb(urb);
> -		dev->adev.urb[i] = NULL;
>  	}
>  
>  	return 0;
> @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
>  static int em28xx_init_audio_isoc(struct em28xx *dev)
>  {
>  	int       i, errCode;
> -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>  
>  	dprintk("Starting isoc transfers\n");
>  
> +	/* Start streaming */
>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> -		struct urb *urb;
> -		int j, k;
> -		void *buf;
> -
> -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> -		if (!urb) {
> -			em28xx_errdev("usb_alloc_urb failed!\n");
> -			for (j = 0; j < i; j++) {
> -				usb_free_urb(dev->adev.urb[j]);
> -				kfree(dev->adev.transfer_buffer[j]);
> -			}
> -			return -ENOMEM;
> -		}
> -
> -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> -					 &urb->transfer_dma);
> -		if (!buf)
> -			return -ENOMEM;
> -		dev->adev.transfer_buffer[i] = buf;
> -		memset(buf, 0x80, sb_size);
> -
> -		urb->dev = dev->udev;
> -		urb->context = dev;
> -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> -		urb->interval = 1;
> -		urb->complete = em28xx_audio_isocirq;
> -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> -		urb->transfer_buffer_length = sb_size;
> -
> -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> -			urb->iso_frame_desc[j].offset = k;
> -			urb->iso_frame_desc[j].length =
> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> -		}
> -		dev->adev.urb[i] = urb;
> -	}
> +		memset(dev->adev.transfer_buffer[i], 0x80,
> +		       dev->adev.urb[i]->transfer_buffer_length);
>  
> -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
>  		if (errCode) {
>  			em28xx_errdev("submit of audio urb failed\n");
> @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
>  	.page      = snd_pcm_get_vmalloc_page,
>  };
>  
> +static void em28xx_audio_free_urb(struct em28xx *dev)
> +{
> +	int i;
> +
> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> +		struct urb *urb = dev->adev.urb[i];
> +
> +		if (!dev->adev.urb[i])
> +			continue;
> +
> +		usb_free_coherent(dev->udev,
> +				  urb->transfer_buffer_length,
> +				  dev->adev.transfer_buffer[i],
> +				  urb->transfer_dma);
> +
> +		usb_free_urb(urb);
> +		dev->adev.urb[i] = NULL;
> +		dev->adev.transfer_buffer[i] = NULL;
> +	}
> +}
> +
>  static int em28xx_audio_init(struct em28xx *dev)
>  {
>  	struct em28xx_audio *adev = &dev->adev;
>  	struct snd_pcm      *pcm;
>  	struct snd_card     *card;
>  	static int          devnr;
> -	int                 err;
> +	int                 err, i;
> +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>  
>  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
>  		/* This device does not support the extension (in this case
> @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>  
>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>  			 "Rechberger\n");
> -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> +	printk(KERN_INFO
> +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
>  
>  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
>  			      &card);
> @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
>  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
>  	}
>  
> +	/* Alloc URB and transfer buffers */
> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> +		struct urb *urb;
> +		int j, k;
> +		void *buf;
> +
> +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> +		if (!urb) {
> +			em28xx_errdev("usb_alloc_urb failed!\n");
> +			em28xx_audio_free_urb(dev);
> +			return -ENOMEM;
> +		}
> +		dev->adev.urb[i] = urb;
> +
> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> +					 &urb->transfer_dma);
> +		if (!buf) {
> +			em28xx_errdev("usb_alloc_coherent failed!\n");
> +			em28xx_audio_free_urb(dev);
> +			return -ENOMEM;
> +		}
> +		dev->adev.transfer_buffer[i] = buf;
> +
> +		urb->dev = dev->udev;
> +		urb->context = dev;
> +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> +		urb->interval = 1;
> +		urb->complete = em28xx_audio_isocirq;
> +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> +		urb->transfer_buffer_length = sb_size;
> +
> +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> +			urb->iso_frame_desc[j].offset = k;
> +			urb->iso_frame_desc[j].length =
> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> +		}
> +	}
> +
>  	err = snd_card_register(card);
>  	if (err < 0) {
>  		snd_card_free(card);
> @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
>  		return 0;
>  	}
>  
> +	em28xx_audio_free_urb(dev);
> +
>  	if (dev->adev.sndcard) {
>  		snd_card_free(dev->adev.sndcard);
>  		dev->adev.sndcard = NULL;
I don't get it.
How does this patch reduce the memory allocation pressure ?
You are still allocating the same amount of memory.
The only differences is that you already do this when the device isn't
used yet and don't free it when gets unused again.
IMHO that makes things worse, not better.

And yes, it makes the code that starts/stops streaming a way simpler.
But at the same time it makes the module initialization code the same
amount more complicated.



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

* Re: [PATCH v4 22/22] [media] em28xx: retry read operation if it fails
  2014-01-04 10:55 ` [PATCH v4 22/22] [media] em28xx: retry read operation if it fails Mauro Carvalho Chehab
@ 2014-01-05 21:06   ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-05 21:06 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> I2C read operations can also take some time to happen.
>
> Try again, if it fails with return code different than 0x10
> until timeout.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> ---
>  drivers/media/usb/em28xx/em28xx-i2c.c | 62 +++++++++++++++++++----------------
>  1 file changed, 34 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> index e030e0b7d645..6cd3d909bb3a 100644
> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> @@ -237,6 +237,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>   */
>  static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  {
> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
>  	int ret;
>  
>  	if (len < 1 || len > 64)
> @@ -246,39 +247,44 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>  	 * Zero length reads always succeed, even if no device is connected
>  	 */
>  
> -	/* Read data from i2c device */
> -	ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
> -	if (ret < 0) {
> -		em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
> -			    addr, ret);
> -		return ret;
> -	}
> -	/*
> -	 * NOTE: some devices with two i2c busses have the bad habit to return 0
> -	 * bytes if we are on bus B AND there was no write attempt to the
> -	 * specified slave address before AND no device is present at the
> -	 * requested slave address.
> -	 * Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
> -	 * spamming the system log on device probing and do nothing here.
> -	 */
> +	do {
> +		/* Read data from i2c device */
> +		ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
> +		if (ret < 0) {
> +			em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
> +				    addr, ret);
> +			return ret;
> +		}
> +		/*
> +		 * NOTE: some devices with two i2c busses have the bad habit to return 0
> +		* bytes if we are on bus B AND there was no write attempt to the
> +		* specified slave address before AND no device is present at the
> +		* requested slave address.
> +		* Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
> +		* spamming the system log on device probing and do nothing here.
> +		*/
> +
> +		/* Check success of the i2c operation */
> +		ret = dev->em28xx_read_reg(dev, 0x05);
> +		if (ret == 0) /* success */
> +			return len;
> +		if (ret < 0) {
> +			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> +				    ret);
> +			return ret;
> +		}
> +		if (ret != 0x10)
> +			break;
> +		msleep(5);
> +	} while (time_is_after_jiffies(timeout));
>  
> -	/* Check success of the i2c operation */
> -	ret = dev->em28xx_read_reg(dev, 0x05);
> -	if (ret == 0) /* success */
> -		return len;
> -	if (ret < 0) {
> -		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> -			    ret);
> -		return ret;
> -	}
>  	if (ret == 0x10) {
>  		if (i2c_debug)
> -			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
> +			em28xx_warn("I2C transfer timeout on reading from addr 0x%02x",
>  				    addr);
> -		return -EREMOTEIO;
> +	} else {
> +		em28xx_warn("unknown i2c error (status=%i)\n", ret);
>  	}
> -
> -	em28xx_warn("unknown i2c error (status=%i)\n", ret);
>  	return -EREMOTEIO;
>  }
>  
NACK.
This patch is wrong.
Why are sending the same wrong patches again and again ?

For all we know (USB-Sniffing logs, observed device behavior, how the
same status code is handled for writes...) 0x10 is a _final_ i2c status
code for an i2c operation and i2c adapters must not repeat failed i2c
transfers automatically.
We already discussed this in detail in the private thread and I'm not
going to repeat the same arguments again and again.

Please stop papering over bugs which are outside of the em28xx adapter
driver. Fix the real bugs instead.


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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-05 21:02   ` Frank Schäfer
@ 2014-01-05 21:25     ` Mauro Carvalho Chehab
  2014-01-06 16:25       ` Mauro Carvalho Chehab
  2014-01-07 17:03       ` Frank Schäfer
  0 siblings, 2 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-05 21:25 UTC (permalink / raw)
  To: Frank Schäfer
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 22:02:40 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > From: Mauro Carvalho Chehab <mchehab@redhat.com>
> Is this line still correct ? ;)
> 
> > Instead of allocating/deallocating URBs and transfer buffers
> > every time stream is started/stopped, just do it once.
> >
> > That reduces the memory allocation pressure and makes the
> > code that start/stop streaming a way simpler.
> >
> > Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> Two Signed-off-by lines ? ;)
> 
> > ---
> >  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
> >  1 file changed, 73 insertions(+), 55 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > index e5120430ec80..30ee389a07f0 100644
> > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > @@ -3,7 +3,7 @@
> >   *
> >   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
> >   *
> > - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
> > + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
> >   *	- Port to work with the in-kernel driver
> >   *	- Cleanups, fixes, alsa-controls, etc.
> >   *
> > @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
> >  			usb_kill_urb(urb);
> >  		else
> >  			usb_unlink_urb(urb);
> > -
> > -		usb_free_coherent(dev->udev,
> > -				  urb->transfer_buffer_length,
> > -				  dev->adev.transfer_buffer[i],
> > -				  urb->transfer_dma);
> > -
> > -		dev->adev.transfer_buffer[i] = NULL;
> > -
> > -		usb_free_urb(urb);
> > -		dev->adev.urb[i] = NULL;
> >  	}
> >  
> >  	return 0;
> > @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
> >  static int em28xx_init_audio_isoc(struct em28xx *dev)
> >  {
> >  	int       i, errCode;
> > -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> > -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >  
> >  	dprintk("Starting isoc transfers\n");
> >  
> > +	/* Start streaming */
> >  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > -		struct urb *urb;
> > -		int j, k;
> > -		void *buf;
> > -
> > -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> > -		if (!urb) {
> > -			em28xx_errdev("usb_alloc_urb failed!\n");
> > -			for (j = 0; j < i; j++) {
> > -				usb_free_urb(dev->adev.urb[j]);
> > -				kfree(dev->adev.transfer_buffer[j]);
> > -			}
> > -			return -ENOMEM;
> > -		}
> > -
> > -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> > -					 &urb->transfer_dma);
> > -		if (!buf)
> > -			return -ENOMEM;
> > -		dev->adev.transfer_buffer[i] = buf;
> > -		memset(buf, 0x80, sb_size);
> > -
> > -		urb->dev = dev->udev;
> > -		urb->context = dev;
> > -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> > -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> > -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> > -		urb->interval = 1;
> > -		urb->complete = em28xx_audio_isocirq;
> > -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> > -		urb->transfer_buffer_length = sb_size;
> > -
> > -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> > -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> > -			urb->iso_frame_desc[j].offset = k;
> > -			urb->iso_frame_desc[j].length =
> > -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > -		}
> > -		dev->adev.urb[i] = urb;
> > -	}
> > +		memset(dev->adev.transfer_buffer[i], 0x80,
> > +		       dev->adev.urb[i]->transfer_buffer_length);
> >  
> > -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> >  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
> >  		if (errCode) {
> >  			em28xx_errdev("submit of audio urb failed\n");
> > @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
> >  	.page      = snd_pcm_get_vmalloc_page,
> >  };
> >  
> > +static void em28xx_audio_free_urb(struct em28xx *dev)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > +		struct urb *urb = dev->adev.urb[i];
> > +
> > +		if (!dev->adev.urb[i])
> > +			continue;
> > +
> > +		usb_free_coherent(dev->udev,
> > +				  urb->transfer_buffer_length,
> > +				  dev->adev.transfer_buffer[i],
> > +				  urb->transfer_dma);
> > +
> > +		usb_free_urb(urb);
> > +		dev->adev.urb[i] = NULL;
> > +		dev->adev.transfer_buffer[i] = NULL;
> > +	}
> > +}
> > +
> >  static int em28xx_audio_init(struct em28xx *dev)
> >  {
> >  	struct em28xx_audio *adev = &dev->adev;
> >  	struct snd_pcm      *pcm;
> >  	struct snd_card     *card;
> >  	static int          devnr;
> > -	int                 err;
> > +	int                 err, i;
> > +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> > +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >  
> >  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
> >  		/* This device does not support the extension (in this case
> > @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >  
> >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >  			 "Rechberger\n");
> > -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> > +	printk(KERN_INFO
> > +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
> >  
> >  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
> >  			      &card);
> > @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
> >  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
> >  	}
> >  
> > +	/* Alloc URB and transfer buffers */
> > +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > +		struct urb *urb;
> > +		int j, k;
> > +		void *buf;
> > +
> > +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> > +		if (!urb) {
> > +			em28xx_errdev("usb_alloc_urb failed!\n");
> > +			em28xx_audio_free_urb(dev);
> > +			return -ENOMEM;
> > +		}
> > +		dev->adev.urb[i] = urb;
> > +
> > +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> > +					 &urb->transfer_dma);
> > +		if (!buf) {
> > +			em28xx_errdev("usb_alloc_coherent failed!\n");
> > +			em28xx_audio_free_urb(dev);
> > +			return -ENOMEM;
> > +		}
> > +		dev->adev.transfer_buffer[i] = buf;
> > +
> > +		urb->dev = dev->udev;
> > +		urb->context = dev;
> > +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> > +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> > +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> > +		urb->interval = 1;
> > +		urb->complete = em28xx_audio_isocirq;
> > +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> > +		urb->transfer_buffer_length = sb_size;
> > +
> > +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> > +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> > +			urb->iso_frame_desc[j].offset = k;
> > +			urb->iso_frame_desc[j].length =
> > +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > +		}
> > +	}
> > +
> >  	err = snd_card_register(card);
> >  	if (err < 0) {
> >  		snd_card_free(card);
> > @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >  		return 0;
> >  	}
> >  
> > +	em28xx_audio_free_urb(dev);
> > +
> >  	if (dev->adev.sndcard) {
> >  		snd_card_free(dev->adev.sndcard);
> >  		dev->adev.sndcard = NULL;
> I don't get it.
> How does this patch reduce the memory allocation pressure ?
> You are still allocating the same amount of memory.

True, but it is not de-allocating/reallocating the same amount of
memory every time, for every start/stop trigger. Depending on the
userspace and the amount of available RAM, this could cause memory 
fragmentation.

If you take a look at xHCI logs, you'll see that those operations
are very expensive, and that it occurs too often.

> The only differences is that you already do this when the device isn't
> used yet and don't free it when gets unused again.
> IMHO that makes things worse, not better.

Why is it worse?

FYI, we're currently allocating DVB buffers at the device init too,
due to the memory fragmentation problems. This is actually critical
if you try to use it on an ARM with limited amount of RAM.

> And yes, it makes the code that starts/stops streaming a way simpler.
> But at the same time it makes the module initialization code the same
> amount more complicated.



-- 

Cheers,
Mauro

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

* Re: [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-05 20:40   ` Frank Schäfer
@ 2014-01-06  9:55     ` Mauro Carvalho Chehab
  2014-01-07 17:28       ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-06  9:55 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 21:40:38 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > The proper error code for I2C errors are EREMOTEIO. The em28xx driver
> > is using EIO instead.
> >
> > Replace all occurrences of EIO at em28xx-i2c, in order to fix it.
> >
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-i2c.c | 20 ++++++++++----------
> >  1 file changed, 10 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> > index 9fa7ed51e5b1..8b35aa51b9bb 100644
> > --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> > +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> > @@ -72,7 +72,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  	if (ret != 2 + len) {
> >  		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
> >  			    addr, ret);
> > -		return (ret < 0) ? ret : -EIO;
> > +		return (ret < 0) ? ret : -EREMOTEIO;
> >  	}
> >  	/* wait for completion */
> >  	while (time_is_after_jiffies(timeout)) {
> > @@ -91,7 +91,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  		msleep(5);
> >  	}
> >  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> > -	return -EIO;
> > +	return -EREMOTEIO;
> >  }
> >  
> >  /*
> > @@ -115,7 +115,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  	if (ret != 2) {
> >  		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
> >  			    addr, ret);
> > -		return (ret < 0) ? ret : -EIO;
> > +		return (ret < 0) ? ret : -EREMOTEIO;
> >  	}
> >  
> >  	/* wait for completion */
> > @@ -142,7 +142,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  	if (ret != len) {
> >  		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
> >  			    addr, ret);
> > -		return (ret < 0) ? ret : -EIO;
> > +		return (ret < 0) ? ret : -EREMOTEIO;
> >  	}
> >  	for (i = 0; i < len; i++)
> >  		buf[i] = buf2[len - 1 - i];
> > @@ -162,7 +162,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
> >  	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
> >  	if (ret == 1)
> >  		return 0;
> > -	return (ret < 0) ? ret : -EIO;
> > +	return (ret < 0) ? ret : -EREMOTEIO;
> >  }
> >  
> >  /*
> > @@ -191,7 +191,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		} else {
> >  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
> >  				    len, addr, ret);
> > -			return -EIO;
> > +			return -EREMOTEIO;
> >  		}
> >  	}
> >  
> > @@ -219,7 +219,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  	}
> >  
> >  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> > -	return -EIO;
> > +	return -EREMOTEIO;
> >  }
> >  
> >  /*
> > @@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >  	}
> >  
> >  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> > -	return -EIO;
> > +	return -EREMOTEIO;
> >  }
> >  
> >  /*
> > @@ -283,7 +283,7 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
> >  	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
> >  	if (ret == 1)
> >  		return 0;
> > -	return (ret < 0) ? ret : -EIO;
> > +	return (ret < 0) ? ret : -EREMOTEIO;
> >  }
> >  
> >  /*
> > @@ -312,7 +312,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		} else {
> >  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
> >  				    len, addr, ret);
> > -			return -EIO;
> > +			return -EREMOTEIO;
> >  		}
> >  	}
> >  	/* Check success */
> Why the hell -EREMOTEIO ???
> See Documentation/i2c/fault-codes.
> It's not even listed there !

> 
> What are you trying to fix here ?

This is not a fixup patch.

The idea of this path is to make em28xx more compliant with the Kernel
error codes. 

As em28xx was the first USB media driver, it doesn't follow the best 
standards, despite all efforts we've made back in 2005, when the driver
was merged, in order to follow the Kernel rules. We eventually fixed
several things along the time, but we didn't took much care to fix the
I2C error codes so far.

Now that we're taking care of it, we should do it right.

However, you're actually right here.

Before 2011, all I2C drivers under drivers/i2c used to return EREMOTEIO,
and the media drivers were moving to this error code since then.

But it seems that we missed a series of patches that moved I2C away from
EREMOTEIO:
	http://www.spinics.net/lists/linux-i2c/msg06395.html
	https://www.mail-archive.com/linux-i2c@vger.kernel.org/msg04819.html

I'll rewrite this patch to return the right error codes, according with
Documentation/i2c/fault-codes.

It seems that the proper return codes are:

	- ETIMEDOUT - when reg 05 returns 0x10
	- ENXIO - when the device is not temporarily not responding
		  (e. g. reg 05 returning something not 0x10 or 0x00)
	- EBUSY - when reg 05 returns 0x20 on em2874 and upper [1]
	- EIO - for generic I/O errors that don't fit into the above.

[1] According with a post that Devin made on IRC sometime ago, bit 5
indicates that the I2C is busy when the master tries to use it, but it
exists only on em2874 (and likely newer chips).

Cheers,
Mauro

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

* Re: [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors
  2014-01-05 20:49   ` Frank Schäfer
@ 2014-01-06 10:37     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-06 10:37 UTC (permalink / raw)
  To: Frank Schäfer
  Cc: Devin Heitmueller, Linux Media Mailing List, Mauro Carvalho Chehab

Em Sun, 05 Jan 2014 21:49:57 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > -ENODEV reports a permanent condition where a device is not found,
> > and used only during device probing or device removal, as stated
> > at  the V4L2 spec:
> > 	http://linuxtv.org/downloads/v4l-dvb-apis/gen_errors.html
> >
> > Except during device detection, this is not the case of I2C
> > transfer timeout errors.
> >
> > So, change them to return -EREMOTEIO instead.
> Mauro,
> 
> make a step back and think about this again.
> What are you doing here ?
> 
> You noticed that your HVR-950 device is working unstable for an unknown
> reason.
> Your specific device seems to be the only one, nobody could reproduce
> your issues so far and with the HVR-900 for example (which is nearly
> identical) we don't see any errors.
> 
> Then you started playing with the em28xx i2c transfer functions and
> noticed, that if you repeat the same i2c operations again and again, you
> finally have luck and it succeeds.
> From that you draw the conclusion, that i2c status 0x10 can't be a
> permanent error and hence 0x10 can't be -ENODEV.
> But that's wrong. Your problems could also be caused by
> sporadic/temporary circuit failures (such as loose contacts or whatever).
> Hardware errors can always happen and they are no reason for not using
> -ENODEV.

There is: it violates both V4L2 API and I2C error fault code. -ENODEV should
only be used on device probing time, according with
Documentation/i2c/fault-codes [1]:
	ENODEV
		Returned by driver probe() methods. 

[1] V4L2 spec also allows using it at device removal (e. g. when the
USB device is physically disconnected).

According with I2C fault codes, the proper error for a timeout is ETIMEDOUT:

	ETIMEDOUT
		This is returned by drivers when an operation took too much
		time, and was aborted before it completed.

		SMBus adapters may return it when an operation took more
		time than allowed by the SMBus specification; for example,
		when a slave stretches clocks too far.  I2C has no such
		timeouts, but it's normal for I2C adapters to impose some
		arbitrary limits (much longer than SMBus!) too.

> Whether -ENODEV is the appropriate error code or not depends on the
> devices error detection capabilities.

No, it depends if the code is called during probing time or not. Outside
device probing, an I2C driver should _never_ return ENODEV.

> The second assumption you make is that 0x10 means that a timeout occured.
> Which timeout are you talking about ?
> The only timeout I can think of can happen with devices which use clock
> stretching and hold down SCL too long.
> In any case you have no evidence for this theory, too.
> What we can say for sure ist that 0x10 includes the NACK error case
> because this happens when the slave device isn't present / doesn't respond.

You can't affirm that the device isn't present.

Let remind a conversation we had with Devin at #v4l back on Seg 27 Mai 2013,
where he checked those error codes on his datasheets:

(16:23:05) mchehab: btw, talking about missing data, register 0x05 is also not documented, although it is one of the most used register
(16:24:11) frankschaefer: This is definitely no kernel bloating.
(16:24:29) devinheitmueller: 5[5] is busy and 5[4] is aborted. Last I checked the driver implemented them properly so I didn't see a need for anything additional.
(16:25:17) frankschaefer: "busy" and "aborted" what ?
(16:25:22) devinheitmueller: i2c.
(16:25:40) devinheitmueller: Oh wait, busy was only on em2874. But aborted was on both versions of the chip.

Again, according with Documentation/i2c/fault-codes, for an I2C
aborted I/O, the error code is ETIMEDOUT.

> But that's all. We have no idea what 0x10 really means in detail.
> Maybe it also covers things like clock stretching timeouts or general
> SCL and SDA line errors, but we'll never know that without the datasheet.
> 
> Interpreting 0x10 as -ENODEV and all other errors as -EIO has been
> working fine for ages now.

When originally written, the only case where -ENODEV was returned was 
during I2C device probing time (I2C reads or writes with size equal to 
zero).

Latter patches corrupted it, and added -ENODEV to be returned outsize
the probing time.

> Changing it based on such fragile theories is no good idea.

The API specs is not a fragile theory. Is a document to be followed,
to warrant compliance.

> NACK from my side.
> 
> > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > ---
> >  drivers/media/usb/em28xx/em28xx-i2c.c | 20 +++++++++-----------
> >  1 file changed, 9 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> > index 8b35aa51b9bb..c3ba8ace5c94 100644
> > --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> > +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> > @@ -81,7 +81,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  			return len;
> >  		if (ret == 0x94 + len - 1) {
> >  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> > -			return -ENODEV;
> > +			return -EREMOTEIO;
> >  		}
> >  		if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > @@ -125,7 +125,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >  			break;
> >  		if (ret == 0x94 + len - 1) {
> >  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
> > -			return -ENODEV;
> > +			return -EREMOTEIO;
> >  		}
> >  		if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > @@ -203,7 +203,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		if (ret == 0x10) {
> >  			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
> >  				    addr);
> > -			return -ENODEV;
> > +			return -EREMOTEIO;
> >  		}
> >  		if (ret < 0) {
> >  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > @@ -249,7 +249,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >  	 * bytes if we are on bus B AND there was no write attempt to the
> >  	 * specified slave address before AND no device is present at the
> >  	 * requested slave address.
> > -	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
> > +	 * Anyway, the next check will fail with -EREMOTEIO in this case, so avoid
> >  	 * spamming the system log on device probing and do nothing here.
> >  	 */
> >  
> > @@ -264,7 +264,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >  	}
> >  	if (ret == 0x10) {
> >  		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
> > -		return -ENODEV;
> > +		return -EREMOTEIO;
> >  	}
> >  
> >  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> > @@ -325,7 +325,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		return len;
> >  	else if (ret > 0) {
> >  		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> > -		return -ENODEV;
> > +		return -EREMOTEIO;
> >  	}
> >  
> >  	return ret;
> > @@ -364,8 +364,6 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  	 * bytes if we are on bus B AND there was no write attempt to the
> >  	 * specified slave address before AND no device is present at the
> >  	 * requested slave address.
> > -	 * Anyway, the next check will fail with -ENODEV in this case, so avoid
> > -	 * spamming the system log on device probing and do nothing here.
> >  	 */
> >  
> >  	/* Check success */
> > @@ -378,7 +376,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >  		return len;
> >  	else if (ret > 0) {
> >  		em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout", ret);
> > -		return -ENODEV;
> > +		return -EREMOTEIO;
> >  	}
> >  
> >  	return ret;
> > @@ -420,7 +418,7 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
> >  		rc = em2800_i2c_check_for_device(dev, addr);
> >  	else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
> >  		rc = em25xx_bus_B_check_for_device(dev, addr);
> > -	if (rc == -ENODEV) {
> > +	if (rc < 0) {
> >  		if (i2c_debug)
> >  			printk(" no device\n");
> >  	}
> > @@ -510,7 +508,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
> >  			       addr, msgs[i].len);
> >  		if (!msgs[i].len) { /* no len: check only for device presence */
> >  			rc = i2c_check_for_device(i2c_bus, addr);
> > -			if (rc == -ENODEV) {
> > +			if (rc < 0) {
> >  				rt_mutex_unlock(&dev->i2c_bus_lock);
> >  				return rc;
> >  			}
> 


-- 

Cheers,
Mauro

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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-05 21:25     ` Mauro Carvalho Chehab
@ 2014-01-06 16:25       ` Mauro Carvalho Chehab
  2014-01-07 17:03       ` Frank Schäfer
  1 sibling, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-06 16:25 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List

Em Sun, 05 Jan 2014 19:25:57 -0200
Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:

> Em Sun, 05 Jan 2014 22:02:40 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> 
> > Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> > > From: Mauro Carvalho Chehab <mchehab@redhat.com>
> > Is this line still correct ? ;)
> > 
> > > Instead of allocating/deallocating URBs and transfer buffers
> > > every time stream is started/stopped, just do it once.
> > >
> > > That reduces the memory allocation pressure and makes the
> > > code that start/stop streaming a way simpler.
> > >
> > > Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> > > Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> > Two Signed-off-by lines ? ;)
> > 
> > > ---
> > >  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
> > >  1 file changed, 73 insertions(+), 55 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> > > index e5120430ec80..30ee389a07f0 100644
> > > --- a/drivers/media/usb/em28xx/em28xx-audio.c
> > > +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> > > @@ -3,7 +3,7 @@
> > >   *
> > >   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
> > >   *
> > > - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
> > > + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
> > >   *	- Port to work with the in-kernel driver
> > >   *	- Cleanups, fixes, alsa-controls, etc.
> > >   *
> > > @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
> > >  			usb_kill_urb(urb);
> > >  		else
> > >  			usb_unlink_urb(urb);
> > > -
> > > -		usb_free_coherent(dev->udev,
> > > -				  urb->transfer_buffer_length,
> > > -				  dev->adev.transfer_buffer[i],
> > > -				  urb->transfer_dma);
> > > -
> > > -		dev->adev.transfer_buffer[i] = NULL;
> > > -
> > > -		usb_free_urb(urb);
> > > -		dev->adev.urb[i] = NULL;
> > >  	}
> > >  
> > >  	return 0;
> > > @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
> > >  static int em28xx_init_audio_isoc(struct em28xx *dev)
> > >  {
> > >  	int       i, errCode;
> > > -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> > > -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > >  
> > >  	dprintk("Starting isoc transfers\n");
> > >  
> > > +	/* Start streaming */
> > >  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > > -		struct urb *urb;
> > > -		int j, k;
> > > -		void *buf;
> > > -
> > > -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> > > -		if (!urb) {
> > > -			em28xx_errdev("usb_alloc_urb failed!\n");
> > > -			for (j = 0; j < i; j++) {
> > > -				usb_free_urb(dev->adev.urb[j]);
> > > -				kfree(dev->adev.transfer_buffer[j]);
> > > -			}
> > > -			return -ENOMEM;
> > > -		}
> > > -
> > > -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> > > -					 &urb->transfer_dma);
> > > -		if (!buf)
> > > -			return -ENOMEM;
> > > -		dev->adev.transfer_buffer[i] = buf;
> > > -		memset(buf, 0x80, sb_size);
> > > -
> > > -		urb->dev = dev->udev;
> > > -		urb->context = dev;
> > > -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> > > -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> > > -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> > > -		urb->interval = 1;
> > > -		urb->complete = em28xx_audio_isocirq;
> > > -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> > > -		urb->transfer_buffer_length = sb_size;
> > > -
> > > -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> > > -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> > > -			urb->iso_frame_desc[j].offset = k;
> > > -			urb->iso_frame_desc[j].length =
> > > -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > > -		}
> > > -		dev->adev.urb[i] = urb;
> > > -	}
> > > +		memset(dev->adev.transfer_buffer[i], 0x80,
> > > +		       dev->adev.urb[i]->transfer_buffer_length);
> > >  
> > > -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > >  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
> > >  		if (errCode) {
> > >  			em28xx_errdev("submit of audio urb failed\n");
> > > @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
> > >  	.page      = snd_pcm_get_vmalloc_page,
> > >  };
> > >  
> > > +static void em28xx_audio_free_urb(struct em28xx *dev)
> > > +{
> > > +	int i;
> > > +
> > > +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > > +		struct urb *urb = dev->adev.urb[i];
> > > +
> > > +		if (!dev->adev.urb[i])
> > > +			continue;
> > > +
> > > +		usb_free_coherent(dev->udev,
> > > +				  urb->transfer_buffer_length,
> > > +				  dev->adev.transfer_buffer[i],
> > > +				  urb->transfer_dma);
> > > +
> > > +		usb_free_urb(urb);
> > > +		dev->adev.urb[i] = NULL;
> > > +		dev->adev.transfer_buffer[i] = NULL;
> > > +	}
> > > +}
> > > +
> > >  static int em28xx_audio_init(struct em28xx *dev)
> > >  {
> > >  	struct em28xx_audio *adev = &dev->adev;
> > >  	struct snd_pcm      *pcm;
> > >  	struct snd_card     *card;
> > >  	static int          devnr;
> > > -	int                 err;
> > > +	int                 err, i;
> > > +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> > > +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > >  
> > >  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
> > >  		/* This device does not support the extension (in this case
> > > @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> > >  
> > >  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> > >  			 "Rechberger\n");
> > > -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> > > +	printk(KERN_INFO
> > > +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
> > >  
> > >  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
> > >  			      &card);
> > > @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
> > >  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
> > >  	}
> > >  
> > > +	/* Alloc URB and transfer buffers */
> > > +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> > > +		struct urb *urb;
> > > +		int j, k;
> > > +		void *buf;
> > > +
> > > +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> > > +		if (!urb) {
> > > +			em28xx_errdev("usb_alloc_urb failed!\n");
> > > +			em28xx_audio_free_urb(dev);
> > > +			return -ENOMEM;
> > > +		}
> > > +		dev->adev.urb[i] = urb;
> > > +
> > > +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> > > +					 &urb->transfer_dma);
> > > +		if (!buf) {
> > > +			em28xx_errdev("usb_alloc_coherent failed!\n");
> > > +			em28xx_audio_free_urb(dev);
> > > +			return -ENOMEM;
> > > +		}
> > > +		dev->adev.transfer_buffer[i] = buf;
> > > +
> > > +		urb->dev = dev->udev;
> > > +		urb->context = dev;
> > > +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> > > +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> > > +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> > > +		urb->interval = 1;
> > > +		urb->complete = em28xx_audio_isocirq;
> > > +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> > > +		urb->transfer_buffer_length = sb_size;
> > > +
> > > +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> > > +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> > > +			urb->iso_frame_desc[j].offset = k;
> > > +			urb->iso_frame_desc[j].length =
> > > +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> > > +		}
> > > +	}
> > > +
> > >  	err = snd_card_register(card);
> > >  	if (err < 0) {
> > >  		snd_card_free(card);
> > > @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
> > >  		return 0;
> > >  	}
> > >  
> > > +	em28xx_audio_free_urb(dev);
> > > +
> > >  	if (dev->adev.sndcard) {
> > >  		snd_card_free(dev->adev.sndcard);
> > >  		dev->adev.sndcard = NULL;
> > I don't get it.
> > How does this patch reduce the memory allocation pressure ?
> > You are still allocating the same amount of memory.
> 
> True, but it is not de-allocating/reallocating the same amount of
> memory every time, for every start/stop trigger. Depending on the
> userspace and the amount of available RAM, this could cause memory 
> fragmentation.

Btw, this fixes a real bug with em2860 (Kworld U305): the time spent
with URB deallocation/reallocation every time that the trigger hits
makes it to loose audio frames.

With this patch, the sound becomes smooth, and it stops with the
periodic ALSA overrun errors that happen after channel tuning.

Regards,
-- 

Cheers,
Mauro

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

* Re: [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-05 12:56     ` Mauro Carvalho Chehab
  2014-01-05 15:18       ` Mauro Carvalho Chehab
@ 2014-01-06 17:38       ` Frank Schäfer
  1 sibling, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-06 17:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 13:56, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 11:47:00 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> Now that all analog-specific code are at em28xx-video, convert
>>> it into an em28xx extension and load it as a separate module.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/Kconfig         |  6 ++-
>>>  drivers/media/usb/em28xx/Makefile        |  5 ++-
>>>  drivers/media/usb/em28xx/em28xx-camera.c |  1 +
>>>  drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
>>>  drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
>>>  drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
>>>  drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
>>>  drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
>>>  drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
>>>  9 files changed, 107 insertions(+), 80 deletions(-)
>>>  create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h
>>>
>>> diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
>>> index d6ba514d31eb..838fc9dbb747 100644
>>> --- a/drivers/media/usb/em28xx/Kconfig
>>> +++ b/drivers/media/usb/em28xx/Kconfig
>>> @@ -1,8 +1,12 @@
>>>  config VIDEO_EM28XX
>>> -	tristate "Empia EM28xx USB video capture support"
>>> +	tristate "Empia EM28xx USB devices support"
>>>  	depends on VIDEO_DEV && I2C
>>>  	select VIDEO_TUNER
>>>  	select VIDEO_TVEEPROM
>>> +
>>> +config VIDEO_EM28XX_V4L2
>>> +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
>>> +	depends on VIDEO_EM28XX && I2C
>> VIDEO_EM28XX already depends on I2C.
>>
>>>  	select VIDEOBUF2_VMALLOC
>>>  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
>>>  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
>>> diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
>>> index ad6d48557940..3f850d5063d0 100644
>>> --- a/drivers/media/usb/em28xx/Makefile
>>> +++ b/drivers/media/usb/em28xx/Makefile
>>> @@ -1,10 +1,11 @@
>>> -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
>>> -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
>>> +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
>>>  
>>> +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
>>>  em28xx-alsa-objs := em28xx-audio.o
>>>  em28xx-rc-objs := em28xx-input.o
>>>  
>>>  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
>>> +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
>>>  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
>>>  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
>>>  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
>>> index d666741797d4..c29f5c4e7b40 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
>>> @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
>>>  
>>>  	return ret;
>>>  }
>>> +EXPORT_SYMBOL_GPL(em28xx_init_camera);
>> em28xx-camera should also be part of the em28xx-v4l module.
> I tried that. Moving em28xx-camera to em28xx-v4l would cause a recursive
> dependency, due to the camera probing logic, that should be called by
> em28xx-cards.c.
I see...

> Moving that probing part to em28xx-v4l is too complex, due to the code
> that detects the board.
>
> One solution would be to break em28xx-camera into two parts: the detection
> code, to be merged with the core, and the sensor part, to be merged with
> em28xx-v4l, but that sounds ugly.
>
> Other solution would be to use something like the dvb_attach() macro,
> to avoid the recursive dependency, but that would be a dirty solution.
Another solution would be to move the sensor probing to em28xx-v4l, too.
Then we need to rely on dev->board.is_webcam to load the v4l module.
This would of course also require to split the board hint stuff.
Even more ugly I think...

> As the code there is not big, the amount of overhead of having everything
> at em28xx-core is not high. So, I opted to keep the simplest path here,
> avoiding the risk of breaking something with a complex changeset.
I agree.

>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>> index 175cd776e0a1..938daaabd8e0 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>> @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
>>>  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
>>>  	},
>>>  };
>>> +EXPORT_SYMBOL_GPL(em28xx_boards);
>>> +
>>>  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
>>>  
>>>  /* table of devices that work with this driver */
>>> @@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
>>>  				"tuner", dev->tuner_addr, NULL);
>>>  		}
>>>  	}
>>> -
>>> -	em28xx_tuner_setup(dev);
>>> -
>>> -	em28xx_init_camera(dev);
>>>  }
>> Here you are fixing half of the em28xx_card_setup() oopses which you've
>> introduced with patch 3/22.
>> This needs to be done together with patch 5/22 before patch 3/22.
> Ok.
>
>>> @@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
>>>  	em28xx_init_extension(dev);
>>>  
>>>  #if defined(CONFIG_MODULES) && defined(MODULE)
>>> +	if (dev->has_video)
>>> +		request_module("em28xx-v4l");
>>>  	if (dev->has_audio_class)
>>>  		request_module("snd-usb-audio");
>>>  	else if (dev->has_alsa_audio)
>>>  		request_module("em28xx-alsa");
>>> -
>>>  	if (dev->board.has_dvb)
>>>  		request_module("em28xx-dvb");
>>>  	if (dev->board.buttons ||
>>> @@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
>>>  {
>>>  	/*FIXME: I2C IR should be disconnected */
>>>  
>>> -	em28xx_release_analog_resources(dev);
>>> -
>>>  	if (dev->def_i2c_bus)
>>>  		em28xx_i2c_unregister(dev, 1);
>>>  	em28xx_i2c_unregister(dev, 0);
>>>  	if (dev->clk)
>>>  		v4l2_clk_unregister_fixed(dev->clk);
>>>  
>>> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>> -
>>> -	v4l2_device_unregister(&dev->v4l2_dev);
>>> -
>>>  	usb_put_dev(dev->udev);
>>>  
>>>  	/* Mark device as unused */
>>> @@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>  	if (retval < 0) {
>>>  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
>>>  			__func__, retval);
>>> -		goto unregister_dev;
>>> +		return retval;
>>>  	}
>>>  
>>>  	/* register i2c bus 1 */
>>> @@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>  		if (retval < 0) {
>>>  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
>>>  				__func__, retval);
>>> -			goto unregister_dev;
>>> +			return retval;
>>>  		}
>>>  	}
>> Hmm... if registering of bus 1 fails, we need to unregister bus 0.
>> But that's an old bug which we can fix later...
> Good point. Yes, this should be on a separate patch.
>
>>>  	/* Do board specific init and eeprom reading */
>>>  	em28xx_card_setup(dev);
>>>  
>>> -	retval = em28xx_register_analog_devices(dev);
>>> -	if (retval < 0) {
>>> -		goto fail;
>>> -	}
>>> -
>>>  	return 0;
>>> -
>>> -fail:
>>> -	if (dev->def_i2c_bus)
>>> -		em28xx_i2c_unregister(dev, 1);
>>> -	em28xx_i2c_unregister(dev, 0);
>>> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>> -
>>> -unregister_dev:
>>> -	v4l2_device_unregister(&dev->v4l2_dev);
>>> -
>>> -	return retval;
>>>  }
>>>  
>>>  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
>>> @@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>  	dev->alt   = -1;
>>>  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
>>>  	dev->has_alsa_audio = has_audio;
>>> +	dev->has_video = has_video;
>>>  	dev->audio_ifnum = ifnum;
>>>  
>>>  	/* Checks if audio is provided by some interface */
>>> @@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>  
>>>  	/* allocate device struct */
>>>  	mutex_init(&dev->lock);
>>> -	mutex_lock(&dev->lock);
>>>  	retval = em28xx_init_dev(dev, udev, interface, nr);
>>>  	if (retval) {
>>> -		goto unlock_and_free;
>>> +		goto err_free;
>>>  	}
>>>  
>>>  	if (usb_xfer_mode < 0) {
>>> @@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>  		if (retval) {
>>>  			printk(DRIVER_NAME
>>>  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
>>> -			goto unlock_and_free;
>>> +			goto err_free;
>>>  		}
>>>  	}
>>>  
>>> @@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>  	/* Should be the last thing to do, to avoid newer udev's to
>>>  	   open the device before fully initializing it
>>>  	 */
>>> -	mutex_unlock(&dev->lock);
>>>  
>>>  	return 0;
>>>  
>>> -unlock_and_free:
>>> -	mutex_unlock(&dev->lock);
>>> -
>>>  err_free:
>>>  	kfree(dev->alt_max_pkt_size_isoc);
>>>  	kfree(dev);
>>> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
>>> index 3012912d2997..1113d4e107d8 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-core.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-core.c
>>> @@ -33,6 +33,18 @@
>>>  
>>>  #include "em28xx.h"
>>>  
>>> +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
>>> +		      "Markus Rechberger <mrechberger@gmail.com>, " \
>>> +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
>>> +		      "Sascha Sommer <saschasommer@freenet.de>"
>>> +
>>> +#define DRIVER_DESC         "Empia em28xx based USB core driver"
>>> +
>>> +MODULE_AUTHOR(DRIVER_AUTHOR);
>>> +MODULE_DESCRIPTION(DRIVER_DESC);
>>> +MODULE_LICENSE("GPL");
>>> +MODULE_VERSION(EM28XX_VERSION);
>>> +
>>>  /* #define ENABLE_DEBUG_ISOC_FRAMES */
>>>  
>>>  static unsigned int core_debug;
>>> diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
>>> new file mode 100644
>>> index 000000000000..bce438691e0e
>>> --- /dev/null
>>> +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
>>> @@ -0,0 +1,20 @@
>>> +/*
>>> +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
>>> +		    video capture devices
>> The information about supported chips is outdated everywhere in the driver,
>> but if you introduce a new header file it should really be up to date.
>> Just talk about EM27xx/EM28xx.
> We need to do a cleanup on all those headers: they don't follow Kernel
> CodingStyle and the old headers use my previous email.
>
> For the sake of keeping a coherency, I deliberately opted to just use the
> same way as the other headers.
>
> My plan is to write a patch series fixing this and other CodingStyle
> issues on em28xx after merging this changeset.
Ok, fine.

>
>>> +
>>> +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> +
>>> +   This program is free software; you can redistribute it and/or modify
>>> +   it under the terms of the GNU General Public License as published by
>>> +   the Free Software Foundation version 2 of the License.
>>> +
>>> +   This program is distributed in the hope that it will be useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> +   GNU General Public License for more details.
>>> + */
>>> +
>>> +
>>> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
>>> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
>>> +extern struct vb2_ops em28xx_vbi_qops;
>>> diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
>>> index 39f39c527c13..db3d655600df 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-vbi.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
>>> @@ -27,6 +27,7 @@
>>>  #include <linux/init.h>
>>>  
>>>  #include "em28xx.h"
>>> +#include "em28xx-v4l.h"
>>>  
>>>  static unsigned int vbibufs = 5;
>>>  module_param(vbibufs, int, 0644);
>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>> index 85284626dbd6..d615bff8ac09 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>> @@ -38,6 +38,7 @@
>>>  #include <linux/slab.h>
>>>  
>>>  #include "em28xx.h"
>>> +#include "em28xx-v4l.h"
>>>  #include <media/v4l2-common.h>
>>>  #include <media/v4l2-ioctl.h>
>>>  #include <media/v4l2-event.h>
>>> @@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
>>>  	},
>>>  };
>>>  
>>> +static int em28xx_vbi_supported(struct em28xx *dev);
>>> +
>> Or move em28xx_vbi_supported() before em28xx_set_outfmt() and
>> em28xx_resolution_set() again.
>> If you had not changed the functions order in patch 1/22, this wouldn't
>> be necessary.
> True. I'll put an extra cleanup patch to remove this reference on the
> CodingStyle cleanup patchset I'm planning to do.
>
>>>  /*
>>>   * em28xx_wake_i2c()
>>>   * configure i2c attached devices
>>>   */
>>> -void em28xx_wake_i2c(struct em28xx *dev)
>>> +static void em28xx_wake_i2c(struct em28xx *dev)
>>>  {
>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
>>> @@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
>>>  }
>>>  
>>> -int em28xx_colorlevels_set_default(struct em28xx *dev)
>>> +static int em28xx_colorlevels_set_default(struct em28xx *dev)
>>>  {
>>>  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
>>>  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
>>> @@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
>>>  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
>>>  }
>>>  
>>> -int em28xx_set_outfmt(struct em28xx *dev)
>>> +static int em28xx_set_outfmt(struct em28xx *dev)
>>>  {
>>>  	int ret;
>>>  	u8 fmt, vinctrl;
>>> @@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
>>>  }
>>>  
>>>  /* FIXME: this only function read values from dev */
>>> -int em28xx_resolution_set(struct em28xx *dev)
>>> +static int em28xx_resolution_set(struct em28xx *dev)
>>>  {
>>>  	int width, height;
>>>  	width = norm_maxw(dev);
>>> @@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
>>>  	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
>>>  }
>>>  
>>> -int em28xx_vbi_supported(struct em28xx *dev)
>>> +static int em28xx_vbi_supported(struct em28xx *dev)
>>>  {
>>>  	/* Modprobe option to manually disable */
>>>  	if (disable_vbi == 1)
>>> @@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
>>>  }
>>>  
>>>  /* Set USB alternate setting for analog video */
>>> -int em28xx_set_alternate(struct em28xx *dev)
>>> +static int em28xx_set_alternate(struct em28xx *dev)
>>>  {
>>>  	int errCode;
>>>  	int i;
>>> @@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
>>>  	.wait_finish    = vb2_ops_wait_finish,
>>>  };
>>>  
>>> -int em28xx_vb2_setup(struct em28xx *dev)
>>> +static int em28xx_vb2_setup(struct em28xx *dev)
>>>  {
>>>  	int rc;
>>>  	struct vb2_queue *q;
>>> @@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
>>>  	em28xx_audio_analog_set(dev);
>>>  }
>>>  
>>> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>>> +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>>>  {
>>>  	struct em28xx *dev = priv;
>>>  
>>> @@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
>>>  		reg->val = ret;
>>>  	} else {
>>>  		__le16 val = 0;
>>> -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>>> +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>>>  						   reg->reg, (char *)&val, 2);
>> Urgh... is it really necessary to start using these pointers again ?
>> Ok... keep it as is, I'll send a patch to clean this up later.
> This is one of the few places where we weren't using those pointers:
>
> $ git grep em28xx_read_reg_req_len drivers/media/usb/em28xx/
> drivers/media/usb/em28xx/em28xx-cards.c:  dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
> drivers/media/usb/em28xx/em28xx-core.c:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
> drivers/media/usb/em28xx/em28xx-core.c:   ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
> drivers/media/usb/em28xx/em28xx-core.c:   ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
> drivers/media/usb/em28xx/em28xx-i2c.c:            ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
> drivers/media/usb/em28xx/em28xx-video.c:          ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> drivers/media/usb/em28xx/em28xx.h:        int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
> drivers/media/usb/em28xx/em28xx.h:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
It seems like your "grep" works better than mine... ;)

> For the sake of coherency, we should either use one or the other way.
Agreed.

>
>>>  		if (ret < 0)
>>>  			return ret;
>>> @@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
>>>  }
>>>  
>>>  /*
>>> - * em28xx_realease_resources()
>>> + * em28xx_v4l2_fini()
>>>   * unregisters the v4l2,i2c and usb devices
>>>   * called when the device gets disconected or at module unload
>>>  */
>>> -void em28xx_release_analog_resources(struct em28xx *dev)
>>> +static int em28xx_v4l2_fini(struct em28xx *dev)
>>>  {
>>>  
>>>  	/*FIXME: I2C IR should be disconnected */
>>> @@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
>>>  			video_device_release(dev->vdev);
>>>  		dev->vdev = NULL;
>>>  	}
>>> +
>>> +	return 0;
>>>  }
>>>  
>>>  /*
>>> @@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
>>>  	if (dev->users == 1) {
>>>  		/* the device is already disconnect,
>>>  		   free the remaining resources */
>>> +
>>>  		if (dev->disconnected) {
>>> -			em28xx_release_resources(dev);
>> Who releases the resources now ?
> This is tricky.
It is. And this part of the code really looks fishy.

> The hole idea is that em28xx-v4l release the resources allocated for V4L
> only, and not all resources, the same way as the other em28xx modules
> do.
>
> If you take a look at the original em28xx_release_resources(), what it does
> is to call this function, and then to de-allocate and unregister v4l2:
>
> 			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> 			v4l2_device_unregister(&dev->v4l2_dev);
>
> after that, it deallocates the rest of allocated data.
>
> Now, em28xx_release_resources() is only called when em28xx is removed
> from memory or when the device is removed.
>
> The code there first calls em28xx_close_extension(dev). So, at device
> removal, em28xx-v4l will release the V4L2 specific resources, and
> em28xx_release_resources() will drop the common dev struct.
Up to now, em28xx_release_resources() was called after the last close.
If you remove this call, the resources are never released.
Or am I missing another place where this function is called ?

> I suspect that it might still be a bug there, but, if so, this bug is 
> also present on em28xx-dvb, em28xx-alsa and em28xx-rc: what happens if 
> the device is removed while the file descriptors is still opened?
At least it doesn't produce any oopses with the old code.
I'm not sure if I checked after the core/v4l split...

Did you observe an problems when you keep the em28xx_release_resources()
call in em28xx_v4l_fini() ?

I agree that the whole thing smells like bugs and close() probably isn't
the correct place for this.
But never calling this function is definitely wrong.
> Maybe the driver core already prevent such things, but I'm not sure.
Hmm... we currently close the extensions unconditionally in
em28xx_usb_disconnect()...
That seems to avoid trouble.

> If there's a bug out there, the proper fix seems to use kref for 
> struct em28xx, increasing refcount for every em28xx extension and/or 
> file open, decreasing it at either extension fini call, or at file close.
>
> This way, em28xx_release_resources() would be called only after refcount
> reaching zero, e. g. after being sure that nobody is using it.
>
> My plan is to take a look on it after having this changeset merged,
> as such change, if needed, will be complex and would require lots of
> testing. Also, it is independent on those changes.
Yes, let's fix things step by step and not all at the same time.

>
>>> +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>> +			v4l2_device_unregister(&dev->v4l2_dev);
>>>  			kfree(dev->alt_max_pkt_size_isoc);
>>> -			mutex_unlock(&dev->lock);
>>> -			kfree(dev);
>>> -			return 0;
>>> +			goto exit;
>>>  		}
>>>  
>>>  		/* Save some power by putting tuner to sleep */
>>> @@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
>>>  		}
>>>  	}
>>>  
>>> +exit:
>>>  	dev->users--;
>> Nice bugfix.
>>
>>>  	mutex_unlock(&dev->lock);
>>>  	return 0;
>>> @@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
>>>  
>>>  /******************************** usb interface ******************************/
>>>  
>>> -
>>> -
>>>  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>>>  					const struct video_device *template,
>>>  					const char *type_name)
>>> @@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
>>>  	}
>>>  }
>>>  
>>> -void em28xx_tuner_setup(struct em28xx *dev)
>>> +static void em28xx_tuner_setup(struct em28xx *dev)
>>>  {
>>>  	struct tuner_setup           tun_setup;
>>>  	struct v4l2_frequency        f;
>>> @@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
>>>  }
>>>  
>>> -int em28xx_register_analog_devices(struct em28xx *dev)
>>> +static int em28xx_v4l2_init(struct em28xx *dev)
>>>  {
>>>  	u8 val;
>>>  	int ret;
>>>  	unsigned int maxw;
>>>  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>>>  
>>> -	if (!dev->is_audio_only) {
>>> +	if (!dev->has_video) {
>>>  		/* This device does not support the v4l2 extension */
>>>  		return 0;
>>>  	}
>>> @@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>>>  		dev->name, EM28XX_VERSION);
>>>  
>>> +	mutex_lock(&dev->lock);
>>> +
>>>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>>>  	if (ret < 0) {
>>>  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
>>> @@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
>>>  		       EM28XX_VINCTRL_CCIR656_ENABLE;
>>>  
>>> +	/* Initialize tuner and camera */
>>> +	em28xx_tuner_setup(dev);
>>> +	em28xx_init_camera(dev);
>>> +
>>>  	/* Configure audio */
>>>  	ret = em28xx_audio_setup(dev);
>>>  	if (ret < 0) {
>>> @@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>  
>>>  	/* initialize videobuf2 stuff */
>>>  	em28xx_vb2_setup(dev);
>>> +
>>>  err:
>>> -	return 0;
>>> +	mutex_unlock(&dev->lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static struct em28xx_ops v4l2_ops = {
>>> +	.id   = EM28XX_V4L2,
>>> +	.name = "Em28xx v4l2 Extension",
>>> +	.init = em28xx_v4l2_init,
>>> +	.fini = em28xx_v4l2_fini,
>>> +};
>>> +
>>> +static int __init em28xx_video_register(void)
>>> +{
>>> +	return em28xx_register_extension(&v4l2_ops);
>>>  }
>>> +
>>> +static void __exit em28xx_video_unregister(void)
>>> +{
>>> +	em28xx_unregister_extension(&v4l2_ops);
>>> +}
>>> +
>>> +module_init(em28xx_video_register);
>>> +module_exit(em28xx_video_unregister);
>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>> index 7ae05ebc13c1..9d6f43e4681f 100644
>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>> @@ -26,7 +26,7 @@
>>>  #ifndef _EM28XX_H
>>>  #define _EM28XX_H
>>>  
>>> -#define EM28XX_VERSION "0.2.0"
>>> +#define EM28XX_VERSION "0.2.1"
>>>  
>>>  #include <linux/workqueue.h>
>>>  #include <linux/i2c.h>
>>> @@ -474,6 +474,7 @@ struct em28xx_eeprom {
>>>  #define EM28XX_AUDIO   0x10
>>>  #define EM28XX_DVB     0x20
>>>  #define EM28XX_RC      0x30
>>> +#define EM28XX_V4L2    0x40
>>>  
>>>  /* em28xx resource types (used for res_get/res_lock etc */
>>>  #define EM28XX_RESOURCE_VIDEO 0x01
>>> @@ -527,6 +528,7 @@ struct em28xx {
>>>  
>>>  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>>>  	unsigned char disconnected:1;	/* device has been diconnected */
>>> +	unsigned int has_video:1;
>>>  	unsigned int has_audio_class:1;
>>>  	unsigned int has_alsa_audio:1;
>>>  	unsigned int is_audio_only:1;
>>> @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
>>>  int em28xx_audio_analog_set(struct em28xx *dev);
>>>  int em28xx_audio_setup(struct em28xx *dev);
>>>  
>>> -int em28xx_colorlevels_set_default(struct em28xx *dev);
>>>  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
>>>  					 enum em28xx_led_role role);
>>>  int em28xx_capture_start(struct em28xx *dev, int start);
>>> -int em28xx_vbi_supported(struct em28xx *dev);
>>> -int em28xx_set_outfmt(struct em28xx *dev);
>>> -int em28xx_resolution_set(struct em28xx *dev);
>>> -int em28xx_set_alternate(struct em28xx *dev);
>>>  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
>>>  		      int num_bufs, int max_pkt_size, int packet_multiplier);
>>>  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
>>> @@ -742,31 +739,17 @@ 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);
>>> -void em28xx_wake_i2c(struct em28xx *dev);
>>>  int em28xx_register_extension(struct em28xx_ops *dev);
>>>  void em28xx_unregister_extension(struct em28xx_ops *dev);
>>>  void em28xx_init_extension(struct em28xx *dev);
>>>  void em28xx_close_extension(struct em28xx *dev);
>>>  
>>> -/* Provided by em28xx-video.c */
>>> -void em28xx_tuner_setup(struct em28xx *dev);
>>> -int em28xx_vb2_setup(struct em28xx *dev);
>>> -int em28xx_register_analog_devices(struct em28xx *dev);
>>> -void em28xx_release_analog_resources(struct em28xx *dev);
>>> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
>>> -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
>>> -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
>>> -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
>>> -
>>>  /* Provided by em28xx-cards.c */
>>>  extern 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_release_resources(struct em28xx *dev);
>>>  
>>> -/* Provided by em28xx-vbi.c */
>>> -extern struct vb2_ops em28xx_vbi_qops;
>>> -
>>>  /* Provided by em28xx-camera.c */
>>>  int em28xx_detect_sensor(struct em28xx *dev);
>>>  int em28xx_init_camera(struct em28xx *dev);
>> Nice clean-up ! :)
> Thanks!
>


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

* Re: [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-05 13:08     ` Mauro Carvalho Chehab
  2014-01-05 15:31       ` Mauro Carvalho Chehab
@ 2014-01-06 17:44       ` Frank Schäfer
  2014-01-06 18:17         ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-06 17:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 14:08, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 11:55:34 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> Add a message with consistent prints before and after each
>>> extension initialization, and provide a better text for module
>>> load.
>>>
>>> While here, add a missing sanity check for extension finish
>>> code at em28xx-v4l extension.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
>>>  drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
>>>  drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
>>>  drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
>>>  drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
>>>  5 files changed, 20 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>> index 2fdb66ee44ab..263886adcf26 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>> @@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  		return 0;
>>>  	}
>>>  
>>> -	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
>>> +	em28xx_info("Binding audio extension\n");
>>> +
>>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>  			 "Rechberger\n");
>>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
>>> @@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  	adev->sndcard = card;
>>>  	adev->udev = dev->udev;
>>>  
>>> +	em28xx_info("Audio extension successfully initialized\n");
>>>  	return 0;
>>>  }
>>>  
>>> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
>>> index 1113d4e107d8..33cf26e106b5 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-core.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-core.c
>>> @@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
>>>  		ops->init(dev);
>>>  	}
>>>  	mutex_unlock(&em28xx_devlist_mutex);
>>> -	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
>>> +	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
>>>  	return 0;
>>>  }
>>>  EXPORT_SYMBOL(em28xx_register_extension);
>>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> index ddc0e609065d..f72663a9b5c5 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
>>> @@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
>>>  static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
>>>  {
>>>  	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
>>> -        struct em28xx *dev = i2c_bus->dev;
>>> +	struct em28xx *dev = i2c_bus->dev;
>>>  
>>>  	if (acquire)
>>>  		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
>>> @@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>  
>>>  	if (!dev->board.has_dvb) {
>>>  		/* This device does not support the extension */
>>> -		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
>>>  		return 0;
>>>  	}
>>>  
>>> +	em28xx_info("Binding DVB extension\n");
>>> +
>>>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
>>>  
>>>  	if (dvb == NULL) {
>>> @@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
>>>  	/* MFE lock */
>>>  	dvb->adapter.mfe_shared = mfe_shared;
>>>  
>>> -	em28xx_info("Successfully loaded em28xx-dvb\n");
>>> +	em28xx_info("DVB extension successfully initialized\n");
>>>  ret:
>>>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
>>>  	mutex_unlock(&dev->lock);
>>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
>>> index 93a7d02b9cb4..eed7dd79f734 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-input.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
>>> @@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>>  		return 0;
>>>  	}
>>>  
>>> +	em28xx_info("Registering input extension\n");
>>> +
>>>  	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
>>>  	rc = rc_allocate_device();
>>>  	if (!ir || !rc)
>>> @@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
>>>  	if (err)
>>>  		goto error;
>>>  
>>> +	em28xx_info("Input extension successfully initalized\n");
>>> +
>>>  	return 0;
>>>  
>>>  error:
>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>> index 56d1b46164a0..b767262c642b 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>> @@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
>>>  
>>>  	/*FIXME: I2C IR should be disconnected */
>>>  
>>> +	if (!dev->has_video) {
>>> +		/* This device does not support the v4l2 extension */
>>> +		return 0;
>>> +	}
>>> +
>> That's a separate change and AFAICS it's not needed.
> It is needed. If you plug a device with video first and then a DVB-only device,
> as em28xx-v4l will be loaded, it will initialize the extension, if this code got
> removed.
We are in em28xx_v4l2_fini(), not em28xx_v4l2_init(). ;)
AFAICS nothing bad can happen.

> I can move it to a separate patch adding the proper description.
>
>>>  	if (dev->radio_dev) {
>>>  		if (video_is_registered(dev->radio_dev))
>>>  			video_unregister_device(dev->radio_dev);
>>> @@ -2215,8 +2220,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>  		return 0;
>>>  	}
>>>  
>>> -	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>>> -		dev->name, EM28XX_VERSION);
>>> +	em28xx_info("Registering V4L2 extension\n");
>>>  
>>>  	mutex_lock(&dev->lock);
>>>  
>>> @@ -2498,6 +2502,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>  	/* initialize videobuf2 stuff */
>>>  	em28xx_vb2_setup(dev);
>>>  
>>> +	em28xx_info("V4L2 extension successfully initialized\n");
>>> +
>>>  err:
>>>  	mutex_unlock(&dev->lock);
>>>  	return ret;
>


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

* Re: [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies
  2014-01-05 13:10     ` Mauro Carvalho Chehab
@ 2014-01-06 17:48       ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-06 17:48 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 14:10, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 12:03:51 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> The I2C wait completion/timeout logic currently assumes that
>>> msleep(5) will wait exaclty 5 ms. This is not true at all,
>>> as it depends on CONFIG_HZ.
>>>
>>> Convert it to use jiffies, in order to not wait for more time
>>> than needed.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-i2c.c | 65 ++++++++++++++++++-----------------
>>>  1 file changed, 34 insertions(+), 31 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
>>> index 9e6a11d01858..9fa7ed51e5b1 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
>>> @@ -26,6 +26,7 @@
>>>  #include <linux/kernel.h>
>>>  #include <linux/usb.h>
>>>  #include <linux/i2c.h>
>>> +#include <linux/jiffies.h>
>>>  
>>>  #include "em28xx.h"
>>>  #include "tuner-xc2028.h"
>>> @@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
>>>   */
>>>  static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  {
>>> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
>>>  	int ret;
>>> -	int write_timeout;
>>>  	u8 b2[6];
>>>  
>>>  	if (len < 1 || len > 4)
>>> @@ -74,15 +75,15 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  		return (ret < 0) ? ret : -EIO;
>>>  	}
>>>  	/* wait for completion */
>>> -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
>>> -	     write_timeout -= 5) {
>>> +	while (time_is_after_jiffies(timeout)) {
>> AFAIU, it must be time_is_before_jiffies(timeout).
> This is tricky, but it is right. 
>
> See its description at jiffies.h:
>
> 	/* time_is_after_jiffies(a) return true if a is after jiffies */
> 	#define time_is_after_jiffies(a) time_before(jiffies, a)
Urgh... yes, you are right.
I've read this, but didn't notice that we check the timeout jiffies and
not the current jiffies. :/
Sorry for the noise.

>
>>>  		ret = dev->em28xx_read_reg(dev, 0x05);
>>> -		if (ret == 0x80 + len - 1) {
>>> +		if (ret == 0x80 + len - 1)
>>>  			return len;
>>> -		} else if (ret == 0x94 + len - 1) {
>>> +		if (ret == 0x94 + len - 1) {
>>>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>>>  			return -ENODEV;
>>> -		} else if (ret < 0) {
>>> +		}
>>> +		if (ret < 0) {
>>>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>>>  				    ret);
>>>  			return ret;
>>> @@ -99,9 +100,9 @@ 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(EM2800_I2C_XFER_TIMEOUT);
>>>  	u8 buf2[4];
>>>  	int ret;
>>> -	int read_timeout;
>>>  	int i;
>>>  
>>>  	if (len < 1 || len > 4)
>>> @@ -118,15 +119,15 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  	}
>>>  
>>>  	/* wait for completion */
>>> -	for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
>>> -	     read_timeout -= 5) {
>>> +	while (time_is_after_jiffies(timeout)) {
>> The same here...
>>
>>>  		ret = dev->em28xx_read_reg(dev, 0x05);
>>> -		if (ret == 0x84 + len - 1) {
>>> +		if (ret == 0x84 + len - 1)
>>>  			break;
>>> -		} else if (ret == 0x94 + len - 1) {
>>> +		if (ret == 0x94 + len - 1) {
>>>  			em28xx_warn("R05 returned 0x%02x: I2C timeout", ret);
>>>  			return -ENODEV;
>>> -		} else if (ret < 0) {
>>> +		}
>>> +		if (ret < 0) {
>>>  			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>>>  				    ret);
>>>  			return ret;
>>> @@ -170,7 +171,8 @@ 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)
>>>  {
>>> -	int write_timeout, ret;
>>> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_I2C_XFER_TIMEOUT);
>>> +	int ret;
>>>  
>>>  	if (len < 1 || len > 64)
>>>  		return -EOPNOTSUPP;
>>> @@ -193,17 +195,18 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>>>  		}
>>>  	}
>>>  
>>> -	/* Check success of the i2c operation */
>>> -	for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
>>> -	     write_timeout -= 5) {
>>> +	/* wait for completion */
>>> +	while (time_is_after_jiffies(timeout)) {
>> ... and here.
>>
>>>  		ret = dev->em28xx_read_reg(dev, 0x05);
>>> -		if (ret == 0) { /* success */
>>> +		if (ret == 0) /* success */
>>>  			return len;
>>> -		} else if (ret == 0x10) {
>>> -			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x", addr);
>>> +		if (ret == 0x10) {
>>> +			em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
>>> +				    addr);
>>>  			return -ENODEV;
>>> -		} else if (ret < 0) {
>>> -			em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
>>> +		}
>>> +		if (ret < 0) {
>>> +			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>>>  				    ret);
>>>  			return ret;
>>>  		}
>>> @@ -214,6 +217,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>>>  		 * (even with high payload) ...
>>>  		 */
>>>  	}
>>> +
>>>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>>>  	return -EIO;
>>>  }
>>> @@ -251,21 +255,20 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>>>  
>>>  	/* Check success of the i2c operation */
>>>  	ret = dev->em28xx_read_reg(dev, 0x05);
>>> +	if (ret == 0) /* success */
>>> +		return len;
>>>  	if (ret < 0) {
>>> -		em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
>>> +		em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
>>>  			    ret);
>>>  		return ret;
>>>  	}
>>> -	if (ret > 0) {
>>> -		if (ret == 0x10) {
>>> -			em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
>>> -			return -ENODEV;
>>> -		} else {
>>> -			em28xx_warn("unknown i2c error (status=%i)\n", ret);
>>> -			return -EIO;
>>> -		}
>>> +	if (ret == 0x10) {
>>> +		em28xx_warn("I2C transfer timeout on read from addr 0x%02x", addr);
>>> +		return -ENODEV;
>>>  	}
>>> -	return len;
>>> +
>>> +	em28xx_warn("unknown i2c error (status=%i)\n", ret);
>>> +	return -EIO;
>>>  }
>>>  
>>>  /*
>


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

* Re: [PATCH v4 07/22] [media] em28xx: improve extension information messages
  2014-01-06 17:44       ` Frank Schäfer
@ 2014-01-06 18:17         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-06 18:17 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Mon, 06 Jan 2014 18:44:02 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 05.01.2014 14:08, schrieb Mauro Carvalho Chehab:
> > Em Sun, 05 Jan 2014 11:55:34 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> >>> Add a message with consistent prints before and after each
> >>> extension initialization, and provide a better text for module
> >>> load.
> >>>
> >>> While here, add a missing sanity check for extension finish
> >>> code at em28xx-v4l extension.
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>> ---
> >>>  drivers/media/usb/em28xx/em28xx-audio.c |  4 +++-
> >>>  drivers/media/usb/em28xx/em28xx-core.c  |  2 +-
> >>>  drivers/media/usb/em28xx/em28xx-dvb.c   |  7 ++++---
> >>>  drivers/media/usb/em28xx/em28xx-input.c |  4 ++++
> >>>  drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++--
> >>>  5 files changed, 20 insertions(+), 7 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> index 2fdb66ee44ab..263886adcf26 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> @@ -649,7 +649,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>  		return 0;
> >>>  	}
> >>>  
> >>> -	printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
> >>> +	em28xx_info("Binding audio extension\n");
> >>> +
> >>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >>>  			 "Rechberger\n");
> >>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> >>> @@ -702,6 +703,7 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>  	adev->sndcard = card;
> >>>  	adev->udev = dev->udev;
> >>>  
> >>> +	em28xx_info("Audio extension successfully initialized\n");
> >>>  	return 0;
> >>>  }
> >>>  
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> >>> index 1113d4e107d8..33cf26e106b5 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-core.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> >>> @@ -1069,7 +1069,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
> >>>  		ops->init(dev);
> >>>  	}
> >>>  	mutex_unlock(&em28xx_devlist_mutex);
> >>> -	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
> >>> +	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
> >>>  	return 0;
> >>>  }
> >>>  EXPORT_SYMBOL(em28xx_register_extension);
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> index ddc0e609065d..f72663a9b5c5 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-dvb.c
> >>> @@ -274,7 +274,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
> >>>  static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
> >>>  {
> >>>  	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
> >>> -        struct em28xx *dev = i2c_bus->dev;
> >>> +	struct em28xx *dev = i2c_bus->dev;
> >>>  
> >>>  	if (acquire)
> >>>  		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
> >>> @@ -992,10 +992,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>  
> >>>  	if (!dev->board.has_dvb) {
> >>>  		/* This device does not support the extension */
> >>> -		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
> >>>  		return 0;
> >>>  	}
> >>>  
> >>> +	em28xx_info("Binding DVB extension\n");
> >>> +
> >>>  	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
> >>>  
> >>>  	if (dvb == NULL) {
> >>> @@ -1407,7 +1408,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
> >>>  	/* MFE lock */
> >>>  	dvb->adapter.mfe_shared = mfe_shared;
> >>>  
> >>> -	em28xx_info("Successfully loaded em28xx-dvb\n");
> >>> +	em28xx_info("DVB extension successfully initialized\n");
> >>>  ret:
> >>>  	em28xx_set_mode(dev, EM28XX_SUSPEND);
> >>>  	mutex_unlock(&dev->lock);
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
> >>> index 93a7d02b9cb4..eed7dd79f734 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-input.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-input.c
> >>> @@ -692,6 +692,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >>>  		return 0;
> >>>  	}
> >>>  
> >>> +	em28xx_info("Registering input extension\n");
> >>> +
> >>>  	ir = kzalloc(sizeof(*ir), GFP_KERNEL);
> >>>  	rc = rc_allocate_device();
> >>>  	if (!ir || !rc)
> >>> @@ -785,6 +787,8 @@ static int em28xx_ir_init(struct em28xx *dev)
> >>>  	if (err)
> >>>  		goto error;
> >>>  
> >>> +	em28xx_info("Input extension successfully initalized\n");
> >>> +
> >>>  	return 0;
> >>>  
> >>>  error:
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> >>> index 56d1b46164a0..b767262c642b 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-video.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> >>> @@ -1884,6 +1884,11 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
> >>>  
> >>>  	/*FIXME: I2C IR should be disconnected */
> >>>  
> >>> +	if (!dev->has_video) {
> >>> +		/* This device does not support the v4l2 extension */
> >>> +		return 0;
> >>> +	}
> >>> +
> >> That's a separate change and AFAICS it's not needed.
> > It is needed. If you plug a device with video first and then a DVB-only device,
> > as em28xx-v4l will be loaded, it will initialize the extension, if this code got
> > removed.
> We are in em28xx_v4l2_fini(), not em28xx_v4l2_init(). ;)
> AFAICS nothing bad can happen.

You're likely right here: the check ends to be redundant with the current
code, but if we ever need to add some other things there, that would cause
troubles. So, I prefer to keep it there, just in case.

Also, similar check exists on the other extensions (basically, on all other
extensions, on fini checks for the same feature as init). IMHO, we should
either remove all of them as a hole, or to keep them all, or otherwise newer
developers could be confused.

So, I prefer to keep the check.

Cheers,
Mauro

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

* Re: [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video
  2014-01-05 14:40     ` Mauro Carvalho Chehab
@ 2014-01-06 21:28       ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-06 21:28 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 15:40, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 11:26:14 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> There are several init code inside em28xx-cards that are actually
>>> part of analog initialization. Move the code to em28x-video, in
>>> order to remove part of the mess.
>>>
>>> In thesis, no functional changes so far.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-cards.c | 71 -------------------------
>>>  drivers/media/usb/em28xx/em28xx-video.c | 91 ++++++++++++++++++++++++++++++---
>>>  2 files changed, 84 insertions(+), 78 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>> index 551cbc294190..175cd776e0a1 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>> @@ -2907,7 +2907,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>  			   struct usb_interface *interface,
>>>  			   int minor)
>>>  {
>>> -	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>>>  	int retval;
>>>  	static const char *default_chip_name = "em28xx";
>>>  	const char *chip_name = default_chip_name;
>>> @@ -3034,15 +3033,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>  		}
>>>  	}
>>>  
>>> -	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
>>> -	if (retval < 0) {
>>> -		em28xx_errdev("Call to v4l2_device_register() failed!\n");
>>> -		return retval;
>>> -	}
>>> -
>>> -	v4l2_ctrl_handler_init(hdl, 8);
>>> -	dev->v4l2_dev.ctrl_handler = hdl;
>>> -
>>>  	rt_mutex_init(&dev->i2c_bus_lock);
>>>  
>>>  	/* register i2c bus 0 */
>>> @@ -3071,72 +3061,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>  		}
>>>  	}
>>>  
>>> -	/*
>>> -	 * Default format, used for tvp5150 or saa711x output formats
>>> -	 */
>>> -	dev->vinmode = 0x10;
>>> -	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
>>> -		       EM28XX_VINCTRL_CCIR656_ENABLE;
>>> -
>>>  	/* Do board specific init and eeprom reading */
>>>  	em28xx_card_setup(dev);
>>>  
>> em28xx_card_setup() initializes some v4l2 subdevices, but now the v4l2
>> device (dev->v4l2_dev) isn't ready at this point, because
>> v4l2_device_register() isn't called yet.
>> This introduces oopses.
>> You are fixing this with patch 5/22 later, but patches should never
>> introduce any oopses.
>> The simplest soultion is to move patch 5/22 before this patch.
> After thinking for a while, the better to just fold patch 5 into patch 3,
> and do the necessary changes at the error handling logic.
>
> This makes it simpler to review and test. 
>
> New patch enclosed.
>
> Btw, I tested here with HVR-950, without any noticeable changes.
>
> Cheers,
> Mauro
>
> -
>
> [PATCH] [media] em28xx: move analog-specific init to em28xx-video
>
> There are several init code inside em28xx-cards that are actually
> part of analog initialization. Move the code to em28x-video, in
> order to remove part of the mess.
>
> In thesis, no functional changes so far.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index 154e6f028fd2..541de6df127b 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2360,24 +2360,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
>  };
>  /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
>  
> -/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
> -static unsigned short saa711x_addrs[] = {
> -	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
> -	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
> -	I2C_CLIENT_END };
> -
> -static unsigned short tvp5150_addrs[] = {
> -	0xb8 >> 1,
> -	0xba >> 1,
> -	I2C_CLIENT_END
> -};
> -
> -static unsigned short msp3400_addrs[] = {
> -	0x80 >> 1,
> -	0x88 >> 1,
> -	I2C_CLIENT_END
> -};
> -
>  int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
>  {
>  	struct em28xx_i2c_bus *i2c_bus = ptr;
> @@ -2782,58 +2764,8 @@ static void em28xx_card_setup(struct em28xx *dev)
>  	/* Allow override tuner type by a module parameter */
>  	if (tuner >= 0)
>  		dev->tuner_type = tuner;
> -
> -	/* request some modules */
> -	if (dev->board.has_msp34xx)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"msp3400", 0, msp3400_addrs);
> -
> -	if (dev->board.decoder == EM28XX_SAA711X)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"saa7115_auto", 0, saa711x_addrs);
> -
> -	if (dev->board.decoder == EM28XX_TVP5150)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"tvp5150", 0, tvp5150_addrs);
> -
> -	if (dev->board.adecoder == EM28XX_TVAUDIO)
> -		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -			"tvaudio", dev->board.tvaudio_addr, NULL);
> -
> -	if (dev->board.tuner_type != TUNER_ABSENT) {
> -		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
> -
> -		if (dev->board.radio.type)
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -				"tuner", dev->board.radio_addr, NULL);
> -
> -		if (has_demod)
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev,
> -				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> -				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
> -		if (dev->tuner_addr == 0) {
> -			enum v4l2_i2c_tuner_type type =
> -				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
> -			struct v4l2_subdev *sd;
> -
> -			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
> -				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> -				0, v4l2_i2c_tuner_addrs(type));
> -
> -			if (sd)
> -				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
> -		} else {
> -			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> -				"tuner", dev->tuner_addr, NULL);
> -		}
> -	}
> -
> -	em28xx_tuner_setup(dev);
> -
> -	em28xx_init_camera(dev);
>  }
>  
> -
>  static void request_module_async(struct work_struct *work)
>  {
>  	struct em28xx *dev = container_of(work,
> @@ -2907,7 +2839,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  			   struct usb_interface *interface,
>  			   int minor)
>  {
> -	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>  	int retval;
>  	static const char *default_chip_name = "em28xx";
>  	const char *chip_name = default_chip_name;
> @@ -3034,15 +2965,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		}
>  	}
>  
> -	retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
> -	if (retval < 0) {
> -		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> -		return retval;
> -	}
> -
> -	v4l2_ctrl_handler_init(hdl, 8);
> -	dev->v4l2_dev.ctrl_handler = hdl;
> -
>  	rt_mutex_init(&dev->i2c_bus_lock);
>  
>  	/* register i2c bus 0 */
> @@ -3053,7 +2975,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  	if (retval < 0) {
>  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
>  			__func__, retval);
> -		goto unregister_dev;
> +		return retval;
>  	}
>  
>  	/* register i2c bus 1 */
> @@ -3067,75 +2989,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  		if (retval < 0) {
>  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
>  				__func__, retval);
> -			goto unregister_dev;
> +			return retval;
>  		}
>  	}
>  
> -	/*
> -	 * Default format, used for tvp5150 or saa711x output formats
> -	 */
> -	dev->vinmode = 0x10;
> -	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> -		       EM28XX_VINCTRL_CCIR656_ENABLE;
> -
>  	/* Do board specific init and eeprom reading */
>  	em28xx_card_setup(dev);
>  
> -	/* Configure audio */
> -	retval = em28xx_audio_setup(dev);
> -	if (retval < 0) {
> -		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> -			__func__, retval);
> -		goto fail;
> -	}
> -	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> -			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> -	} else {
> -		/* install the em28xx notify callback */
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> -				em28xx_ctrl_notify, dev);
> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> -				em28xx_ctrl_notify, dev);
> -	}
> -
> -	/* wake i2c devices */
> -	em28xx_wake_i2c(dev);
> -
> -	/* init video dma queues */
> -	INIT_LIST_HEAD(&dev->vidq.active);
> -	INIT_LIST_HEAD(&dev->vbiq.active);
> -
> -	if (dev->board.has_msp34xx) {
> -		/* Send a reset to other chips via gpio */
> -		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
> -		if (retval < 0) {
> -			em28xx_errdev("%s: em28xx_write_reg - "
> -				      "msp34xx(1) failed! error [%d]\n",
> -				      __func__, retval);
> -			goto fail;
> -		}
> -		msleep(3);
> -
> -		retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
> -		if (retval < 0) {
> -			em28xx_errdev("%s: em28xx_write_reg - "
> -				      "msp34xx(2) failed! error [%d]\n",
> -				      __func__, retval);
> -			goto fail;
> -		}
> -		msleep(3);
> -	}
> -
>  	retval = em28xx_register_analog_devices(dev);
> -	if (retval < 0) {
> +	if (retval < 0)
>  		goto fail;
> -	}
> -
> -	/* Save some power by putting tuner to sleep */
> -	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
>  
>  	return 0;
>  
> @@ -3143,10 +3006,6 @@ fail:
>  	if (dev->def_i2c_bus)
>  		em28xx_i2c_unregister(dev, 1);
>  	em28xx_i2c_unregister(dev, 0);
> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> -
> -unregister_dev:
> -	v4l2_device_unregister(&dev->v4l2_dev);
>  
>  	return retval;
>  }
> @@ -3388,9 +3247,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	/* save our data pointer in this interface device */
>  	usb_set_intfdata(interface, dev);
>  
> -	/* initialize videobuf2 stuff */
> -	em28xx_vb2_setup(dev);
> -
>  	/* allocate device struct */
>  	mutex_init(&dev->lock);
>  	mutex_lock(&dev->lock);
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index b3ede856c32e..3726af134f39 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -2045,6 +2045,24 @@ static struct video_device em28xx_radio_template = {
>  	.ioctl_ops 	      = &radio_ioctl_ops,
>  };
>  
> +/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
> +static unsigned short saa711x_addrs[] = {
> +	0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
> +	0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
> +	I2C_CLIENT_END };
> +
> +static unsigned short tvp5150_addrs[] = {
> +	0xb8 >> 1,
> +	0xba >> 1,
> +	I2C_CLIENT_END
> +};
> +
> +static unsigned short msp3400_addrs[] = {
> +	0x80 >> 1,
> +	0x88 >> 1,
> +	I2C_CLIENT_END
> +};
> +
>  /******************************** usb interface ******************************/
>  
>  
> @@ -2186,10 +2204,129 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	u8 val;
>  	int ret;
>  	unsigned int maxw;
> +	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
> +
> +	if (dev->is_audio_only) {
> +		/* This device does not support the v4l2 extension */
> +		return 0;
> +	}
>  
>  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>  		dev->name, EM28XX_VERSION);
>  
> +	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
> +	if (ret < 0) {
> +		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> +		goto err;
> +	}
> +
> +	v4l2_ctrl_handler_init(hdl, 8);
> +	dev->v4l2_dev.ctrl_handler = hdl;
> +
> +	/*
> +	 * Default format, used for tvp5150 or saa711x output formats
> +	 */
> +	dev->vinmode = 0x10;
> +	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
> +		       EM28XX_VINCTRL_CCIR656_ENABLE;
> +
> +	/* request some modules */
> +
> +	if (dev->board.has_msp34xx)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"msp3400", 0, msp3400_addrs);
> +
> +	if (dev->board.decoder == EM28XX_SAA711X)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"saa7115_auto", 0, saa711x_addrs);
> +
> +	if (dev->board.decoder == EM28XX_TVP5150)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"tvp5150", 0, tvp5150_addrs);
> +
> +	if (dev->board.adecoder == EM28XX_TVAUDIO)
> +		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +			"tvaudio", dev->board.tvaudio_addr, NULL);
> +
> +	/* Initialize tuner and camera */
> +
> +	if (dev->board.tuner_type != TUNER_ABSENT) {
> +		int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
> +
> +		if (dev->board.radio.type)
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +				"tuner", dev->board.radio_addr, NULL);
> +
> +		if (has_demod)
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev,
> +				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> +				0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
> +		if (dev->tuner_addr == 0) {
> +			enum v4l2_i2c_tuner_type type =
> +				has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
> +			struct v4l2_subdev *sd;
> +
> +			sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
> +				&dev->i2c_adap[dev->def_i2c_bus], "tuner",
> +				0, v4l2_i2c_tuner_addrs(type));
> +
> +			if (sd)
> +				dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
> +		} else {
> +			v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
> +				"tuner", dev->tuner_addr, NULL);
> +		}
> +	}
> +
> +	em28xx_tuner_setup(dev);
> +	em28xx_init_camera(dev);
> +
> +	/* Configure audio */
> +	ret = em28xx_audio_setup(dev);
> +	if (ret < 0) {
> +		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
> +			__func__, ret);
> +		goto unregister_dev;
> +	}
> +	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
> +			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
> +	} else {
> +		/* install the em28xx notify callback */
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
> +				em28xx_ctrl_notify, dev);
> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
> +				em28xx_ctrl_notify, dev);
> +	}
> +
> +	/* wake i2c devices */
> +	em28xx_wake_i2c(dev);
> +
> +	/* init video dma queues */
> +	INIT_LIST_HEAD(&dev->vidq.active);
> +	INIT_LIST_HEAD(&dev->vbiq.active);
> +
> +	if (dev->board.has_msp34xx) {
> +		/* Send a reset to other chips via gpio */
> +		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
> +		if (ret < 0) {
> +			em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
> +				      __func__, ret);
> +			goto unregister_dev;
> +		}
> +		msleep(3);
> +
> +		ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
> +		if (ret < 0) {
> +			em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
> +				      __func__, ret);
> +			goto unregister_dev;
> +		}
> +		msleep(3);
> +	}
> +
>  	/* set default norm */
>  	dev->norm = V4L2_STD_PAL;
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
> @@ -2252,14 +2389,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	/* Reset image controls */
>  	em28xx_colorlevels_set_default(dev);
>  	v4l2_ctrl_handler_setup(&dev->ctrl_handler);
> -	if (dev->ctrl_handler.error)
> -		return dev->ctrl_handler.error;
> +	ret = dev->ctrl_handler.error;
> +	if (ret)
> +		goto unregister_dev;
>  
>  	/* allocate and fill video video_device struct */
>  	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
>  	if (!dev->vdev) {
>  		em28xx_errdev("cannot allocate video_device.\n");
> -		return -ENODEV;
> +		ret = -ENODEV;
> +		goto unregister_dev;
>  	}
>  	dev->vdev->queue = &dev->vb_vidq;
>  	dev->vdev->queue->lock = &dev->vb_queue_lock;
> @@ -2289,7 +2428,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	if (ret) {
>  		em28xx_errdev("unable to register video device (error=%i).\n",
>  			      ret);
> -		return ret;
> +		goto unregister_dev;
>  	}
>  
>  	/* Allocate and fill vbi video_device struct */
> @@ -2318,7 +2457,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  					    vbi_nr[dev->devno]);
>  		if (ret < 0) {
>  			em28xx_errdev("unable to register vbi device\n");
> -			return ret;
> +			goto unregister_dev;
>  		}
>  	}
>  
> @@ -2327,13 +2466,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  						  "radio");
>  		if (!dev->radio_dev) {
>  			em28xx_errdev("cannot allocate video_device.\n");
> -			return -ENODEV;
> +			ret = -ENODEV;
> +			goto unregister_dev;
>  		}
>  		ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
>  					    radio_nr[dev->devno]);
>  		if (ret < 0) {
>  			em28xx_errdev("can't register radio device\n");
> -			return ret;
> +			goto unregister_dev;
>  		}
>  		em28xx_info("Registered radio device as %s\n",
>  			    video_device_node_name(dev->radio_dev));
> @@ -2346,5 +2486,17 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  		em28xx_info("V4L2 VBI device registered as %s\n",
>  			    video_device_node_name(dev->vbi_dev));
>  
> +	/* Save some power by putting tuner to sleep */
> +	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
> +
> +	/* initialize videobuf2 stuff */
> +	em28xx_vb2_setup(dev);
> +
>  	return 0;
> +
> +unregister_dev:
> +	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> +	v4l2_device_unregister(&dev->v4l2_dev);
> +err:
> +	return ret;
>  }
>
Ok, looks fine now. :)

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>


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

* Re: [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module
  2014-01-05 15:18       ` Mauro Carvalho Chehab
@ 2014-01-06 21:35         ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-06 21:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Mauro Carvalho Chehab; +Cc: Linux Media Mailing List

Am 05.01.2014 16:18, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 10:56:33 -0200
> Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:
>
>> Em Sun, 05 Jan 2014 11:47:00 +0100
>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>
>>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>>> Now that all analog-specific code are at em28xx-video, convert
>>>> it into an em28xx extension and load it as a separate module.
>>>>
>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>> ---
>>>>  drivers/media/usb/em28xx/Kconfig         |  6 ++-
>>>>  drivers/media/usb/em28xx/Makefile        |  5 ++-
>>>>  drivers/media/usb/em28xx/em28xx-camera.c |  1 +
>>>>  drivers/media/usb/em28xx/em28xx-cards.c  | 45 ++++---------------
>>>>  drivers/media/usb/em28xx/em28xx-core.c   | 12 ++++++
>>>>  drivers/media/usb/em28xx/em28xx-v4l.h    | 20 +++++++++
>>>>  drivers/media/usb/em28xx/em28xx-vbi.c    |  1 +
>>>>  drivers/media/usb/em28xx/em28xx-video.c  | 74 +++++++++++++++++++++++---------
>>>>  drivers/media/usb/em28xx/em28xx.h        | 23 ++--------
>>>>  9 files changed, 107 insertions(+), 80 deletions(-)
>>>>  create mode 100644 drivers/media/usb/em28xx/em28xx-v4l.h
>>>>
>>>> diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
>>>> index d6ba514d31eb..838fc9dbb747 100644
>>>> --- a/drivers/media/usb/em28xx/Kconfig
>>>> +++ b/drivers/media/usb/em28xx/Kconfig
>>>> @@ -1,8 +1,12 @@
>>>>  config VIDEO_EM28XX
>>>> -	tristate "Empia EM28xx USB video capture support"
>>>> +	tristate "Empia EM28xx USB devices support"
>>>>  	depends on VIDEO_DEV && I2C
>>>>  	select VIDEO_TUNER
>>>>  	select VIDEO_TVEEPROM
>>>> +
>>>> +config VIDEO_EM28XX_V4L2
>>>> +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
>>>> +	depends on VIDEO_EM28XX && I2C
>>> VIDEO_EM28XX already depends on I2C.
>>>
>>>>  	select VIDEOBUF2_VMALLOC
>>>>  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
>>>>  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
>>>> diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
>>>> index ad6d48557940..3f850d5063d0 100644
>>>> --- a/drivers/media/usb/em28xx/Makefile
>>>> +++ b/drivers/media/usb/em28xx/Makefile
>>>> @@ -1,10 +1,11 @@
>>>> -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
>>>> -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
>>>> +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
>>>>  
>>>> +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
>>>>  em28xx-alsa-objs := em28xx-audio.o
>>>>  em28xx-rc-objs := em28xx-input.o
>>>>  
>>>>  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
>>>> +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
>>>>  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
>>>>  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
>>>>  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
>>>> index d666741797d4..c29f5c4e7b40 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-camera.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
>>>> @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
>>>>  
>>>>  	return ret;
>>>>  }
>>>> +EXPORT_SYMBOL_GPL(em28xx_init_camera);
>>> em28xx-camera should also be part of the em28xx-v4l module.
>> I tried that. Moving em28xx-camera to em28xx-v4l would cause a recursive
>> dependency, due to the camera probing logic, that should be called by
>> em28xx-cards.c.
>>
>> Moving that probing part to em28xx-v4l is too complex, due to the code
>> that detects the board.
>>
>> One solution would be to break em28xx-camera into two parts: the detection
>> code, to be merged with the core, and the sensor part, to be merged with
>> em28xx-v4l, but that sounds ugly.
>>
>> Other solution would be to use something like the dvb_attach() macro,
>> to avoid the recursive dependency, but that would be a dirty solution.
>>
>> As the code there is not big, the amount of overhead of having everything
>> at em28xx-core is not high. So, I opted to keep the simplest path here,
>> avoiding the risk of breaking something with a complex changeset.
>>
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
>>>> index 175cd776e0a1..938daaabd8e0 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-cards.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
>>>> @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
>>>>  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
>>>>  	},
>>>>  };
>>>> +EXPORT_SYMBOL_GPL(em28xx_boards);
>>>> +
>>>>  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
>>>>  
>>>>  /* table of devices that work with this driver */
>>>> @@ -2827,10 +2829,6 @@ static void em28xx_card_setup(struct em28xx *dev)
>>>>  				"tuner", dev->tuner_addr, NULL);
>>>>  		}
>>>>  	}
>>>> -
>>>> -	em28xx_tuner_setup(dev);
>>>> -
>>>> -	em28xx_init_camera(dev);
>>>>  }
>>> Here you are fixing half of the em28xx_card_setup() oopses which you've
>>> introduced with patch 3/22.
>>> This needs to be done together with patch 5/22 before patch 3/22.
>> Ok.
>>
>>>> @@ -2848,11 +2846,12 @@ static void request_module_async(struct work_struct *work)
>>>>  	em28xx_init_extension(dev);
>>>>  
>>>>  #if defined(CONFIG_MODULES) && defined(MODULE)
>>>> +	if (dev->has_video)
>>>> +		request_module("em28xx-v4l");
>>>>  	if (dev->has_audio_class)
>>>>  		request_module("snd-usb-audio");
>>>>  	else if (dev->has_alsa_audio)
>>>>  		request_module("em28xx-alsa");
>>>> -
>>>>  	if (dev->board.has_dvb)
>>>>  		request_module("em28xx-dvb");
>>>>  	if (dev->board.buttons ||
>>>> @@ -2881,18 +2880,12 @@ void em28xx_release_resources(struct em28xx *dev)
>>>>  {
>>>>  	/*FIXME: I2C IR should be disconnected */
>>>>  
>>>> -	em28xx_release_analog_resources(dev);
>>>> -
>>>>  	if (dev->def_i2c_bus)
>>>>  		em28xx_i2c_unregister(dev, 1);
>>>>  	em28xx_i2c_unregister(dev, 0);
>>>>  	if (dev->clk)
>>>>  		v4l2_clk_unregister_fixed(dev->clk);
>>>>  
>>>> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>> -
>>>> -	v4l2_device_unregister(&dev->v4l2_dev);
>>>> -
>>>>  	usb_put_dev(dev->udev);
>>>>  
>>>>  	/* Mark device as unused */
>>>> @@ -3043,7 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>>  	if (retval < 0) {
>>>>  		em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
>>>>  			__func__, retval);
>>>> -		goto unregister_dev;
>>>> +		return retval;
>>>>  	}
>>>>  
>>>>  	/* register i2c bus 1 */
>>>> @@ -3057,30 +3050,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>>>>  		if (retval < 0) {
>>>>  			em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
>>>>  				__func__, retval);
>>>> -			goto unregister_dev;
>>>> +			return retval;
>>>>  		}
>>>>  	}
>>> Hmm... if registering of bus 1 fails, we need to unregister bus 0.
>>> But that's an old bug which we can fix later...
>> Good point. Yes, this should be on a separate patch.
> Patch sent.
>
>>>>  	/* Do board specific init and eeprom reading */
>>>>  	em28xx_card_setup(dev);
>>>>  
>>>> -	retval = em28xx_register_analog_devices(dev);
>>>> -	if (retval < 0) {
>>>> -		goto fail;
>>>> -	}
>>>> -
>>>>  	return 0;
>>>> -
>>>> -fail:
>>>> -	if (dev->def_i2c_bus)
>>>> -		em28xx_i2c_unregister(dev, 1);
>>>> -	em28xx_i2c_unregister(dev, 0);
>>>> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>> -
>>>> -unregister_dev:
>>>> -	v4l2_device_unregister(&dev->v4l2_dev);
>>>> -
>>>> -	return retval;
>>>>  }
>>>>  
>>>>  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
>>>> @@ -3283,6 +3260,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>  	dev->alt   = -1;
>>>>  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
>>>>  	dev->has_alsa_audio = has_audio;
>>>> +	dev->has_video = has_video;
>>>>  	dev->audio_ifnum = ifnum;
>>>>  
>>>>  	/* Checks if audio is provided by some interface */
>>>> @@ -3322,10 +3300,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>  
>>>>  	/* allocate device struct */
>>>>  	mutex_init(&dev->lock);
>>>> -	mutex_lock(&dev->lock);
>>>>  	retval = em28xx_init_dev(dev, udev, interface, nr);
>>>>  	if (retval) {
>>>> -		goto unlock_and_free;
>>>> +		goto err_free;
>>>>  	}
>>>>  
>>>>  	if (usb_xfer_mode < 0) {
>>>> @@ -3368,7 +3345,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>  		if (retval) {
>>>>  			printk(DRIVER_NAME
>>>>  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
>>>> -			goto unlock_and_free;
>>>> +			goto err_free;
>>>>  		}
>>>>  	}
>>>>  
>>>> @@ -3377,13 +3354,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>>>>  	/* Should be the last thing to do, to avoid newer udev's to
>>>>  	   open the device before fully initializing it
>>>>  	 */
>>>> -	mutex_unlock(&dev->lock);
>>>>  
>>>>  	return 0;
>>>>  
>>>> -unlock_and_free:
>>>> -	mutex_unlock(&dev->lock);
>>>> -
>>>>  err_free:
>>>>  	kfree(dev->alt_max_pkt_size_isoc);
>>>>  	kfree(dev);
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
>>>> index 3012912d2997..1113d4e107d8 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-core.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-core.c
>>>> @@ -33,6 +33,18 @@
>>>>  
>>>>  #include "em28xx.h"
>>>>  
>>>> +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
>>>> +		      "Markus Rechberger <mrechberger@gmail.com>, " \
>>>> +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
>>>> +		      "Sascha Sommer <saschasommer@freenet.de>"
>>>> +
>>>> +#define DRIVER_DESC         "Empia em28xx based USB core driver"
>>>> +
>>>> +MODULE_AUTHOR(DRIVER_AUTHOR);
>>>> +MODULE_DESCRIPTION(DRIVER_DESC);
>>>> +MODULE_LICENSE("GPL");
>>>> +MODULE_VERSION(EM28XX_VERSION);
>>>> +
>>>>  /* #define ENABLE_DEBUG_ISOC_FRAMES */
>>>>  
>>>>  static unsigned int core_debug;
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
>>>> new file mode 100644
>>>> index 000000000000..bce438691e0e
>>>> --- /dev/null
>>>> +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
>>>> @@ -0,0 +1,20 @@
>>>> +/*
>>>> +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
>>>> +		    video capture devices
>>> The information about supported chips is outdated everywhere in the driver,
>>> but if you introduce a new header file it should really be up to date.
>>> Just talk about EM27xx/EM28xx.
>> We need to do a cleanup on all those headers: they don't follow Kernel
>> CodingStyle and the old headers use my previous email.
>>
>> For the sake of keeping a coherency, I deliberately opted to just use the
>> same way as the other headers.
>>
>> My plan is to write a patch series fixing this and other CodingStyle
>> issues on em28xx after merging this changeset.
>>
>>>> +
>>>> +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>> +
>>>> +   This program is free software; you can redistribute it and/or modify
>>>> +   it under the terms of the GNU General Public License as published by
>>>> +   the Free Software Foundation version 2 of the License.
>>>> +
>>>> +   This program is distributed in the hope that it will be useful,
>>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> +   GNU General Public License for more details.
>>>> + */
>>>> +
>>>> +
>>>> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
>>>> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
>>>> +extern struct vb2_ops em28xx_vbi_qops;
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
>>>> index 39f39c527c13..db3d655600df 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-vbi.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
>>>> @@ -27,6 +27,7 @@
>>>>  #include <linux/init.h>
>>>>  
>>>>  #include "em28xx.h"
>>>> +#include "em28xx-v4l.h"
>>>>  
>>>>  static unsigned int vbibufs = 5;
>>>>  module_param(vbibufs, int, 0644);
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>>> index 85284626dbd6..d615bff8ac09 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>>> @@ -38,6 +38,7 @@
>>>>  #include <linux/slab.h>
>>>>  
>>>>  #include "em28xx.h"
>>>> +#include "em28xx-v4l.h"
>>>>  #include <media/v4l2-common.h>
>>>>  #include <media/v4l2-ioctl.h>
>>>>  #include <media/v4l2-event.h>
>>>> @@ -141,11 +142,13 @@ static struct em28xx_fmt format[] = {
>>>>  	},
>>>>  };
>>>>  
>>>> +static int em28xx_vbi_supported(struct em28xx *dev);
>>>> +
>>> Or move em28xx_vbi_supported() before em28xx_set_outfmt() and
>>> em28xx_resolution_set() again.
>>> If you had not changed the functions order in patch 1/22, this wouldn't
>>> be necessary.
>> True. I'll put an extra cleanup patch to remove this reference on the
>> CodingStyle cleanup patchset I'm planning to do.
> Ok, I changed the order on patch 1/22, so this line was removed.
>
>>>>  /*
>>>>   * em28xx_wake_i2c()
>>>>   * configure i2c attached devices
>>>>   */
>>>> -void em28xx_wake_i2c(struct em28xx *dev)
>>>> +static void em28xx_wake_i2c(struct em28xx *dev)
>>>>  {
>>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
>>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
>>>> @@ -153,7 +156,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
>>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
>>>>  }
>>>>  
>>>> -int em28xx_colorlevels_set_default(struct em28xx *dev)
>>>> +static int em28xx_colorlevels_set_default(struct em28xx *dev)
>>>>  {
>>>>  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
>>>>  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
>>>> @@ -171,7 +174,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
>>>>  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
>>>>  }
>>>>  
>>>> -int em28xx_set_outfmt(struct em28xx *dev)
>>>> +static int em28xx_set_outfmt(struct em28xx *dev)
>>>>  {
>>>>  	int ret;
>>>>  	u8 fmt, vinctrl;
>>>> @@ -278,7 +281,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
>>>>  }
>>>>  
>>>>  /* FIXME: this only function read values from dev */
>>>> -int em28xx_resolution_set(struct em28xx *dev)
>>>> +static int em28xx_resolution_set(struct em28xx *dev)
>>>>  {
>>>>  	int width, height;
>>>>  	width = norm_maxw(dev);
>>>> @@ -310,7 +313,7 @@ int em28xx_resolution_set(struct em28xx *dev)
>>>>  	return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
>>>>  }
>>>>  
>>>> -int em28xx_vbi_supported(struct em28xx *dev)
>>>> +static int em28xx_vbi_supported(struct em28xx *dev)
>>>>  {
>>>>  	/* Modprobe option to manually disable */
>>>>  	if (disable_vbi == 1)
>>>> @@ -330,7 +333,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
>>>>  }
>>>>  
>>>>  /* Set USB alternate setting for analog video */
>>>> -int em28xx_set_alternate(struct em28xx *dev)
>>>> +static int em28xx_set_alternate(struct em28xx *dev)
>>>>  {
>>>>  	int errCode;
>>>>  	int i;
>>>> @@ -1020,7 +1023,7 @@ static struct vb2_ops em28xx_video_qops = {
>>>>  	.wait_finish    = vb2_ops_wait_finish,
>>>>  };
>>>>  
>>>> -int em28xx_vb2_setup(struct em28xx *dev)
>>>> +static int em28xx_vb2_setup(struct em28xx *dev)
>>>>  {
>>>>  	int rc;
>>>>  	struct vb2_queue *q;
>>>> @@ -1088,7 +1091,7 @@ static void video_mux(struct em28xx *dev, int index)
>>>>  	em28xx_audio_analog_set(dev);
>>>>  }
>>>>  
>>>> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>>>> +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>>>>  {
>>>>  	struct em28xx *dev = priv;
>>>>  
>>>> @@ -1625,7 +1628,7 @@ static int vidioc_g_register(struct file *file, void *priv,
>>>>  		reg->val = ret;
>>>>  	} else {
>>>>  		__le16 val = 0;
>>>> -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>>>> +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>>>>  						   reg->reg, (char *)&val, 2);
>>> Urgh... is it really necessary to start using these pointers again ?
>>> Ok... keep it as is, I'll send a patch to clean this up later.
>> This is one of the few places where we weren't using those pointers:
>>
>> $ git grep em28xx_read_reg_req_len drivers/media/usb/em28xx/
>> drivers/media/usb/em28xx/em28xx-cards.c:  dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
>> drivers/media/usb/em28xx/em28xx-core.c:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
>> drivers/media/usb/em28xx/em28xx-core.c:   ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
>> drivers/media/usb/em28xx/em28xx-core.c:   ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
>> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
>> drivers/media/usb/em28xx/em28xx-i2c.c:            ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
>> drivers/media/usb/em28xx/em28xx-i2c.c:    ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
>> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
>> drivers/media/usb/em28xx/em28xx-input.c:  rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
>> drivers/media/usb/em28xx/em28xx-video.c:          ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>> drivers/media/usb/em28xx/em28xx.h:        int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
>> drivers/media/usb/em28xx/em28xx.h:int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
>>
>> For the sake of coherency, we should either use one or the other way.
>>
>>>>  		if (ret < 0)
>>>>  			return ret;
>>>> @@ -1872,11 +1875,11 @@ static int em28xx_v4l2_open(struct file *filp)
>>>>  }
>>>>  
>>>>  /*
>>>> - * em28xx_realease_resources()
>>>> + * em28xx_v4l2_fini()
>>>>   * unregisters the v4l2,i2c and usb devices
>>>>   * called when the device gets disconected or at module unload
>>>>  */
>>>> -void em28xx_release_analog_resources(struct em28xx *dev)
>>>> +static int em28xx_v4l2_fini(struct em28xx *dev)
>>>>  {
>>>>  
>>>>  	/*FIXME: I2C IR should be disconnected */
>>>> @@ -1906,6 +1909,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
>>>>  			video_device_release(dev->vdev);
>>>>  		dev->vdev = NULL;
>>>>  	}
>>>> +
>>>> +	return 0;
>>>>  }
>>>>  
>>>>  /*
>>>> @@ -1927,12 +1932,12 @@ static int em28xx_v4l2_close(struct file *filp)
>>>>  	if (dev->users == 1) {
>>>>  		/* the device is already disconnect,
>>>>  		   free the remaining resources */
>>>> +
>>>>  		if (dev->disconnected) {
>>>> -			em28xx_release_resources(dev);
>>> Who releases the resources now ?
>> This is tricky.
>>
>> The hole idea is that em28xx-v4l release the resources allocated for V4L
>> only, and not all resources, the same way as the other em28xx modules
>> do.
>>
>> If you take a look at the original em28xx_release_resources(), what it does
>> is to call this function, and then to de-allocate and unregister v4l2:
>>
>> 			v4l2_ctrl_handler_free(&dev->ctrl_handler);
>> 			v4l2_device_unregister(&dev->v4l2_dev);
>>
>> after that, it deallocates the rest of allocated data.
>>
>> Now, em28xx_release_resources() is only called when em28xx is removed
>> from memory or when the device is removed.
>>
>> The code there first calls em28xx_close_extension(dev). So, at device
>> removal, em28xx-v4l will release the V4L2 specific resources, and
>> em28xx_release_resources() will drop the common dev struct.
>>
>> I suspect that it might still be a bug there, but, if so, this bug is 
>> also present on em28xx-dvb, em28xx-alsa and em28xx-rc: what happens if 
>> the device is removed while the file descriptors is still opened?
>>
>> Maybe the driver core already prevent such things, but I'm not sure.
>>
>> If there's a bug out there, the proper fix seems to use kref for 
>> struct em28xx, increasing refcount for every em28xx extension and/or 
>> file open, decreasing it at either extension fini call, or at file close.
>>
>> This way, em28xx_release_resources() would be called only after refcount
>> reaching zero, e. g. after being sure that nobody is using it.
>>
>> My plan is to take a look on it after having this changeset merged,
>> as such change, if needed, will be complex and would require lots of
>> testing. Also, it is independent on those changes.
>>
>>>> +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
>>>> +			v4l2_device_unregister(&dev->v4l2_dev);
>>>>  			kfree(dev->alt_max_pkt_size_isoc);
>>>> -			mutex_unlock(&dev->lock);
>>>> -			kfree(dev);
>>>> -			return 0;
>>>> +			goto exit;
>>>>  		}
>>>>  
>>>>  		/* Save some power by putting tuner to sleep */
>>>> @@ -1951,6 +1956,7 @@ static int em28xx_v4l2_close(struct file *filp)
>>>>  		}
>>>>  	}
>>>>  
>>>> +exit:
>>>>  	dev->users--;
>>> Nice bugfix.
>>>
>>>>  	mutex_unlock(&dev->lock);
>>>>  	return 0;
>>>> @@ -2047,8 +2053,6 @@ static struct video_device em28xx_radio_template = {
>>>>  
>>>>  /******************************** usb interface ******************************/
>>>>  
>>>> -
>>>> -
>>>>  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>>>>  					const struct video_device *template,
>>>>  					const char *type_name)
>>>> @@ -2122,7 +2126,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
>>>>  	}
>>>>  }
>>>>  
>>>> -void em28xx_tuner_setup(struct em28xx *dev)
>>>> +static void em28xx_tuner_setup(struct em28xx *dev)
>>>>  {
>>>>  	struct tuner_setup           tun_setup;
>>>>  	struct v4l2_frequency        f;
>>>> @@ -2181,14 +2185,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
>>>>  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
>>>>  }
>>>>  
>>>> -int em28xx_register_analog_devices(struct em28xx *dev)
>>>> +static int em28xx_v4l2_init(struct em28xx *dev)
>>>>  {
>>>>  	u8 val;
>>>>  	int ret;
>>>>  	unsigned int maxw;
>>>>  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>>>>  
>>>> -	if (!dev->is_audio_only) {
>>>> +	if (!dev->has_video) {
>>>>  		/* This device does not support the v4l2 extension */
>>>>  		return 0;
>>>>  	}
>>>> @@ -2196,6 +2200,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>>  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>>>>  		dev->name, EM28XX_VERSION);
>>>>  
>>>> +	mutex_lock(&dev->lock);
>>>> +
>>>>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>>>>  	if (ret < 0) {
>>>>  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
>>>> @@ -2212,6 +2218,10 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>>  	dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
>>>>  		       EM28XX_VINCTRL_CCIR656_ENABLE;
>>>>  
>>>> +	/* Initialize tuner and camera */
>>>> +	em28xx_tuner_setup(dev);
>>>> +	em28xx_init_camera(dev);
>>>> +
>>>>  	/* Configure audio */
>>>>  	ret = em28xx_audio_setup(dev);
>>>>  	if (ret < 0) {
>>>> @@ -2422,6 +2432,28 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>>>>  
>>>>  	/* initialize videobuf2 stuff */
>>>>  	em28xx_vb2_setup(dev);
>>>> +
>>>>  err:
>>>> -	return 0;
>>>> +	mutex_unlock(&dev->lock);
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static struct em28xx_ops v4l2_ops = {
>>>> +	.id   = EM28XX_V4L2,
>>>> +	.name = "Em28xx v4l2 Extension",
>>>> +	.init = em28xx_v4l2_init,
>>>> +	.fini = em28xx_v4l2_fini,
>>>> +};
>>>> +
>>>> +static int __init em28xx_video_register(void)
>>>> +{
>>>> +	return em28xx_register_extension(&v4l2_ops);
>>>>  }
>>>> +
>>>> +static void __exit em28xx_video_unregister(void)
>>>> +{
>>>> +	em28xx_unregister_extension(&v4l2_ops);
>>>> +}
>>>> +
>>>> +module_init(em28xx_video_register);
>>>> +module_exit(em28xx_video_unregister);
>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>>> index 7ae05ebc13c1..9d6f43e4681f 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>>> @@ -26,7 +26,7 @@
>>>>  #ifndef _EM28XX_H
>>>>  #define _EM28XX_H
>>>>  
>>>> -#define EM28XX_VERSION "0.2.0"
>>>> +#define EM28XX_VERSION "0.2.1"
>>>>  
>>>>  #include <linux/workqueue.h>
>>>>  #include <linux/i2c.h>
>>>> @@ -474,6 +474,7 @@ struct em28xx_eeprom {
>>>>  #define EM28XX_AUDIO   0x10
>>>>  #define EM28XX_DVB     0x20
>>>>  #define EM28XX_RC      0x30
>>>> +#define EM28XX_V4L2    0x40
>>>>  
>>>>  /* em28xx resource types (used for res_get/res_lock etc */
>>>>  #define EM28XX_RESOURCE_VIDEO 0x01
>>>> @@ -527,6 +528,7 @@ struct em28xx {
>>>>  
>>>>  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>>>>  	unsigned char disconnected:1;	/* device has been diconnected */
>>>> +	unsigned int has_video:1;
>>>>  	unsigned int has_audio_class:1;
>>>>  	unsigned int has_alsa_audio:1;
>>>>  	unsigned int is_audio_only:1;
>>>> @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
>>>>  int em28xx_audio_analog_set(struct em28xx *dev);
>>>>  int em28xx_audio_setup(struct em28xx *dev);
>>>>  
>>>> -int em28xx_colorlevels_set_default(struct em28xx *dev);
>>>>  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
>>>>  					 enum em28xx_led_role role);
>>>>  int em28xx_capture_start(struct em28xx *dev, int start);
>>>> -int em28xx_vbi_supported(struct em28xx *dev);
>>>> -int em28xx_set_outfmt(struct em28xx *dev);
>>>> -int em28xx_resolution_set(struct em28xx *dev);
>>>> -int em28xx_set_alternate(struct em28xx *dev);
>>>>  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
>>>>  		      int num_bufs, int max_pkt_size, int packet_multiplier);
>>>>  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
>>>> @@ -742,31 +739,17 @@ 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);
>>>> -void em28xx_wake_i2c(struct em28xx *dev);
>>>>  int em28xx_register_extension(struct em28xx_ops *dev);
>>>>  void em28xx_unregister_extension(struct em28xx_ops *dev);
>>>>  void em28xx_init_extension(struct em28xx *dev);
>>>>  void em28xx_close_extension(struct em28xx *dev);
>>>>  
>>>> -/* Provided by em28xx-video.c */
>>>> -void em28xx_tuner_setup(struct em28xx *dev);
>>>> -int em28xx_vb2_setup(struct em28xx *dev);
>>>> -int em28xx_register_analog_devices(struct em28xx *dev);
>>>> -void em28xx_release_analog_resources(struct em28xx *dev);
>>>> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
>>>> -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
>>>> -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
>>>> -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
>>>> -
>>>>  /* Provided by em28xx-cards.c */
>>>>  extern 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_release_resources(struct em28xx *dev);
>>>>  
>>>> -/* Provided by em28xx-vbi.c */
>>>> -extern struct vb2_ops em28xx_vbi_qops;
>>>> -
>>>>  /* Provided by em28xx-camera.c */
>>>>  int em28xx_detect_sensor(struct em28xx *dev);
>>>>  int em28xx_init_camera(struct em28xx *dev);
>>> Nice clean-up ! :)
>> Thanks!
>>
> Ok, this is the new version of the patch. It is basically a rebase of the
> previous one. Btw, I'm adding those patches on this tree:
>
> 	http://git.linuxtv.org/mchehab/experimental.git/shortlog/refs/heads/em28xx-v4l2-v5
>
> -
>
> [media] em28xx: make em28xx-video to be a separate module
>
> Now that all analog-specific code are at em28xx-video, convert
> it into an em28xx extension and load it as a separate module.
>
> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>
> diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
> index d6ba514d31eb..838fc9dbb747 100644
> --- a/drivers/media/usb/em28xx/Kconfig
> +++ b/drivers/media/usb/em28xx/Kconfig
> @@ -1,8 +1,12 @@
>  config VIDEO_EM28XX
> -	tristate "Empia EM28xx USB video capture support"
> +	tristate "Empia EM28xx USB devices support"
>  	depends on VIDEO_DEV && I2C
>  	select VIDEO_TUNER
>  	select VIDEO_TVEEPROM
> +
> +config VIDEO_EM28XX_V4L2
> +	tristate "Empia EM28xx analog TV, video capture and/or webcam support"
> +	depends on VIDEO_EM28XX
>  	select VIDEOBUF2_VMALLOC
>  	select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
>  	select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
> diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
> index ad6d48557940..3f850d5063d0 100644
> --- a/drivers/media/usb/em28xx/Makefile
> +++ b/drivers/media/usb/em28xx/Makefile
> @@ -1,10 +1,11 @@
> -em28xx-y +=	em28xx-video.o em28xx-i2c.o em28xx-cards.o
> -em28xx-y +=	em28xx-core.o  em28xx-vbi.o em28xx-camera.o
> +em28xx-y +=	em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
>  
> +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
>  em28xx-alsa-objs := em28xx-audio.o
>  em28xx-rc-objs := em28xx-input.o
>  
>  obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
> +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
>  obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
>  obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
>  obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
> diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
> index d666741797d4..c29f5c4e7b40 100644
> --- a/drivers/media/usb/em28xx/em28xx-camera.c
> +++ b/drivers/media/usb/em28xx/em28xx-camera.c
> @@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
>  
>  	return ret;
>  }
> +EXPORT_SYMBOL_GPL(em28xx_init_camera);
> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
> index dbce4dc421f9..b25869331284 100644
> --- a/drivers/media/usb/em28xx/em28xx-cards.c
> +++ b/drivers/media/usb/em28xx/em28xx-cards.c
> @@ -2159,6 +2159,8 @@ struct em28xx_board em28xx_boards[] = {
>  		.ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
>  	},
>  };
> +EXPORT_SYMBOL_GPL(em28xx_boards);
> +
>  const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
>  
>  /* table of devices that work with this driver */
> @@ -2780,11 +2782,12 @@ static void request_module_async(struct work_struct *work)
>  	em28xx_init_extension(dev);
>  
>  #if defined(CONFIG_MODULES) && defined(MODULE)
> +	if (dev->has_video)
> +		request_module("em28xx-v4l");
>  	if (dev->has_audio_class)
>  		request_module("snd-usb-audio");
>  	else if (dev->has_alsa_audio)
>  		request_module("em28xx-alsa");
> -
>  	if (dev->board.has_dvb)
>  		request_module("em28xx-dvb");
>  	if (dev->board.buttons ||
> @@ -2813,18 +2816,12 @@ void em28xx_release_resources(struct em28xx *dev)
>  {
>  	/*FIXME: I2C IR should be disconnected */
>  
> -	em28xx_release_analog_resources(dev);
> -
>  	if (dev->def_i2c_bus)
>  		em28xx_i2c_unregister(dev, 1);
>  	em28xx_i2c_unregister(dev, 0);
>  	if (dev->clk)
>  		v4l2_clk_unregister_fixed(dev->clk);
>  
> -	v4l2_ctrl_handler_free(&dev->ctrl_handler);
> -
> -	v4l2_device_unregister(&dev->v4l2_dev);
> -
>  	usb_put_dev(dev->udev);
>  
>  	/* Mark device as unused */
> @@ -2999,18 +2996,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
>  	/* Do board specific init and eeprom reading */
>  	em28xx_card_setup(dev);
>  
> -	retval = em28xx_register_analog_devices(dev);
> -	if (retval < 0)
> -		goto fail;
> -
>  	return 0;
> -
> -fail:
> -	if (dev->def_i2c_bus)
> -		em28xx_i2c_unregister(dev, 1);
> -	em28xx_i2c_unregister(dev, 0);
> -
> -	return retval;
>  }
>  
>  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
> @@ -3213,6 +3199,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	dev->alt   = -1;
>  	dev->is_audio_only = has_audio && !(has_video || has_dvb);
>  	dev->has_alsa_audio = has_audio;
> +	dev->has_video = has_video;
>  	dev->audio_ifnum = ifnum;
>  
>  	/* Checks if audio is provided by some interface */
> @@ -3252,10 +3239,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  
>  	/* allocate device struct */
>  	mutex_init(&dev->lock);
> -	mutex_lock(&dev->lock);
>  	retval = em28xx_init_dev(dev, udev, interface, nr);
>  	if (retval) {
> -		goto unlock_and_free;
> +		goto err_free;
>  	}
>  
>  	if (usb_xfer_mode < 0) {
> @@ -3298,7 +3284,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  		if (retval) {
>  			printk(DRIVER_NAME
>  			       ": Failed to pre-allocate USB transfer buffers for DVB.\n");
> -			goto unlock_and_free;
> +			goto err_free;
>  		}
>  	}
>  
> @@ -3307,13 +3293,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
>  	/* Should be the last thing to do, to avoid newer udev's to
>  	   open the device before fully initializing it
>  	 */
> -	mutex_unlock(&dev->lock);
>  
>  	return 0;
>  
> -unlock_and_free:
> -	mutex_unlock(&dev->lock);
> -
>  err_free:
>  	kfree(dev->alt_max_pkt_size_isoc);
>  	kfree(dev);
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index f77301773aee..c416dd33af3f 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -33,6 +33,18 @@
>  
>  #include "em28xx.h"
>  
> +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
> +		      "Markus Rechberger <mrechberger@gmail.com>, " \
> +		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
> +		      "Sascha Sommer <saschasommer@freenet.de>"
> +
> +#define DRIVER_DESC         "Empia em28xx based USB core driver"
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(EM28XX_VERSION);
> +
>  /* #define ENABLE_DEBUG_ISOC_FRAMES */
>  
>  static unsigned int core_debug;
> diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
> new file mode 100644
> index 000000000000..bce438691e0e
> --- /dev/null
> +++ b/drivers/media/usb/em28xx/em28xx-v4l.h
> @@ -0,0 +1,20 @@
> +/*
> +   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
> +		    video capture devices
> +
> +   Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> + */
> +
> +
> +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> +int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> +extern struct vb2_ops em28xx_vbi_qops;
> diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
> index 39f39c527c13..db3d655600df 100644
> --- a/drivers/media/usb/em28xx/em28xx-vbi.c
> +++ b/drivers/media/usb/em28xx/em28xx-vbi.c
> @@ -27,6 +27,7 @@
>  #include <linux/init.h>
>  
>  #include "em28xx.h"
> +#include "em28xx-v4l.h"
>  
>  static unsigned int vbibufs = 5;
>  module_param(vbibufs, int, 0644);
> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
> index 3726af134f39..78a1bfb97c3d 100644
> --- a/drivers/media/usb/em28xx/em28xx-video.c
> +++ b/drivers/media/usb/em28xx/em28xx-video.c
> @@ -38,6 +38,7 @@
>  #include <linux/slab.h>
>  
>  #include "em28xx.h"
> +#include "em28xx-v4l.h"
>  #include <media/v4l2-common.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-event.h>
> @@ -141,7 +142,7 @@ static struct em28xx_fmt format[] = {
>  	},
>  };
>  
> -int em28xx_vbi_supported(struct em28xx *dev)
> +static int em28xx_vbi_supported(struct em28xx *dev)
>  {
>  	/* Modprobe option to manually disable */
>  	if (disable_vbi == 1)
> @@ -164,7 +165,7 @@ int em28xx_vbi_supported(struct em28xx *dev)
>   * em28xx_wake_i2c()
>   * configure i2c attached devices
>   */
> -void em28xx_wake_i2c(struct em28xx *dev)
> +static void em28xx_wake_i2c(struct em28xx *dev)
>  {
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
> @@ -172,7 +173,7 @@ void em28xx_wake_i2c(struct em28xx *dev)
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
>  }
>  
> -int em28xx_colorlevels_set_default(struct em28xx *dev)
> +static int em28xx_colorlevels_set_default(struct em28xx *dev)
>  {
>  	em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
>  	em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
> @@ -190,7 +191,7 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
>  	return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
>  }
>  
> -int em28xx_set_outfmt(struct em28xx *dev)
> +static int em28xx_set_outfmt(struct em28xx *dev)
>  {
>  	int ret;
>  	u8 fmt, vinctrl;
> @@ -297,7 +298,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
>  }
>  
>  /* FIXME: this only function read values from dev */
> -int em28xx_resolution_set(struct em28xx *dev)
> +static int em28xx_resolution_set(struct em28xx *dev)
>  {
>  	int width, height;
>  	width = norm_maxw(dev);
> @@ -330,7 +331,7 @@ int em28xx_resolution_set(struct em28xx *dev)
>  }
>  
>  /* Set USB alternate setting for analog video */
> -int em28xx_set_alternate(struct em28xx *dev)
> +static int em28xx_set_alternate(struct em28xx *dev)
>  {
>  	int errCode;
>  	int i;
> @@ -1020,7 +1021,7 @@ static struct vb2_ops em28xx_video_qops = {
>  	.wait_finish    = vb2_ops_wait_finish,
>  };
>  
> -int em28xx_vb2_setup(struct em28xx *dev)
> +static int em28xx_vb2_setup(struct em28xx *dev)
>  {
>  	int rc;
>  	struct vb2_queue *q;
> @@ -1088,7 +1089,7 @@ static void video_mux(struct em28xx *dev, int index)
>  	em28xx_audio_analog_set(dev);
>  }
>  
> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
> +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
>  {
>  	struct em28xx *dev = priv;
>  
> @@ -1625,7 +1626,7 @@ static int vidioc_g_register(struct file *file, void *priv,
>  		reg->val = ret;
>  	} else {
>  		__le16 val = 0;
> -		ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
> +		ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
>  						   reg->reg, (char *)&val, 2);
>  		if (ret < 0)
>  			return ret;
> @@ -1872,15 +1873,12 @@ static int em28xx_v4l2_open(struct file *filp)
>  }
>  
>  /*
> - * em28xx_realease_resources()
> + * em28xx_v4l2_fini()
>   * unregisters the v4l2,i2c and usb devices
>   * called when the device gets disconected or at module unload
>  */
> -void em28xx_release_analog_resources(struct em28xx *dev)
> +static int em28xx_v4l2_fini(struct em28xx *dev)
>  {
> -
> -	/*FIXME: I2C IR should be disconnected */
> -
>  	if (dev->radio_dev) {
>  		if (video_is_registered(dev->radio_dev))
>  			video_unregister_device(dev->radio_dev);
> @@ -1906,6 +1904,8 @@ void em28xx_release_analog_resources(struct em28xx *dev)
>  			video_device_release(dev->vdev);
>  		dev->vdev = NULL;
>  	}
> +
> +	return 0;
>  }
>  
>  /*
> @@ -1927,12 +1927,12 @@ static int em28xx_v4l2_close(struct file *filp)
>  	if (dev->users == 1) {
>  		/* the device is already disconnect,
>  		   free the remaining resources */
> +
>  		if (dev->disconnected) {
> -			em28xx_release_resources(dev);
Ok, this is the last remaining issue with this patch.

I've tested it without removing this call and the core/v4l2 split
doesn't cause any trouble.
I've also verified that em28xx_v4l2_close() is still called although the
extensions are already unregistered at that time.

As discussed in the previous mail this evening, keeping it here is still
better than never releasing the resources.
We can fix the whole extensions+resources releasing later.


With this change:
Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Tested-by: Frank Schäfer <fschaefer.oss@googlemail.com>


> +			v4l2_ctrl_handler_free(&dev->ctrl_handler);
> +			v4l2_device_unregister(&dev->v4l2_dev);
>  			kfree(dev->alt_max_pkt_size_isoc);
> -			mutex_unlock(&dev->lock);
> -			kfree(dev);
> -			return 0;
> +			goto exit;
>  		}
>  
>  		/* Save some power by putting tuner to sleep */
> @@ -1951,6 +1951,7 @@ static int em28xx_v4l2_close(struct file *filp)
>  		}
>  	}
>  
> +exit:
>  	dev->users--;
>  	mutex_unlock(&dev->lock);
>  	return 0;
> @@ -2065,8 +2066,6 @@ static unsigned short msp3400_addrs[] = {
>  
>  /******************************** usb interface ******************************/
>  
> -
> -
>  static struct video_device *em28xx_vdev_init(struct em28xx *dev,
>  					const struct video_device *template,
>  					const char *type_name)
> @@ -2140,7 +2139,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
>  	}
>  }
>  
> -void em28xx_tuner_setup(struct em28xx *dev)
> +static void em28xx_tuner_setup(struct em28xx *dev)
>  {
>  	struct tuner_setup           tun_setup;
>  	struct v4l2_frequency        f;
> @@ -2199,14 +2198,14 @@ void em28xx_tuner_setup(struct em28xx *dev)
>  	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
>  }
>  
> -int em28xx_register_analog_devices(struct em28xx *dev)
> +static int em28xx_v4l2_init(struct em28xx *dev)
>  {
>  	u8 val;
>  	int ret;
>  	unsigned int maxw;
>  	struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
>  
> -	if (dev->is_audio_only) {
> +	if (!dev->has_video) {
>  		/* This device does not support the v4l2 extension */
>  		return 0;
>  	}
> @@ -2214,6 +2213,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	printk(KERN_INFO "%s: v4l2 driver version %s\n",
>  		dev->name, EM28XX_VERSION);
>  
> +	mutex_lock(&dev->lock);
> +
>  	ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
>  	if (ret < 0) {
>  		em28xx_errdev("Call to v4l2_device_register() failed!\n");
> @@ -2492,11 +2493,33 @@ int em28xx_register_analog_devices(struct em28xx *dev)
>  	/* initialize videobuf2 stuff */
>  	em28xx_vb2_setup(dev);
>  
> +	mutex_unlock(&dev->lock);
>  	return 0;
>  
>  unregister_dev:
>  	v4l2_ctrl_handler_free(&dev->ctrl_handler);
>  	v4l2_device_unregister(&dev->v4l2_dev);
>  err:
> +	mutex_unlock(&dev->lock);
>  	return ret;
>  }
> +
> +static struct em28xx_ops v4l2_ops = {
> +	.id   = EM28XX_V4L2,
> +	.name = "Em28xx v4l2 Extension",
> +	.init = em28xx_v4l2_init,
> +	.fini = em28xx_v4l2_fini,
> +};
> +
> +static int __init em28xx_video_register(void)
> +{
> +	return em28xx_register_extension(&v4l2_ops);
> +}
> +
> +static void __exit em28xx_video_unregister(void)
> +{
> +	em28xx_unregister_extension(&v4l2_ops);
> +}
> +
> +module_init(em28xx_video_register);
> +module_exit(em28xx_video_unregister);
> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> index 7ae05ebc13c1..9d6f43e4681f 100644
> --- a/drivers/media/usb/em28xx/em28xx.h
> +++ b/drivers/media/usb/em28xx/em28xx.h
> @@ -26,7 +26,7 @@
>  #ifndef _EM28XX_H
>  #define _EM28XX_H
>  
> -#define EM28XX_VERSION "0.2.0"
> +#define EM28XX_VERSION "0.2.1"
>  
>  #include <linux/workqueue.h>
>  #include <linux/i2c.h>
> @@ -474,6 +474,7 @@ struct em28xx_eeprom {
>  #define EM28XX_AUDIO   0x10
>  #define EM28XX_DVB     0x20
>  #define EM28XX_RC      0x30
> +#define EM28XX_V4L2    0x40
>  
>  /* em28xx resource types (used for res_get/res_lock etc */
>  #define EM28XX_RESOURCE_VIDEO 0x01
> @@ -527,6 +528,7 @@ struct em28xx {
>  
>  	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
>  	unsigned char disconnected:1;	/* device has been diconnected */
> +	unsigned int has_video:1;
>  	unsigned int has_audio_class:1;
>  	unsigned int has_alsa_audio:1;
>  	unsigned int is_audio_only:1;
> @@ -723,14 +725,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
>  int em28xx_audio_analog_set(struct em28xx *dev);
>  int em28xx_audio_setup(struct em28xx *dev);
>  
> -int em28xx_colorlevels_set_default(struct em28xx *dev);
>  const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
>  					 enum em28xx_led_role role);
>  int em28xx_capture_start(struct em28xx *dev, int start);
> -int em28xx_vbi_supported(struct em28xx *dev);
> -int em28xx_set_outfmt(struct em28xx *dev);
> -int em28xx_resolution_set(struct em28xx *dev);
> -int em28xx_set_alternate(struct em28xx *dev);
>  int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
>  		      int num_bufs, int max_pkt_size, int packet_multiplier);
>  int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
> @@ -742,31 +739,17 @@ 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);
> -void em28xx_wake_i2c(struct em28xx *dev);
>  int em28xx_register_extension(struct em28xx_ops *dev);
>  void em28xx_unregister_extension(struct em28xx_ops *dev);
>  void em28xx_init_extension(struct em28xx *dev);
>  void em28xx_close_extension(struct em28xx *dev);
>  
> -/* Provided by em28xx-video.c */
> -void em28xx_tuner_setup(struct em28xx *dev);
> -int em28xx_vb2_setup(struct em28xx *dev);
> -int em28xx_register_analog_devices(struct em28xx *dev);
> -void em28xx_release_analog_resources(struct em28xx *dev);
> -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
> -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
> -int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
> -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
> -
>  /* Provided by em28xx-cards.c */
>  extern 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_release_resources(struct em28xx *dev);
>  
> -/* Provided by em28xx-vbi.c */
> -extern struct vb2_ops em28xx_vbi_qops;
> -
>  /* Provided by em28xx-camera.c */
>  int em28xx_detect_sensor(struct em28xx *dev);
>  int em28xx_init_camera(struct em28xx *dev);
>


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

* Re: [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code
  2014-01-05 15:44       ` Mauro Carvalho Chehab
@ 2014-01-07 16:50         ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-07 16:50 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Mauro Carvalho Chehab; +Cc: Linux Media Mailing List

Am 05.01.2014 16:44, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 11:20:02 -0200
> Mauro Carvalho Chehab <m.chehab@samsung.com> escreveu:
>
>> Em Sun, 05 Jan 2014 12:19:41 +0100
>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>
>>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>>> Instead of assuming that msleep() is precise, use a jiffies
>>>> based code to wait for AC97 to be available.
>>>>
>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>> ---
>>>>  drivers/media/usb/em28xx/em28xx-core.c | 7 +++++--
>>>>  drivers/media/usb/em28xx/em28xx.h      | 5 ++++-
>>>>  2 files changed, 9 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
>>>> index 818248d3fd28..36b2f1ab4474 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx-core.c
>>>> +++ b/drivers/media/usb/em28xx/em28xx-core.c
>>>> @@ -23,6 +23,7 @@
>>>>   */
>>>>  
>>>>  #include <linux/init.h>
>>>> +#include <linux/jiffies.h>
>>>>  #include <linux/list.h>
>>>>  #include <linux/module.h>
>>>>  #include <linux/slab.h>
>>>> @@ -254,16 +255,18 @@ EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
>>>>   */
>>>>  static int em28xx_is_ac97_ready(struct em28xx *dev)
>>>>  {
>>>> -	int ret, i;
>>>> +	unsigned long timeout = jiffies + msecs_to_jiffies(EM2800_AC97_XFER_TIMEOUT);
>>>> +	int ret;
>>>>  
>>>>  	/* Wait up to 50 ms for AC97 command to complete */
>>>> -	for (i = 0; i < 10; i++, msleep(5)) {
>>>> +	while (time_is_after_jiffies(timeout)) {
>>> time_is_before_jiffies(timeout)
>>>
>>>>  		ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
>>>>  		if (ret < 0)
>>>>  			return ret;
>>>>  
>>>>  		if (!(ret & 0x01))
>>>>  			return 0;
>>>> +		msleep (5);
>>>>  	}
>>>>  
>>>>  	em28xx_warn("AC97 command still being executed: not handled properly!\n");
>>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>>> index 9d6f43e4681f..ac79501f5d9f 100644
>>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>>> @@ -182,9 +182,12 @@
>>>>  
>>>>  #define EM28XX_INTERLACED_DEFAULT 1
>>>>  
>>>> -/* time in msecs to wait for i2c writes to finish */
>>>> +/* time in msecs to wait for i2c xfers to finish */
>>>>  #define EM2800_I2C_XFER_TIMEOUT		20
>>>>  
>>>> +/* time in msecs to wait for AC97 xfers to finish */
>>>> +#define EM2800_AC97_XFER_TIMEOUT	100
>>>> +
>>> I applies to all chips supporting AC97 audio, so call it
>>> EM28XX_AC97_XFER_TIMEOUT.
>> Ok.
>>
>>> Why did you increase the timeout from 50ms to 100ms ?
>>> 50ms already seems to be a lot !
> Err... actually, the code is currently waiting for up to 100ms.
>
> The thing is that msleep(5) will wait for a minimum time of 1/CONFIG_HZ.
>
> If CONFIG_HZ is equal to 100 (the minimum), that means that it will
> wait for 10 ms. So,
>
> for (i = 0; i < 10; i++, msleep(5)) {
> 	...
> }
>
> Will actually wait up to 10*10ms = 100ms at the worse case. 
>
> The patch is just keeping the maximum timeout equal for all setups, no
> matter what's set at CONFIG_HZ.
>
> Arbitrarily changing it to a lower value seems risky, as it may cause
> regressions on some boards.
>
> So, I'll just rename the define here, preserving 100ms as timeout.
>
> Regards,
> Mauro
Ok, then it makes sense.
I'm pretty sure 100ms is much more than needed and it seems to work for
those people using a CONFIG_HZ value higher 100.
But for now let's keep it as.

Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>



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

* Re: [PATCH v4 13/22] [media] em28xx: initialize audio latter
  2014-01-05 13:17     ` Mauro Carvalho Chehab
@ 2014-01-07 17:00       ` Frank Schäfer
  2014-01-08 14:29         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-07 17:00 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 14:17, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 12:29:11 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> Better to first write the GPIOs of the input mux, before initializing
>>> the audio.
>> Why are you making this change ?
>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-video.c | 40 ++++++++++++++++-----------------
>>>  1 file changed, 20 insertions(+), 20 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
>>> index b767262c642b..328d724a13ea 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-video.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-video.c
>>> @@ -2291,26 +2291,6 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>  	em28xx_tuner_setup(dev);
>>>  	em28xx_init_camera(dev);
>>>  
>>> -	/* Configure audio */
>>> -	ret = em28xx_audio_setup(dev);
>>> -	if (ret < 0) {
>>> -		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
>>> -			__func__, ret);
>>> -		goto err;
>>> -	}
>>> -	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
>>> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
>>> -			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
>>> -		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
>>> -			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
>>> -	} else {
>>> -		/* install the em28xx notify callback */
>>> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
>>> -				em28xx_ctrl_notify, dev);
>>> -		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
>>> -				em28xx_ctrl_notify, dev);
>>> -	}
>>> -
>>>  	/* wake i2c devices */
>>>  	em28xx_wake_i2c(dev);
>>>  
>>> @@ -2356,6 +2336,26 @@ static int em28xx_v4l2_init(struct em28xx *dev)
>>>  
>>>  	video_mux(dev, 0);
>>>  
>>> +	/* Configure audio */
>>> +	ret = em28xx_audio_setup(dev);
>>> +	if (ret < 0) {
>>> +		em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
>>> +			__func__, ret);
>>> +		goto err;
>>> +	}
>>> +	if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
>>> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
>>> +			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
>>> +		v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
>>> +			V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
>>> +	} else {
>>> +		/* install the em28xx notify callback */
>>> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
>>> +				em28xx_ctrl_notify, dev);
>>> +		v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
>>> +				em28xx_ctrl_notify, dev);
>>> +	}
>>> +
>>>  	/* Audio defaults */
>>>  	dev->mute = 1;
>>>  	dev->volume = 0x1f;
>> Well, the v4l/core split didn't change the order.
>> And if the current order would be wrong, then you would also have to
>> call audio_setup() each time the user switches the input.
> Maybe this is needed anyway. Btw, there's a bug on xawtv: if you maximize
> a window, audio stops playing. I didn't have time yet to identify why.
>
>> So unless you are trying to fix a real bug, I wouldn't change it.
>> The current order is sane and we likely could never change it back later
>> without risking regressions...
> Sometimes, ac97 is not properly detected here with HVR-950. Not sure
> what happens. I need to do more tests. Perhaps it happens only on USB 3.0
> ports.
So you are making yet another change to fix a bug, although you even
haven't identified yet what the bug is ?

> In any case, it makes sense to first wake up I2C devices, then to set
> the video mux, before start probing for audio, as the audio setting
> may depend on the video mux settings.
>
You are ignoring what I said.

1.) If the current order would really be wrong, we would have bugs. But
we don't know any bugs caused by the current order.
2.) If you change the order, it is also necessary to wake up or even do
the whole setup again after each input switch (video_mux() call).
This patch misses this fix. So there is a chance that you are causing
regressions.
3.) We can always do this change later, but we likely can't revert it
anymore after a while (without retesting all device that have been added
in the meantime)

The whole gpio sequences stuff and its unknown effects on the
power/reset state of the subdevices has already turned em28xx
maintenance into a nightmare.
There is lots of problematic code which can never be fixed without
testing all ~100 devices.
Let's not walk needlessly into the same trap with yet another piece of code.



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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-05 21:25     ` Mauro Carvalho Chehab
  2014-01-06 16:25       ` Mauro Carvalho Chehab
@ 2014-01-07 17:03       ` Frank Schäfer
  2014-01-08 14:10         ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-07 17:03 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 22:25, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 22:02:40 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> From: Mauro Carvalho Chehab <mchehab@redhat.com>
>> Is this line still correct ? ;)
>>
>>> Instead of allocating/deallocating URBs and transfer buffers
>>> every time stream is started/stopped, just do it once.
>>>
>>> That reduces the memory allocation pressure and makes the
>>> code that start/stop streaming a way simpler.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>> Two Signed-off-by lines ? ;)
>>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
>>>  1 file changed, 73 insertions(+), 55 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>> index e5120430ec80..30ee389a07f0 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>> @@ -3,7 +3,7 @@
>>>   *
>>>   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
>>>   *
>>> - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
>>> + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
>>>   *	- Port to work with the in-kernel driver
>>>   *	- Cleanups, fixes, alsa-controls, etc.
>>>   *
>>> @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
>>>  			usb_kill_urb(urb);
>>>  		else
>>>  			usb_unlink_urb(urb);
>>> -
>>> -		usb_free_coherent(dev->udev,
>>> -				  urb->transfer_buffer_length,
>>> -				  dev->adev.transfer_buffer[i],
>>> -				  urb->transfer_dma);
>>> -
>>> -		dev->adev.transfer_buffer[i] = NULL;
>>> -
>>> -		usb_free_urb(urb);
>>> -		dev->adev.urb[i] = NULL;
>>>  	}
>>>  
>>>  	return 0;
>>> @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
>>>  static int em28xx_init_audio_isoc(struct em28xx *dev)
>>>  {
>>>  	int       i, errCode;
>>> -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>  
>>>  	dprintk("Starting isoc transfers\n");
>>>  
>>> +	/* Start streaming */
>>>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> -		struct urb *urb;
>>> -		int j, k;
>>> -		void *buf;
>>> -
>>> -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>> -		if (!urb) {
>>> -			em28xx_errdev("usb_alloc_urb failed!\n");
>>> -			for (j = 0; j < i; j++) {
>>> -				usb_free_urb(dev->adev.urb[j]);
>>> -				kfree(dev->adev.transfer_buffer[j]);
>>> -			}
>>> -			return -ENOMEM;
>>> -		}
>>> -
>>> -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>> -					 &urb->transfer_dma);
>>> -		if (!buf)
>>> -			return -ENOMEM;
>>> -		dev->adev.transfer_buffer[i] = buf;
>>> -		memset(buf, 0x80, sb_size);
>>> -
>>> -		urb->dev = dev->udev;
>>> -		urb->context = dev;
>>> -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>> -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>> -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>> -		urb->interval = 1;
>>> -		urb->complete = em28xx_audio_isocirq;
>>> -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>> -		urb->transfer_buffer_length = sb_size;
>>> -
>>> -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>> -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>> -			urb->iso_frame_desc[j].offset = k;
>>> -			urb->iso_frame_desc[j].length =
>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>> -		}
>>> -		dev->adev.urb[i] = urb;
>>> -	}
>>> +		memset(dev->adev.transfer_buffer[i], 0x80,
>>> +		       dev->adev.urb[i]->transfer_buffer_length);
>>>  
>>> -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
>>>  		if (errCode) {
>>>  			em28xx_errdev("submit of audio urb failed\n");
>>> @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
>>>  	.page      = snd_pcm_get_vmalloc_page,
>>>  };
>>>  
>>> +static void em28xx_audio_free_urb(struct em28xx *dev)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> +		struct urb *urb = dev->adev.urb[i];
>>> +
>>> +		if (!dev->adev.urb[i])
>>> +			continue;
>>> +
>>> +		usb_free_coherent(dev->udev,
>>> +				  urb->transfer_buffer_length,
>>> +				  dev->adev.transfer_buffer[i],
>>> +				  urb->transfer_dma);
>>> +
>>> +		usb_free_urb(urb);
>>> +		dev->adev.urb[i] = NULL;
>>> +		dev->adev.transfer_buffer[i] = NULL;
>>> +	}
>>> +}
>>> +
>>>  static int em28xx_audio_init(struct em28xx *dev)
>>>  {
>>>  	struct em28xx_audio *adev = &dev->adev;
>>>  	struct snd_pcm      *pcm;
>>>  	struct snd_card     *card;
>>>  	static int          devnr;
>>> -	int                 err;
>>> +	int                 err, i;
>>> +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>  
>>>  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
>>>  		/* This device does not support the extension (in this case
>>> @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  
>>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>  			 "Rechberger\n");
>>> -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
>>> +	printk(KERN_INFO
>>> +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
>>>  
>>>  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
>>>  			      &card);
>>> @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
>>>  	}
>>>  
>>> +	/* Alloc URB and transfer buffers */
>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>> +		struct urb *urb;
>>> +		int j, k;
>>> +		void *buf;
>>> +
>>> +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>> +		if (!urb) {
>>> +			em28xx_errdev("usb_alloc_urb failed!\n");
>>> +			em28xx_audio_free_urb(dev);
>>> +			return -ENOMEM;
>>> +		}
>>> +		dev->adev.urb[i] = urb;
>>> +
>>> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>> +					 &urb->transfer_dma);
>>> +		if (!buf) {
>>> +			em28xx_errdev("usb_alloc_coherent failed!\n");
>>> +			em28xx_audio_free_urb(dev);
>>> +			return -ENOMEM;
>>> +		}
>>> +		dev->adev.transfer_buffer[i] = buf;
>>> +
>>> +		urb->dev = dev->udev;
>>> +		urb->context = dev;
>>> +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>> +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>> +		urb->interval = 1;
>>> +		urb->complete = em28xx_audio_isocirq;
>>> +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>> +		urb->transfer_buffer_length = sb_size;
>>> +
>>> +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>> +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>> +			urb->iso_frame_desc[j].offset = k;
>>> +			urb->iso_frame_desc[j].length =
>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>> +		}
>>> +	}
>>> +
>>>  	err = snd_card_register(card);
>>>  	if (err < 0) {
>>>  		snd_card_free(card);
>>> @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>  		return 0;
>>>  	}
>>>  
>>> +	em28xx_audio_free_urb(dev);
>>> +
>>>  	if (dev->adev.sndcard) {
>>>  		snd_card_free(dev->adev.sndcard);
>>>  		dev->adev.sndcard = NULL;
>> I don't get it.
>> How does this patch reduce the memory allocation pressure ?
>> You are still allocating the same amount of memory.
> True, but it is not de-allocating/reallocating the same amount of
> memory every time, for every start/stop trigger. Depending on the
> userspace and the amount of available RAM, this could cause memory 
> fragmentation.
>
> If you take a look at xHCI logs, you'll see that those operations
> are very expensive, and that it occurs too often.
How often is the device started/stopped ?
It's nothing that happens often/with a high freuqency, so is memeory
fragmentation really a problem here ?

>
>> The only differences is that you already do this when the device isn't
>> used yet and don't free it when gets unused again.
>> IMHO that makes things worse, not better.
> Why is it worse?
Because you increase the memory usage of closed devices.

> FYI, we're currently allocating DVB buffers at the device init too,
> due to the memory fragmentation problems. This is actually critical
> if you try to use it on an ARM with limited amount of RAM.
I was always wondering why.

Ok, if this really solves problems on ARM, do it.
I assume it makes sense fix it for analog video, too. ;)

>
>> And yes, it makes the code that starts/stops streaming a way simpler.
>> But at the same time it makes the module initialization code the same
>> amount more complicated.
>
>


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

* Re: [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts
  2014-01-05 20:57     ` Mauro Carvalho Chehab
@ 2014-01-07 17:15       ` Frank Schäfer
  2014-01-08 14:39         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-07 17:15 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 05.01.2014 21:57, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 21:38:31 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> In the lack of a better spec, let's assume the timeout
>>> values compatible with SMBus spec:
>>> 	http://smbus.org/specs/smbus110.pdf
>>>
>>> at chapter 8 - Electrical Characteristics of SMBus devices
>>>
>>> Ok, SMBus is a subset of I2C, and not all devices will be
>>> following it, but the timeout value before this patch was not
>>> even following the spec.
>>>
>>> So, while we don't have a better guess for it, use 35 + 1
>>> ms as the timeout.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx.h | 17 +++++++++++++++--
>>>  1 file changed, 15 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
>>> index db47c2236ca4..9af19332b0f1 100644
>>> --- a/drivers/media/usb/em28xx/em28xx.h
>>> +++ b/drivers/media/usb/em28xx/em28xx.h
>>> @@ -183,8 +183,21 @@
>>>  
>>>  #define EM28XX_INTERLACED_DEFAULT 1
>>>  
>>> -/* time in msecs to wait for i2c xfers to finish */
>>> -#define EM2800_I2C_XFER_TIMEOUT		20
>>> +/*
>>> + * 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 EM2800_I2C_XFER_TIMEOUT		36
>>>  
>>>  /* time in msecs to wait for AC97 xfers to finish */
>>>  #define EM2800_AC97_XFER_TIMEOUT	100
>> Mauro...
>> What exactly are you fixing with this patch ?
> It fixes some of the timeouts I noticed here with HVR-950.
>
>> Which devices are not working with the current timeout value ?
>>
>> You really shouldn't increase the timout to 172% for all devices based
>> on such a fragile pure theory.
> It is not fragile. It is the SMBUS spec. It should _at_least_ wait up to
> the timeout specified there.
>
> Btw, it is not increasing the timeout. It is actually reducing it.
>
> See, this is the code before the patch:
>
> for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
> 	     read_timeout -= 5) {
> 		ret = dev->em28xx_read_reg(dev, 0x05);
> 		if (ret == 0x84 + len - 1) {
> 			break;
> 		} else if (ret == 0x94 + len - 1) {
> 			return -ENODEV;
> 		} else if (ret < 0) {
> 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> 				    ret);
> 			return ret;
> 		}
> 		msleep(5);
> 	}
>
> msleep(5) actually sleeps up to 20 ms, as the minimal time is the
> schedule() time - being 10 ms a typical value (CONFIG_HZ equal to 100). 
>
> So, the current code has a timeout of up to 100 ms.
20ms / 5ms = 4.
4 * 10ms = 40ms ?

> This patch is actually reducing from 100 ms to 36 ms.
Ok, it's the same as with AC97 reads/writes.
I would accept any value from 20ms to 40ms.

> Regards,
> Mauro


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

* Re: [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-06  9:55     ` Mauro Carvalho Chehab
@ 2014-01-07 17:28       ` Frank Schäfer
  2014-01-08 11:55         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 80+ messages in thread
From: Frank Schäfer @ 2014-01-07 17:28 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 06.01.2014 10:55, schrieb Mauro Carvalho Chehab:
> Em Sun, 05 Jan 2014 21:40:38 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>> The proper error code for I2C errors are EREMOTEIO. The em28xx driver
>>> is using EIO instead.
>>>
>>> Replace all occurrences of EIO at em28xx-i2c, in order to fix it.
>>>
>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>> ---
>>>  drivers/media/usb/em28xx/em28xx-i2c.c | 20 ++++++++++----------
>>>  1 file changed, 10 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
>>> index 9fa7ed51e5b1..8b35aa51b9bb 100644
>>> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
>>> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
>>> @@ -72,7 +72,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  	if (ret != 2 + len) {
>>>  		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
>>>  			    addr, ret);
>>> -		return (ret < 0) ? ret : -EIO;
>>> +		return (ret < 0) ? ret : -EREMOTEIO;
>>>  	}
>>>  	/* wait for completion */
>>>  	while (time_is_after_jiffies(timeout)) {
>>> @@ -91,7 +91,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  		msleep(5);
>>>  	}
>>>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>>> -	return -EIO;
>>> +	return -EREMOTEIO;
>>>  }
>>>  
>>>  /*
>>> @@ -115,7 +115,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  	if (ret != 2) {
>>>  		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
>>>  			    addr, ret);
>>> -		return (ret < 0) ? ret : -EIO;
>>> +		return (ret < 0) ? ret : -EREMOTEIO;
>>>  	}
>>>  
>>>  	/* wait for completion */
>>> @@ -142,7 +142,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
>>>  	if (ret != len) {
>>>  		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
>>>  			    addr, ret);
>>> -		return (ret < 0) ? ret : -EIO;
>>> +		return (ret < 0) ? ret : -EREMOTEIO;
>>>  	}
>>>  	for (i = 0; i < len; i++)
>>>  		buf[i] = buf2[len - 1 - i];
>>> @@ -162,7 +162,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
>>>  	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
>>>  	if (ret == 1)
>>>  		return 0;
>>> -	return (ret < 0) ? ret : -EIO;
>>> +	return (ret < 0) ? ret : -EREMOTEIO;
>>>  }
>>>  
>>>  /*
>>> @@ -191,7 +191,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>>>  		} else {
>>>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
>>>  				    len, addr, ret);
>>> -			return -EIO;
>>> +			return -EREMOTEIO;
>>>  		}
>>>  	}
>>>  
>>> @@ -219,7 +219,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>>>  	}
>>>  
>>>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
>>> -	return -EIO;
>>> +	return -EREMOTEIO;
>>>  }
>>>  
>>>  /*
>>> @@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
>>>  	}
>>>  
>>>  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
>>> -	return -EIO;
>>> +	return -EREMOTEIO;
>>>  }
>>>  
>>>  /*
>>> @@ -283,7 +283,7 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
>>>  	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
>>>  	if (ret == 1)
>>>  		return 0;
>>> -	return (ret < 0) ? ret : -EIO;
>>> +	return (ret < 0) ? ret : -EREMOTEIO;
>>>  }
>>>  
>>>  /*
>>> @@ -312,7 +312,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
>>>  		} else {
>>>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
>>>  				    len, addr, ret);
>>> -			return -EIO;
>>> +			return -EREMOTEIO;
>>>  		}
>>>  	}
>>>  	/* Check success */
>> Why the hell -EREMOTEIO ???
>> See Documentation/i2c/fault-codes.
>> It's not even listed there !
>> What are you trying to fix here ?
> This is not a fixup patch.
>
> The idea of this path is to make em28xx more compliant with the Kernel
> error codes. 
>
> As em28xx was the first USB media driver, it doesn't follow the best 
> standards, despite all efforts we've made back in 2005, when the driver
> was merged, in order to follow the Kernel rules. We eventually fixed
> several things along the time, but we didn't took much care to fix the
> I2C error codes so far.
>
> Now that we're taking care of it, we should do it right.
>
> However, you're actually right here.
>
> Before 2011, all I2C drivers under drivers/i2c used to return EREMOTEIO,
> and the media drivers were moving to this error code since then.
Ok, that explains it.

> But it seems that we missed a series of patches that moved I2C away from
> EREMOTEIO:
> 	http://www.spinics.net/lists/linux-i2c/msg06395.html
> 	https://www.mail-archive.com/linux-i2c@vger.kernel.org/msg04819.html
>
> I'll rewrite this patch to return the right error codes, according with
> Documentation/i2c/fault-codes.
>
> It seems that the proper return codes are:
>
> 	- ETIMEDOUT - when reg 05 returns 0x10
I still don't agree here.
AFAICS an I2C timeout can only happen if clock stretching is used.
But we also get this when a slave device isn't present or doesn't
answer, which means it doesn't ACK the data.
So ETIMEDOUT is wrong.
Yes, 0x10 _could_ be a more general error. In that case EIO would be the
better choice.
But that's pure speculation as long as we don't have the datasheets.

After reading the i2c fault codes descriptions again, I would agree to
change it from ENODEV to ENXIO.
ENXIO seems to be the intended error code for NACK errors and it's a bit
more unspecific than ENODEV.

Would that be acceptable for you ?

> 	- ENXIO - when the device is not temporarily not responding
> 		  (e. g. reg 05 returning something not 0x10 or 0x00)
For those I would return just EIO.
I thought we agree here ?

> 	- EBUSY - when reg 05 returns 0x20 on em2874 and upper [1]
Yes, that's ok

> 	- EIO - for generic I/O errors that don't fit into the above.
I'm not sure what you mean with "generic", but yeah, that's ok, too.

> [1] According with a post that Devin made on IRC sometime ago, bit 5
> indicates that the I2C is busy when the master tries to use it, but it
> exists only on em2874 (and likely newer chips).
Can give me a pointer to this post ?

Regards,
Frank

> Cheers,
> Mauro


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

* Re: [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-07 17:28       ` Frank Schäfer
@ 2014-01-08 11:55         ` Mauro Carvalho Chehab
  2014-01-08 19:37           ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-08 11:55 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 07 Jan 2014 18:28:45 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 06.01.2014 10:55, schrieb Mauro Carvalho Chehab:
> > Em Sun, 05 Jan 2014 21:40:38 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> >>> The proper error code for I2C errors are EREMOTEIO. The em28xx driver
> >>> is using EIO instead.
> >>>
> >>> Replace all occurrences of EIO at em28xx-i2c, in order to fix it.
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>> ---
> >>>  drivers/media/usb/em28xx/em28xx-i2c.c | 20 ++++++++++----------
> >>>  1 file changed, 10 insertions(+), 10 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
> >>> index 9fa7ed51e5b1..8b35aa51b9bb 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-i2c.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-i2c.c
> >>> @@ -72,7 +72,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >>>  	if (ret != 2 + len) {
> >>>  		em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
> >>>  			    addr, ret);
> >>> -		return (ret < 0) ? ret : -EIO;
> >>> +		return (ret < 0) ? ret : -EREMOTEIO;
> >>>  	}
> >>>  	/* wait for completion */
> >>>  	while (time_is_after_jiffies(timeout)) {
> >>> @@ -91,7 +91,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >>>  		msleep(5);
> >>>  	}
> >>>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> >>> -	return -EIO;
> >>> +	return -EREMOTEIO;
> >>>  }
> >>>  
> >>>  /*
> >>> @@ -115,7 +115,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >>>  	if (ret != 2) {
> >>>  		em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
> >>>  			    addr, ret);
> >>> -		return (ret < 0) ? ret : -EIO;
> >>> +		return (ret < 0) ? ret : -EREMOTEIO;
> >>>  	}
> >>>  
> >>>  	/* wait for completion */
> >>> @@ -142,7 +142,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
> >>>  	if (ret != len) {
> >>>  		em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
> >>>  			    addr, ret);
> >>> -		return (ret < 0) ? ret : -EIO;
> >>> +		return (ret < 0) ? ret : -EREMOTEIO;
> >>>  	}
> >>>  	for (i = 0; i < len; i++)
> >>>  		buf[i] = buf2[len - 1 - i];
> >>> @@ -162,7 +162,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
> >>>  	ret = em2800_i2c_recv_bytes(dev, addr, &buf, 1);
> >>>  	if (ret == 1)
> >>>  		return 0;
> >>> -	return (ret < 0) ? ret : -EIO;
> >>> +	return (ret < 0) ? ret : -EREMOTEIO;
> >>>  }
> >>>  
> >>>  /*
> >>> @@ -191,7 +191,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >>>  		} else {
> >>>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
> >>>  				    len, addr, ret);
> >>> -			return -EIO;
> >>> +			return -EREMOTEIO;
> >>>  		}
> >>>  	}
> >>>  
> >>> @@ -219,7 +219,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >>>  	}
> >>>  
> >>>  	em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
> >>> -	return -EIO;
> >>> +	return -EREMOTEIO;
> >>>  }
> >>>  
> >>>  /*
> >>> @@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
> >>>  	}
> >>>  
> >>>  	em28xx_warn("unknown i2c error (status=%i)\n", ret);
> >>> -	return -EIO;
> >>> +	return -EREMOTEIO;
> >>>  }
> >>>  
> >>>  /*
> >>> @@ -283,7 +283,7 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
> >>>  	ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
> >>>  	if (ret == 1)
> >>>  		return 0;
> >>> -	return (ret < 0) ? ret : -EIO;
> >>> +	return (ret < 0) ? ret : -EREMOTEIO;
> >>>  }
> >>>  
> >>>  /*
> >>> @@ -312,7 +312,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
> >>>  		} else {
> >>>  			em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
> >>>  				    len, addr, ret);
> >>> -			return -EIO;
> >>> +			return -EREMOTEIO;
> >>>  		}
> >>>  	}
> >>>  	/* Check success */
> >> Why the hell -EREMOTEIO ???
> >> See Documentation/i2c/fault-codes.
> >> It's not even listed there !
> >> What are you trying to fix here ?
> > This is not a fixup patch.
> >
> > The idea of this path is to make em28xx more compliant with the Kernel
> > error codes. 
> >
> > As em28xx was the first USB media driver, it doesn't follow the best 
> > standards, despite all efforts we've made back in 2005, when the driver
> > was merged, in order to follow the Kernel rules. We eventually fixed
> > several things along the time, but we didn't took much care to fix the
> > I2C error codes so far.
> >
> > Now that we're taking care of it, we should do it right.
> >
> > However, you're actually right here.
> >
> > Before 2011, all I2C drivers under drivers/i2c used to return EREMOTEIO,
> > and the media drivers were moving to this error code since then.
> Ok, that explains it.
> 
> > But it seems that we missed a series of patches that moved I2C away from
> > EREMOTEIO:
> > 	http://www.spinics.net/lists/linux-i2c/msg06395.html
> > 	https://www.mail-archive.com/linux-i2c@vger.kernel.org/msg04819.html
> >
> > I'll rewrite this patch to return the right error codes, according with
> > Documentation/i2c/fault-codes.
> >
> > It seems that the proper return codes are:
> >
> > 	- ETIMEDOUT - when reg 05 returns 0x10
> I still don't agree here.
> AFAICS an I2C timeout can only happen if clock stretching is used.

It can also happen if the I2C gate is closed, for example, or when
a device is not powered.

This is likely the most common error when someone didn't properly
mapped the GPIOs for switching to analog mode or to digital mode.

> But we also get this when a slave device isn't present or doesn't
> answer, which means it doesn't ACK the data.
> So ETIMEDOUT is wrong.

It is still a timeout: the device didn't answer in time.

> Yes, 0x10 _could_ be a more general error. In that case EIO would be the
> better choice.
> But that's pure speculation as long as we don't have the datasheets.

The datasheet will not tell what are the corresponding Linux error codes.

ETIMEDOUT is better than the generic unspecific EIO.

> After reading the i2c fault codes descriptions again, I would agree to
> change it from ENODEV to ENXIO.
> ENXIO seems to be the intended error code for NACK errors and it's a bit
> more unspecific than ENODEV.
> 
> Would that be acceptable for you ?

Yes.

> > 	- ENXIO - when the device is not temporarily not responding
> > 		  (e. g. reg 05 returning something not 0x10 or 0x00)
> For those I would return just EIO.
> I thought we agree here ?

No. With em28xx/xc3028/tvp5150, we've got some temporary not responding
errors with return code 0x02 or 0x04, before fixing that xc3028 power down
bug.

What I suspect is that codes 0x02 and 0x04 are related to I2C stretching,
and that's why they need to be retried up to a software given timeout.

I prefer to use EIO only when we got an error while writing to reg 0x04
or when the read operation didn't return the number of requested bytes.

So, the better seems to return ETIMEDOUT for return codes different
than 0x00/0x10/0x20.

> 
> > 	- EBUSY - when reg 05 returns 0x20 on em2874 and upper [1]
> Yes, that's ok
> 
> > 	- EIO - for generic I/O errors that don't fit into the above.
> I'm not sure what you mean with "generic", but yeah, that's ok, too.
> 
> > [1] According with a post that Devin made on IRC sometime ago, bit 5
> > indicates that the I2C is busy when the master tries to use it, but it
> > exists only on em2874 (and likely newer chips).
> Can give me a pointer to this post ?

Unfortunately, the IRC logs weren't working on May, 27.

If you agree with this proposal, I'll rewrite 
https://patchwork.linuxtv.org/patch/21481/ accordingly.

Regards,
Mauro

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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-07 17:03       ` Frank Schäfer
@ 2014-01-08 14:10         ` Mauro Carvalho Chehab
  2014-01-08 19:14           ` Frank Schäfer
  0 siblings, 1 reply; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-08 14:10 UTC (permalink / raw)
  To: Frank Schäfer
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 07 Jan 2014 18:03:50 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 05.01.2014 22:25, schrieb Mauro Carvalho Chehab:
> > Em Sun, 05 Jan 2014 22:02:40 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> >>> From: Mauro Carvalho Chehab <mchehab@redhat.com>
> >> Is this line still correct ? ;)
> >>
> >>> Instead of allocating/deallocating URBs and transfer buffers
> >>> every time stream is started/stopped, just do it once.
> >>>
> >>> That reduces the memory allocation pressure and makes the
> >>> code that start/stop streaming a way simpler.
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >> Two Signed-off-by lines ? ;)
> >>
> >>> ---
> >>>  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
> >>>  1 file changed, 73 insertions(+), 55 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> index e5120430ec80..30ee389a07f0 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
> >>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
> >>> @@ -3,7 +3,7 @@
> >>>   *
> >>>   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
> >>>   *
> >>> - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
> >>> + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
> >>>   *	- Port to work with the in-kernel driver
> >>>   *	- Cleanups, fixes, alsa-controls, etc.
> >>>   *
> >>> @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
> >>>  			usb_kill_urb(urb);
> >>>  		else
> >>>  			usb_unlink_urb(urb);
> >>> -
> >>> -		usb_free_coherent(dev->udev,
> >>> -				  urb->transfer_buffer_length,
> >>> -				  dev->adev.transfer_buffer[i],
> >>> -				  urb->transfer_dma);
> >>> -
> >>> -		dev->adev.transfer_buffer[i] = NULL;
> >>> -
> >>> -		usb_free_urb(urb);
> >>> -		dev->adev.urb[i] = NULL;
> >>>  	}
> >>>  
> >>>  	return 0;
> >>> @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
> >>>  static int em28xx_init_audio_isoc(struct em28xx *dev)
> >>>  {
> >>>  	int       i, errCode;
> >>> -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> >>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >>>  
> >>>  	dprintk("Starting isoc transfers\n");
> >>>  
> >>> +	/* Start streaming */
> >>>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> >>> -		struct urb *urb;
> >>> -		int j, k;
> >>> -		void *buf;
> >>> -
> >>> -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> >>> -		if (!urb) {
> >>> -			em28xx_errdev("usb_alloc_urb failed!\n");
> >>> -			for (j = 0; j < i; j++) {
> >>> -				usb_free_urb(dev->adev.urb[j]);
> >>> -				kfree(dev->adev.transfer_buffer[j]);
> >>> -			}
> >>> -			return -ENOMEM;
> >>> -		}
> >>> -
> >>> -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> >>> -					 &urb->transfer_dma);
> >>> -		if (!buf)
> >>> -			return -ENOMEM;
> >>> -		dev->adev.transfer_buffer[i] = buf;
> >>> -		memset(buf, 0x80, sb_size);
> >>> -
> >>> -		urb->dev = dev->udev;
> >>> -		urb->context = dev;
> >>> -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> >>> -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> >>> -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> >>> -		urb->interval = 1;
> >>> -		urb->complete = em28xx_audio_isocirq;
> >>> -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> >>> -		urb->transfer_buffer_length = sb_size;
> >>> -
> >>> -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> >>> -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> >>> -			urb->iso_frame_desc[j].offset = k;
> >>> -			urb->iso_frame_desc[j].length =
> >>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >>> -		}
> >>> -		dev->adev.urb[i] = urb;
> >>> -	}
> >>> +		memset(dev->adev.transfer_buffer[i], 0x80,
> >>> +		       dev->adev.urb[i]->transfer_buffer_length);
> >>>  
> >>> -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> >>>  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
> >>>  		if (errCode) {
> >>>  			em28xx_errdev("submit of audio urb failed\n");
> >>> @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
> >>>  	.page      = snd_pcm_get_vmalloc_page,
> >>>  };
> >>>  
> >>> +static void em28xx_audio_free_urb(struct em28xx *dev)
> >>> +{
> >>> +	int i;
> >>> +
> >>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> >>> +		struct urb *urb = dev->adev.urb[i];
> >>> +
> >>> +		if (!dev->adev.urb[i])
> >>> +			continue;
> >>> +
> >>> +		usb_free_coherent(dev->udev,
> >>> +				  urb->transfer_buffer_length,
> >>> +				  dev->adev.transfer_buffer[i],
> >>> +				  urb->transfer_dma);
> >>> +
> >>> +		usb_free_urb(urb);
> >>> +		dev->adev.urb[i] = NULL;
> >>> +		dev->adev.transfer_buffer[i] = NULL;
> >>> +	}
> >>> +}
> >>> +
> >>>  static int em28xx_audio_init(struct em28xx *dev)
> >>>  {
> >>>  	struct em28xx_audio *adev = &dev->adev;
> >>>  	struct snd_pcm      *pcm;
> >>>  	struct snd_card     *card;
> >>>  	static int          devnr;
> >>> -	int                 err;
> >>> +	int                 err, i;
> >>> +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
> >>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >>>  
> >>>  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
> >>>  		/* This device does not support the extension (in this case
> >>> @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>  
> >>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
> >>>  			 "Rechberger\n");
> >>> -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
> >>> +	printk(KERN_INFO
> >>> +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
> >>>  
> >>>  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
> >>>  			      &card);
> >>> @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
> >>>  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
> >>>  	}
> >>>  
> >>> +	/* Alloc URB and transfer buffers */
> >>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
> >>> +		struct urb *urb;
> >>> +		int j, k;
> >>> +		void *buf;
> >>> +
> >>> +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
> >>> +		if (!urb) {
> >>> +			em28xx_errdev("usb_alloc_urb failed!\n");
> >>> +			em28xx_audio_free_urb(dev);
> >>> +			return -ENOMEM;
> >>> +		}
> >>> +		dev->adev.urb[i] = urb;
> >>> +
> >>> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
> >>> +					 &urb->transfer_dma);
> >>> +		if (!buf) {
> >>> +			em28xx_errdev("usb_alloc_coherent failed!\n");
> >>> +			em28xx_audio_free_urb(dev);
> >>> +			return -ENOMEM;
> >>> +		}
> >>> +		dev->adev.transfer_buffer[i] = buf;
> >>> +
> >>> +		urb->dev = dev->udev;
> >>> +		urb->context = dev;
> >>> +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
> >>> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> >>> +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
> >>> +		urb->interval = 1;
> >>> +		urb->complete = em28xx_audio_isocirq;
> >>> +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
> >>> +		urb->transfer_buffer_length = sb_size;
> >>> +
> >>> +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
> >>> +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
> >>> +			urb->iso_frame_desc[j].offset = k;
> >>> +			urb->iso_frame_desc[j].length =
> >>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
> >>> +		}
> >>> +	}
> >>> +
> >>>  	err = snd_card_register(card);
> >>>  	if (err < 0) {
> >>>  		snd_card_free(card);
> >>> @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
> >>>  		return 0;
> >>>  	}
> >>>  
> >>> +	em28xx_audio_free_urb(dev);
> >>> +
> >>>  	if (dev->adev.sndcard) {
> >>>  		snd_card_free(dev->adev.sndcard);
> >>>  		dev->adev.sndcard = NULL;
> >> I don't get it.
> >> How does this patch reduce the memory allocation pressure ?
> >> You are still allocating the same amount of memory.
> > True, but it is not de-allocating/reallocating the same amount of
> > memory every time, for every start/stop trigger. Depending on the
> > userspace and the amount of available RAM, this could cause memory 
> > fragmentation.
> >
> > If you take a look at xHCI logs, you'll see that those operations
> > are very expensive, and that it occurs too often.
> How often is the device started/stopped ?
> It's nothing that happens often/with a high freuqency, so is memeory
> fragmentation really a problem here ?

The trigger is called every time an underrun occurs. The thing is that
the memory allocation, plus the start URB logic takes too long.

With my test machine (an i7core with 4 cores, 8 threads, running at
2.4 GHz) and Kworld 305U (em2861), the time between receiving the trigger
and having the first audio buffer is long enough to produce another underrun.

At underrun, the driver will kill all existing URBs (with takes some time),
deallocate memory. Then a new trigger will reallocate memory and re-submit
URBs.

That actually means that underrun->trigger off/trigger on->underrun loop
happens several times per second, producing a crappy audio.

At least on this machine, removing memory allocation from the trigger loop
fixes the issue with Kworld 305U.

Btw, I noticed the same bug in the past on an older test hardware and
HVR-950.

PS.: on a slower machine, this may eventually not be enough, and we may
need to remove also the URB cancel/resubmit from the trigger loop.
I have some patches for this too, as such patch were needed to isolate
bugs when connected to a xHCI port (where URB kill doesn't seem to be
working properly), but I'll submit such patches only if I can make em28xx
work when connected to an xHCI 1.0 port, and while the USB core is not fixed.

> >
> >> The only differences is that you already do this when the device isn't
> >> used yet and don't free it when gets unused again.
> >> IMHO that makes things worse, not better.
> > Why is it worse?
> Because you increase the memory usage of closed devices.

So what? If someone plugged an em28xx device, it is because it is supposed
to be used. Besides that, the amount of allocated memory is not big.

> > FYI, we're currently allocating DVB buffers at the device init too,
> > due to the memory fragmentation problems. This is actually critical
> > if you try to use it on an ARM with limited amount of RAM.
> I was always wondering why.
> 
> Ok, if this really solves problems on ARM, do it.
> I assume it makes sense fix it for analog video, too. ;)

Yes, it makes sense for analog video too. There are some additional steps
to make em28xx v4l to work with ARM though. I'll eventually work on it if
I have some time during this month.

> >
> >> And yes, it makes the code that starts/stops streaming a way simpler.
> >> But at the same time it makes the module initialization code the same
> >> amount more complicated.
> >
> >
> 


-- 

Cheers,
Mauro

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

* Re: [PATCH v4 13/22] [media] em28xx: initialize audio latter
  2014-01-07 17:00       ` Frank Schäfer
@ 2014-01-08 14:29         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-08 14:29 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 07 Jan 2014 18:00:07 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 05.01.2014 14:17, schrieb Mauro Carvalho Chehab:
> > Em Sun, 05 Jan 2014 12:29:11 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> >>> Better to first write the GPIOs of the input mux, before initializing
> >>> the audio.
> >> Why are you making this change ?
> >>

...

> Let's not walk needlessly into the same trap with yet another piece of code.

Good point. I'll drop this one.

Regards,
Mauro

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

* Re: [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts
  2014-01-07 17:15       ` Frank Schäfer
@ 2014-01-08 14:39         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 80+ messages in thread
From: Mauro Carvalho Chehab @ 2014-01-08 14:39 UTC (permalink / raw)
  To: Frank Schäfer; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Em Tue, 07 Jan 2014 18:15:38 +0100
Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:

> Am 05.01.2014 21:57, schrieb Mauro Carvalho Chehab:
> > Em Sun, 05 Jan 2014 21:38:31 +0100
> > Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
> >
> >> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
> >>> In the lack of a better spec, let's assume the timeout
> >>> values compatible with SMBus spec:
> >>> 	http://smbus.org/specs/smbus110.pdf
> >>>
> >>> at chapter 8 - Electrical Characteristics of SMBus devices
> >>>
> >>> Ok, SMBus is a subset of I2C, and not all devices will be
> >>> following it, but the timeout value before this patch was not
> >>> even following the spec.
> >>>
> >>> So, while we don't have a better guess for it, use 35 + 1
> >>> ms as the timeout.
> >>>
> >>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
> >>> ---
> >>>  drivers/media/usb/em28xx/em28xx.h | 17 +++++++++++++++--
> >>>  1 file changed, 15 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
> >>> index db47c2236ca4..9af19332b0f1 100644
> >>> --- a/drivers/media/usb/em28xx/em28xx.h
> >>> +++ b/drivers/media/usb/em28xx/em28xx.h
> >>> @@ -183,8 +183,21 @@
> >>>  
> >>>  #define EM28XX_INTERLACED_DEFAULT 1
> >>>  
> >>> -/* time in msecs to wait for i2c xfers to finish */
> >>> -#define EM2800_I2C_XFER_TIMEOUT		20
> >>> +/*
> >>> + * 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 EM2800_I2C_XFER_TIMEOUT		36
> >>>  
> >>>  /* time in msecs to wait for AC97 xfers to finish */
> >>>  #define EM2800_AC97_XFER_TIMEOUT	100
> >> Mauro...
> >> What exactly are you fixing with this patch ?
> > It fixes some of the timeouts I noticed here with HVR-950.
> >
> >> Which devices are not working with the current timeout value ?
> >>
> >> You really shouldn't increase the timout to 172% for all devices based
> >> on such a fragile pure theory.
> > It is not fragile. It is the SMBUS spec. It should _at_least_ wait up to
> > the timeout specified there.
> >
> > Btw, it is not increasing the timeout. It is actually reducing it.
> >
> > See, this is the code before the patch:
> >
> > for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
> > 	     read_timeout -= 5) {
> > 		ret = dev->em28xx_read_reg(dev, 0x05);
> > 		if (ret == 0x84 + len - 1) {
> > 			break;
> > 		} else if (ret == 0x94 + len - 1) {
> > 			return -ENODEV;
> > 		} else if (ret < 0) {
> > 			em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
> > 				    ret);
> > 			return ret;
> > 		}
> > 		msleep(5);
> > 	}
> >
> > msleep(5) actually sleeps up to 20 ms, as the minimal time is the
> > schedule() time - being 10 ms a typical value (CONFIG_HZ equal to 100). 
> >
> > So, the current code has a timeout of up to 100 ms.
> 20ms / 5ms = 4.
> 4 * 10ms = 40ms ?

Yes. Actually the worse case is 20ms, as one could have manually 50 for
HZ, but, as distros either use 100 or 1000 for CONFIG_HZ, it seems safe
enough to assume that 10ms is the real worse case scenario for the
sleep time given by msleep(5).

> 
> > This patch is actually reducing from 100 ms to 36 ms.
> Ok, it's the same as with AC97 reads/writes.

Yes.

> I would accept any value from 20ms to 40ms.

36ms seems good enough, at least as an start point, as it is the maximum
time given by SMBUS spec.

It should be noticed that any I2C device that doesn't follow SMBUS
spec will likely have a much higher timeout, as said at
Documentation/i2c/fault-codes:

ETIMEDOUT
	This is returned by drivers when an operation took too much
	time, and was aborted before it completed.

	SMBus adapters may return it when an operation took more
	time than allowed by the SMBus specification; for example,
	when a slave stretches clocks too far.  I2C has no such
	timeouts, but it's normal for I2C adapters to impose some
	arbitrary limits (much longer than SMBus!) too.

That means that we might need to increase the timeout in order to
support I2C adapters that use stretching and are not SMBUS compliant.

Regards,
Mauro

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

* Re: [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init
  2014-01-08 14:10         ` Mauro Carvalho Chehab
@ 2014-01-08 19:14           ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-08 19:14 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Mauro Carvalho Chehab

Am 08.01.2014 15:10, schrieb Mauro Carvalho Chehab:
> Em Tue, 07 Jan 2014 18:03:50 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>
>> Am 05.01.2014 22:25, schrieb Mauro Carvalho Chehab:
>>> Em Sun, 05 Jan 2014 22:02:40 +0100
>>> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
>>>
>>>> Am 04.01.2014 11:55, schrieb Mauro Carvalho Chehab:
>>>>> From: Mauro Carvalho Chehab <mchehab@redhat.com>
>>>> Is this line still correct ? ;)
>>>>
>>>>> Instead of allocating/deallocating URBs and transfer buffers
>>>>> every time stream is started/stopped, just do it once.
>>>>>
>>>>> That reduces the memory allocation pressure and makes the
>>>>> code that start/stop streaming a way simpler.
>>>>>
>>>>> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
>>>>> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
>>>> Two Signed-off-by lines ? ;)
>>>>
>>>>> ---
>>>>>  drivers/media/usb/em28xx/em28xx-audio.c | 128 ++++++++++++++++++--------------
>>>>>  1 file changed, 73 insertions(+), 55 deletions(-)
>>>>>
>>>>> diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> index e5120430ec80..30ee389a07f0 100644
>>>>> --- a/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> +++ b/drivers/media/usb/em28xx/em28xx-audio.c
>>>>> @@ -3,7 +3,7 @@
>>>>>   *
>>>>>   *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
>>>>>   *
>>>>> - *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
>>>>> + *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
>>>>>   *	- Port to work with the in-kernel driver
>>>>>   *	- Cleanups, fixes, alsa-controls, etc.
>>>>>   *
>>>>> @@ -70,16 +70,6 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
>>>>>  			usb_kill_urb(urb);
>>>>>  		else
>>>>>  			usb_unlink_urb(urb);
>>>>> -
>>>>> -		usb_free_coherent(dev->udev,
>>>>> -				  urb->transfer_buffer_length,
>>>>> -				  dev->adev.transfer_buffer[i],
>>>>> -				  urb->transfer_dma);
>>>>> -
>>>>> -		dev->adev.transfer_buffer[i] = NULL;
>>>>> -
>>>>> -		usb_free_urb(urb);
>>>>> -		dev->adev.urb[i] = NULL;
>>>>>  	}
>>>>>  
>>>>>  	return 0;
>>>>> @@ -174,53 +164,14 @@ static void em28xx_audio_isocirq(struct urb *urb)
>>>>>  static int em28xx_init_audio_isoc(struct em28xx *dev)
>>>>>  {
>>>>>  	int       i, errCode;
>>>>> -	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>>>  
>>>>>  	dprintk("Starting isoc transfers\n");
>>>>>  
>>>>> +	/* Start streaming */
>>>>>  	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>>> -		struct urb *urb;
>>>>> -		int j, k;
>>>>> -		void *buf;
>>>>> -
>>>>> -		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>>>> -		if (!urb) {
>>>>> -			em28xx_errdev("usb_alloc_urb failed!\n");
>>>>> -			for (j = 0; j < i; j++) {
>>>>> -				usb_free_urb(dev->adev.urb[j]);
>>>>> -				kfree(dev->adev.transfer_buffer[j]);
>>>>> -			}
>>>>> -			return -ENOMEM;
>>>>> -		}
>>>>> -
>>>>> -		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>>>> -					 &urb->transfer_dma);
>>>>> -		if (!buf)
>>>>> -			return -ENOMEM;
>>>>> -		dev->adev.transfer_buffer[i] = buf;
>>>>> -		memset(buf, 0x80, sb_size);
>>>>> -
>>>>> -		urb->dev = dev->udev;
>>>>> -		urb->context = dev;
>>>>> -		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>>>> -		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>>>> -		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>>>> -		urb->interval = 1;
>>>>> -		urb->complete = em28xx_audio_isocirq;
>>>>> -		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>>>> -		urb->transfer_buffer_length = sb_size;
>>>>> -
>>>>> -		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>>>> -			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>>>> -			urb->iso_frame_desc[j].offset = k;
>>>>> -			urb->iso_frame_desc[j].length =
>>>>> -			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>>> -		}
>>>>> -		dev->adev.urb[i] = urb;
>>>>> -	}
>>>>> +		memset(dev->adev.transfer_buffer[i], 0x80,
>>>>> +		       dev->adev.urb[i]->transfer_buffer_length);
>>>>>  
>>>>> -	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>>>  		errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
>>>>>  		if (errCode) {
>>>>>  			em28xx_errdev("submit of audio urb failed\n");
>>>>> @@ -643,13 +594,36 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
>>>>>  	.page      = snd_pcm_get_vmalloc_page,
>>>>>  };
>>>>>  
>>>>> +static void em28xx_audio_free_urb(struct em28xx *dev)
>>>>> +{
>>>>> +	int i;
>>>>> +
>>>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>>> +		struct urb *urb = dev->adev.urb[i];
>>>>> +
>>>>> +		if (!dev->adev.urb[i])
>>>>> +			continue;
>>>>> +
>>>>> +		usb_free_coherent(dev->udev,
>>>>> +				  urb->transfer_buffer_length,
>>>>> +				  dev->adev.transfer_buffer[i],
>>>>> +				  urb->transfer_dma);
>>>>> +
>>>>> +		usb_free_urb(urb);
>>>>> +		dev->adev.urb[i] = NULL;
>>>>> +		dev->adev.transfer_buffer[i] = NULL;
>>>>> +	}
>>>>> +}
>>>>> +
>>>>>  static int em28xx_audio_init(struct em28xx *dev)
>>>>>  {
>>>>>  	struct em28xx_audio *adev = &dev->adev;
>>>>>  	struct snd_pcm      *pcm;
>>>>>  	struct snd_card     *card;
>>>>>  	static int          devnr;
>>>>> -	int                 err;
>>>>> +	int                 err, i;
>>>>> +	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
>>>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>>>  
>>>>>  	if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
>>>>>  		/* This device does not support the extension (in this case
>>>>> @@ -662,7 +636,8 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>>>  
>>>>>  	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
>>>>>  			 "Rechberger\n");
>>>>> -	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
>>>>> +	printk(KERN_INFO
>>>>> +	       "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
>>>>>  
>>>>>  	err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
>>>>>  			      &card);
>>>>> @@ -704,6 +679,47 @@ static int em28xx_audio_init(struct em28xx *dev)
>>>>>  		em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
>>>>>  	}
>>>>>  
>>>>> +	/* Alloc URB and transfer buffers */
>>>>> +	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
>>>>> +		struct urb *urb;
>>>>> +		int j, k;
>>>>> +		void *buf;
>>>>> +
>>>>> +		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
>>>>> +		if (!urb) {
>>>>> +			em28xx_errdev("usb_alloc_urb failed!\n");
>>>>> +			em28xx_audio_free_urb(dev);
>>>>> +			return -ENOMEM;
>>>>> +		}
>>>>> +		dev->adev.urb[i] = urb;
>>>>> +
>>>>> +		buf = usb_alloc_coherent(dev->udev, sb_size, GFP_ATOMIC,
>>>>> +					 &urb->transfer_dma);
>>>>> +		if (!buf) {
>>>>> +			em28xx_errdev("usb_alloc_coherent failed!\n");
>>>>> +			em28xx_audio_free_urb(dev);
>>>>> +			return -ENOMEM;
>>>>> +		}
>>>>> +		dev->adev.transfer_buffer[i] = buf;
>>>>> +
>>>>> +		urb->dev = dev->udev;
>>>>> +		urb->context = dev;
>>>>> +		urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
>>>>> +		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
>>>>> +		urb->transfer_buffer = dev->adev.transfer_buffer[i];
>>>>> +		urb->interval = 1;
>>>>> +		urb->complete = em28xx_audio_isocirq;
>>>>> +		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
>>>>> +		urb->transfer_buffer_length = sb_size;
>>>>> +
>>>>> +		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
>>>>> +			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
>>>>> +			urb->iso_frame_desc[j].offset = k;
>>>>> +			urb->iso_frame_desc[j].length =
>>>>> +			    EM28XX_AUDIO_MAX_PACKET_SIZE;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>>  	err = snd_card_register(card);
>>>>>  	if (err < 0) {
>>>>>  		snd_card_free(card);
>>>>> @@ -728,6 +744,8 @@ static int em28xx_audio_fini(struct em28xx *dev)
>>>>>  		return 0;
>>>>>  	}
>>>>>  
>>>>> +	em28xx_audio_free_urb(dev);
>>>>> +
>>>>>  	if (dev->adev.sndcard) {
>>>>>  		snd_card_free(dev->adev.sndcard);
>>>>>  		dev->adev.sndcard = NULL;
>>>> I don't get it.
>>>> How does this patch reduce the memory allocation pressure ?
>>>> You are still allocating the same amount of memory.
>>> True, but it is not de-allocating/reallocating the same amount of
>>> memory every time, for every start/stop trigger. Depending on the
>>> userspace and the amount of available RAM, this could cause memory 
>>> fragmentation.
>>>
>>> If you take a look at xHCI logs, you'll see that those operations
>>> are very expensive, and that it occurs too often.
>> How often is the device started/stopped ?
>> It's nothing that happens often/with a high freuqency, so is memeory
>> fragmentation really a problem here ?
> The trigger is called every time an underrun occurs. The thing is that
> the memory allocation, plus the start URB logic takes too long.
>
> With my test machine (an i7core with 4 cores, 8 threads, running at
> 2.4 GHz) and Kworld 305U (em2861), the time between receiving the trigger
> and having the first audio buffer is long enough to produce another underrun.
>
> At underrun, the driver will kill all existing URBs (with takes some time),
> deallocate memory. Then a new trigger will reallocate memory and re-submit
> URBs.
>
> That actually means that underrun->trigger off/trigger on->underrun loop
> happens several times per second, producing a crappy audio.
Ah, ok, I didn't expect it to happen that often.
No question then, the patch makes definitely sense.

Thanks for your explanations.

> At least on this machine, removing memory allocation from the trigger loop
> fixes the issue with Kworld 305U.
>
> Btw, I noticed the same bug in the past on an older test hardware and
> HVR-950.
>
> PS.: on a slower machine, this may eventually not be enough, and we may
> need to remove also the URB cancel/resubmit from the trigger loop.
> I have some patches for this too, as such patch were needed to isolate
> bugs when connected to a xHCI port (where URB kill doesn't seem to be
> working properly), but I'll submit such patches only if I can make em28xx
> work when connected to an xHCI 1.0 port, and while the USB core is not fixed.
I really need to buy a em28xx device with vendor audio interface.
My HVR930 has vendor audio, but - as you know - we don't support the
analog part of this device yet. :(


>
>>>> The only differences is that you already do this when the device isn't
>>>> used yet and don't free it when gets unused again.
>>>> IMHO that makes things worse, not better.
>>> Why is it worse?
>> Because you increase the memory usage of closed devices.
> So what? If someone plugged an em28xx device, it is because it is supposed
> to be used. Besides that, the amount of allocated memory is not big.
Sure, it's not a big problem.

>
>>> FYI, we're currently allocating DVB buffers at the device init too,
>>> due to the memory fragmentation problems. This is actually critical
>>> if you try to use it on an ARM with limited amount of RAM.
>> I was always wondering why.
>>
>> Ok, if this really solves problems on ARM, do it.
>> I assume it makes sense fix it for analog video, too. ;)
> Yes, it makes sense for analog video too. There are some additional steps
> to make em28xx v4l to work with ARM though. I'll eventually work on it if
> I have some time during this month.
Ok, great. :)

>
>>>> And yes, it makes the code that starts/stops streaming a way simpler.
>>>> But at the same time it makes the module initialization code the same
>>>> amount more complicated.


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

* Re: [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers
  2014-01-08 11:55         ` Mauro Carvalho Chehab
@ 2014-01-08 19:37           ` Frank Schäfer
  0 siblings, 0 replies; 80+ messages in thread
From: Frank Schäfer @ 2014-01-08 19:37 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Am 08.01.2014 12:55, schrieb Mauro Carvalho Chehab:
> Em Tue, 07 Jan 2014 18:28:45 +0100
> Frank Schäfer <fschaefer.oss@googlemail.com> escreveu:
...
>
>> But we also get this when a slave device isn't present or doesn't
>> answer, which means it doesn't ACK the data.
>> So ETIMEDOUT is wrong.
> It is still a timeout: the device didn't answer in time.
Ok, it's a 1 clock cycle timeout. :D :D :D

>
>> Yes, 0x10 _could_ be a more general error. In that case EIO would be the
>> better choice.
>> But that's pure speculation as long as we don't have the datasheets.
> The datasheet will not tell what are the corresponding Linux error codes.
Sure, we have to map the errors on our own.
But the datasheet should tell us for which error condition the bridge
returns which i2c state.

> ETIMEDOUT is better than the generic unspecific EIO.
The bridge should also be able to detect when something is fundamentally
wrong with SCL/SDA lines (bus not ready).
That's why I wouldn't return ETIMEDOUT for error codes we haven't seen
so far.
ETIMEDOUT for a clock stretching timeout (0x02 or 0x04) is of course right.

>
>> After reading the i2c fault codes descriptions again, I would agree to
>> change it from ENODEV to ENXIO.
>> ENXIO seems to be the intended error code for NACK errors and it's a bit
>> more unspecific than ENODEV.
>>
>> Would that be acceptable for you ?
> Yes.
Ok. fine, then let's use ENXIO for 0x10.

>
>>> 	- ENXIO - when the device is not temporarily not responding
>>> 		  (e. g. reg 05 returning something not 0x10 or 0x00)
>> For those I would return just EIO.
>> I thought we agree here ?
> No. With em28xx/xc3028/tvp5150, we've got some temporary not responding
> errors with return code 0x02 or 0x04, before fixing that xc3028 power down
> bug.
>
> What I suspect is that codes 0x02 and 0x04 are related to I2C stretching,
> and that's why they need to be retried up to a software given timeout.
Yeah, that's very likely.
ETIMEDOUT is ok for a clock stretching timeout, but I wonder why there
should be two of them. Can we narrow that down further ?
If you are looping over reg 0x05 only (not the whole procedure) after a
write for a very long time, which of these two states are temporary and
which never change ?
My theory would be, that one of them is temporary and means "busy,
client holds down SCL" and the other one is final and means "bridge gave
up waiting for the client to continue" (internal timeout).

> I prefer to use EIO only when we got an error while writing to reg 0x04
> or when the read operation didn't return the number of requested bytes.
The register read/write functions currently return the following error
codes:

device disconnected from USB port: -ENODEV
len > URB_MAX_CTRL_SIZE: -EINVAL (Btw, this one should probably should
be changed to a more appropriate error code)

or the error codes from the USB transfer, filtered/maopped with
usb_translate_errors():
-ENOMEM
-ENODEV
-EOPNOTSUPP
-EIO

I'm not sure if it is necessary to filter/map them further.
With the exeception of -EINVAL, they could probably be passed to to the
i2c client, too.
OTOH I doubt than any i2c client implements such a detailed error
handling. ;)
I have no objections against just returning EIO.

Regards,
Frank



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

end of thread, other threads:[~2014-01-08 19:36 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-04 10:55 [PATCH v4 00/22] em28xx: split analog part into a separate module Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 01/22] [media] em28xx: move some video-specific functions to em28xx-video Mauro Carvalho Chehab
2014-01-05 10:11   ` Frank Schäfer
2014-01-05 13:28     ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 02/22] [media] em28xx: some cosmetic changes Mauro Carvalho Chehab
2014-01-05 10:13   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 03/22] [media] em28xx: move analog-specific init to em28xx-video Mauro Carvalho Chehab
2014-01-05 10:26   ` Frank Schäfer
2014-01-05 14:40     ` Mauro Carvalho Chehab
2014-01-06 21:28       ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 04/22] [media] em28xx: make em28xx-video to be a separate module Mauro Carvalho Chehab
2014-01-05 10:47   ` Frank Schäfer
2014-01-05 12:56     ` Mauro Carvalho Chehab
2014-01-05 15:18       ` Mauro Carvalho Chehab
2014-01-06 21:35         ` Frank Schäfer
2014-01-06 17:38       ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 05/22] [media] em28xx: initialize analog I2C devices at the right place Mauro Carvalho Chehab
2014-01-05 10:48   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 06/22] [media] em28xx: add warn messages for timeout Mauro Carvalho Chehab
2014-01-05 10:51   ` Frank Schäfer
2014-01-05 13:05     ` Mauro Carvalho Chehab
2014-01-05 13:25     ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 07/22] [media] em28xx: improve extension information messages Mauro Carvalho Chehab
2014-01-05 10:55   ` Frank Schäfer
2014-01-05 13:08     ` Mauro Carvalho Chehab
2014-01-05 15:31       ` Mauro Carvalho Chehab
2014-01-06 17:44       ` Frank Schäfer
2014-01-06 18:17         ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 08/22] [media] em28xx: convert i2c wait completion logic to use jiffies Mauro Carvalho Chehab
2014-01-05 11:03   ` Frank Schäfer
2014-01-05 13:10     ` Mauro Carvalho Chehab
2014-01-06 17:48       ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 09/22] [media] tvp5150: make read operations atomic Mauro Carvalho Chehab
2014-01-05 11:07   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 10/22] [media] tuner-xc2028: remove unused code Mauro Carvalho Chehab
2014-01-05 11:07   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 11/22] [media] em28xx: check if a device has audio earlier Mauro Carvalho Chehab
2014-01-05 11:12   ` Frank Schäfer
2014-01-05 13:22     ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 12/22] [media] em28xx: properly implement AC97 wait code Mauro Carvalho Chehab
2014-01-05 11:19   ` Frank Schäfer
2014-01-05 13:20     ` Mauro Carvalho Chehab
2014-01-05 15:44       ` Mauro Carvalho Chehab
2014-01-07 16:50         ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 13/22] [media] em28xx: initialize audio latter Mauro Carvalho Chehab
2014-01-05 11:29   ` Frank Schäfer
2014-01-05 13:17     ` Mauro Carvalho Chehab
2014-01-07 17:00       ` Frank Schäfer
2014-01-08 14:29         ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 14/22] [media] em28xx: unify module version Mauro Carvalho Chehab
2014-01-05 11:33   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 15/22] [media] em28xx: Fix em28xx deplock Mauro Carvalho Chehab
2014-01-05 11:38   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 16/22] [media] em28xx: use a better value for I2C timeouts Mauro Carvalho Chehab
2014-01-05 20:38   ` Frank Schäfer
2014-01-05 20:57     ` Mauro Carvalho Chehab
2014-01-07 17:15       ` Frank Schäfer
2014-01-08 14:39         ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 17/22] [media] em28xx-i2c: Fix error code for I2C error transfers Mauro Carvalho Chehab
2014-01-05 20:40   ` Frank Schäfer
2014-01-06  9:55     ` Mauro Carvalho Chehab
2014-01-07 17:28       ` Frank Schäfer
2014-01-08 11:55         ` Mauro Carvalho Chehab
2014-01-08 19:37           ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 18/22] [media] em28xx: don't return -ENODEV for I2C xfer errors Mauro Carvalho Chehab
2014-01-05 20:49   ` Frank Schäfer
2014-01-06 10:37     ` Mauro Carvalho Chehab
2014-01-04 10:55 ` [PATCH v4 19/22] [media] em28xx: cleanup I2C debug messages Mauro Carvalho Chehab
2014-01-05 20:54   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 20/22] [media] em28xx: use usb_alloc_coherent() for audio Mauro Carvalho Chehab
2014-01-05 20:57   ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 21/22] [media] em28xx-audio: allocate URBs at device driver init Mauro Carvalho Chehab
2014-01-05 21:02   ` Frank Schäfer
2014-01-05 21:25     ` Mauro Carvalho Chehab
2014-01-06 16:25       ` Mauro Carvalho Chehab
2014-01-07 17:03       ` Frank Schäfer
2014-01-08 14:10         ` Mauro Carvalho Chehab
2014-01-08 19:14           ` Frank Schäfer
2014-01-04 10:55 ` [PATCH v4 22/22] [media] em28xx: retry read operation if it fails Mauro Carvalho Chehab
2014-01-05 21:06   ` Frank Schäfer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.