Message ID | 1388832951-11195-2-git-send-email-m.chehab@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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
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 --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);
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(-)