diff mbox

[v4,01/22,media] em28xx: move some video-specific functions to em28xx-video

Message ID 1388832951-11195-2-git-send-email-m.chehab@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mauro Carvalho Chehab Jan. 4, 2014, 10:55 a.m. UTC
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(-)

Comments

Frank Schäfer Jan. 5, 2014, 10:11 a.m. UTC | #1
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>

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mauro Carvalho Chehab Jan. 5, 2014, 1:28 p.m. UTC | #2
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().
diff mbox

Patch

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);