Em Sun, 05 Jan 2014 11:11:20 +0100 Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx> 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@xxxxxxxxxxx> > > --- > > 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@xxxxxxxxxxxxxx> > 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 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html