diff options
author | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-12-22 13:28:26 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-01-05 05:58:16 -0500 |
commit | 0560f337f3282dc6bf77b13ac344ffe30d9ccce5 (patch) | |
tree | 63f0105442382f0b3fc9d1c985432ee1960c74a0 /drivers/media/usb/em28xx/em28xx-video.c | |
parent | 547bf2508146f0274e4b72793c5017ca276282b6 (diff) |
[media] em28xx: move some video-specific functions to em28xx-video
Now that we want to split the video handling to a separate
module, move all video-specific functions to em28xx-video.
No functional changes.
Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-video.c | 374 |
1 files changed, 370 insertions, 4 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index dd19c9ff76e0..51d440588ed5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -53,15 +53,23 @@ | |||
53 | 53 | ||
54 | #define EM28XX_VERSION "0.2.0" | 54 | #define EM28XX_VERSION "0.2.0" |
55 | 55 | ||
56 | static unsigned int isoc_debug; | ||
57 | module_param(isoc_debug, int, 0644); | ||
58 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
59 | |||
60 | static unsigned int disable_vbi; | ||
61 | module_param(disable_vbi, int, 0644); | ||
62 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
63 | |||
64 | static int alt; | ||
65 | module_param(alt, int, 0644); | ||
66 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | ||
67 | |||
56 | #define em28xx_videodbg(fmt, arg...) do {\ | 68 | #define em28xx_videodbg(fmt, arg...) do {\ |
57 | if (video_debug) \ | 69 | if (video_debug) \ |
58 | printk(KERN_INFO "%s %s :"fmt, \ | 70 | printk(KERN_INFO "%s %s :"fmt, \ |
59 | dev->name, __func__ , ##arg); } while (0) | 71 | dev->name, __func__ , ##arg); } while (0) |
60 | 72 | ||
61 | static unsigned int isoc_debug; | ||
62 | module_param(isoc_debug, int, 0644); | ||
63 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
64 | |||
65 | #define em28xx_isocdbg(fmt, arg...) \ | 73 | #define em28xx_isocdbg(fmt, arg...) \ |
66 | do {\ | 74 | do {\ |
67 | if (isoc_debug) { \ | 75 | if (isoc_debug) { \ |
@@ -135,6 +143,257 @@ static struct em28xx_fmt format[] = { | |||
135 | }, | 143 | }, |
136 | }; | 144 | }; |
137 | 145 | ||
146 | int em28xx_vbi_supported(struct em28xx *dev) | ||
147 | { | ||
148 | /* Modprobe option to manually disable */ | ||
149 | if (disable_vbi == 1) | ||
150 | return 0; | ||
151 | |||
152 | if (dev->board.is_webcam) | ||
153 | return 0; | ||
154 | |||
155 | /* FIXME: check subdevices for VBI support */ | ||
156 | |||
157 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
158 | dev->chip_id == CHIP_ID_EM2883) | ||
159 | return 1; | ||
160 | |||
161 | /* Version of em28xx that does not support VBI */ | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * em28xx_wake_i2c() | ||
167 | * configure i2c attached devices | ||
168 | */ | ||
169 | void em28xx_wake_i2c(struct em28xx *dev) | ||
170 | { | ||
171 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); | ||
172 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, | ||
173 | INPUT(dev->ctl_input)->vmux, 0, 0); | ||
174 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); | ||
175 | } | ||
176 | |||
177 | int em28xx_colorlevels_set_default(struct em28xx *dev) | ||
178 | { | ||
179 | em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); | ||
180 | em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); | ||
181 | em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); | ||
182 | em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); | ||
183 | em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); | ||
184 | em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); | ||
185 | |||
186 | em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); | ||
187 | em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); | ||
188 | em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); | ||
189 | em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); | ||
190 | em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); | ||
191 | em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); | ||
192 | return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); | ||
193 | } | ||
194 | |||
195 | int em28xx_set_outfmt(struct em28xx *dev) | ||
196 | { | ||
197 | int ret; | ||
198 | u8 fmt, vinctrl; | ||
199 | |||
200 | fmt = dev->format->reg; | ||
201 | if (!dev->is_em25xx) | ||
202 | fmt |= 0x20; | ||
203 | /* | ||
204 | * NOTE: it's not clear if this is really needed ! | ||
205 | * The datasheets say bit 5 is a reserved bit and devices seem to work | ||
206 | * fine without it. But the Windows driver sets it for em2710/50+em28xx | ||
207 | * devices and we've always been setting it, too. | ||
208 | * | ||
209 | * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, | ||
210 | * it's likely used for an additional (compressed ?) format there. | ||
211 | */ | ||
212 | ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); | ||
213 | if (ret < 0) | ||
214 | return ret; | ||
215 | |||
216 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); | ||
217 | if (ret < 0) | ||
218 | return ret; | ||
219 | |||
220 | vinctrl = dev->vinctl; | ||
221 | if (em28xx_vbi_supported(dev) == 1) { | ||
222 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
223 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
224 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); | ||
225 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); | ||
226 | if (dev->norm & V4L2_STD_525_60) { | ||
227 | /* NTSC */ | ||
228 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
229 | } else if (dev->norm & V4L2_STD_625_50) { | ||
230 | /* PAL */ | ||
231 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
236 | } | ||
237 | |||
238 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | ||
239 | u8 ymin, u8 ymax) | ||
240 | { | ||
241 | em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n", | ||
242 | xmin, ymin, xmax, ymax); | ||
243 | |||
244 | em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); | ||
245 | em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); | ||
246 | em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); | ||
247 | return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); | ||
248 | } | ||
249 | |||
250 | static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, | ||
251 | u16 width, u16 height) | ||
252 | { | ||
253 | u8 cwidth = width >> 2; | ||
254 | u8 cheight = height >> 2; | ||
255 | u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); | ||
256 | /* NOTE: size limit: 2047x1023 = 2MPix */ | ||
257 | |||
258 | em28xx_videodbg("capture area set to (%d,%d): %dx%d\n", | ||
259 | hstart, vstart, | ||
260 | ((overflow & 2) << 9 | cwidth << 2), | ||
261 | ((overflow & 1) << 10 | cheight << 2)); | ||
262 | |||
263 | em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); | ||
264 | em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); | ||
265 | em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); | ||
266 | em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); | ||
267 | em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); | ||
268 | |||
269 | /* FIXME: function/meaning of these registers ? */ | ||
270 | /* FIXME: align width+height to multiples of 4 ?! */ | ||
271 | if (dev->is_em25xx) { | ||
272 | em28xx_write_reg(dev, 0x34, width >> 4); | ||
273 | em28xx_write_reg(dev, 0x35, height >> 4); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) | ||
278 | { | ||
279 | u8 mode; | ||
280 | /* the em2800 scaler only supports scaling down to 50% */ | ||
281 | |||
282 | if (dev->board.is_em2800) { | ||
283 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); | ||
284 | } else { | ||
285 | u8 buf[2]; | ||
286 | |||
287 | buf[0] = h; | ||
288 | buf[1] = h >> 8; | ||
289 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); | ||
290 | |||
291 | buf[0] = v; | ||
292 | buf[1] = v >> 8; | ||
293 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); | ||
294 | /* it seems that both H and V scalers must be active | ||
295 | to work correctly */ | ||
296 | mode = (h || v) ? 0x30 : 0x00; | ||
297 | } | ||
298 | return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); | ||
299 | } | ||
300 | |||
301 | /* FIXME: this only function read values from dev */ | ||
302 | int em28xx_resolution_set(struct em28xx *dev) | ||
303 | { | ||
304 | int width, height; | ||
305 | width = norm_maxw(dev); | ||
306 | height = norm_maxh(dev); | ||
307 | |||
308 | /* Properly setup VBI */ | ||
309 | dev->vbi_width = 720; | ||
310 | if (dev->norm & V4L2_STD_525_60) | ||
311 | dev->vbi_height = 12; | ||
312 | else | ||
313 | dev->vbi_height = 18; | ||
314 | |||
315 | em28xx_set_outfmt(dev); | ||
316 | |||
317 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | ||
318 | |||
319 | /* If we don't set the start position to 2 in VBI mode, we end up | ||
320 | with line 20/21 being YUYV encoded instead of being in 8-bit | ||
321 | greyscale. The core of the issue is that line 21 (and line 23 for | ||
322 | PAL WSS) are inside of active video region, and as a result they | ||
323 | get the pixelformatting associated with that area. So by cropping | ||
324 | it out, we end up with the same format as the rest of the VBI | ||
325 | region */ | ||
326 | if (em28xx_vbi_supported(dev) == 1) | ||
327 | em28xx_capture_area_set(dev, 0, 2, width, height); | ||
328 | else | ||
329 | em28xx_capture_area_set(dev, 0, 0, width, height); | ||
330 | |||
331 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | ||
332 | } | ||
333 | |||
334 | /* Set USB alternate setting for analog video */ | ||
335 | int em28xx_set_alternate(struct em28xx *dev) | ||
336 | { | ||
337 | int errCode; | ||
338 | int i; | ||
339 | unsigned int min_pkt_size = dev->width * 2 + 4; | ||
340 | |||
341 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed | ||
342 | bulk transfers seem to work only with alt=0 ! */ | ||
343 | dev->alt = 0; | ||
344 | if ((alt > 0) && (alt < dev->num_alt)) { | ||
345 | em28xx_videodbg("alternate forced to %d\n", dev->alt); | ||
346 | dev->alt = alt; | ||
347 | goto set_alt; | ||
348 | } | ||
349 | if (dev->analog_xfer_bulk) | ||
350 | goto set_alt; | ||
351 | |||
352 | /* When image size is bigger than a certain value, | ||
353 | the frame size should be increased, otherwise, only | ||
354 | green screen will be received. | ||
355 | */ | ||
356 | if (dev->width * 2 * dev->height > 720 * 240 * 2) | ||
357 | min_pkt_size *= 2; | ||
358 | |||
359 | for (i = 0; i < dev->num_alt; i++) { | ||
360 | /* stop when the selected alt setting offers enough bandwidth */ | ||
361 | if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { | ||
362 | dev->alt = i; | ||
363 | break; | ||
364 | /* otherwise make sure that we end up with the maximum bandwidth | ||
365 | because the min_pkt_size equation might be wrong... | ||
366 | */ | ||
367 | } else if (dev->alt_max_pkt_size_isoc[i] > | ||
368 | dev->alt_max_pkt_size_isoc[dev->alt]) | ||
369 | dev->alt = i; | ||
370 | } | ||
371 | |||
372 | set_alt: | ||
373 | /* NOTE: for bulk transfers, we need to call usb_set_interface() | ||
374 | * even if the previous settings were the same. Otherwise streaming | ||
375 | * fails with all urbs having status = -EOVERFLOW ! */ | ||
376 | if (dev->analog_xfer_bulk) { | ||
377 | dev->max_pkt_size = 512; /* USB 2.0 spec */ | ||
378 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; | ||
379 | } else { /* isoc */ | ||
380 | em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n", | ||
381 | min_pkt_size, dev->alt); | ||
382 | dev->max_pkt_size = | ||
383 | dev->alt_max_pkt_size_isoc[dev->alt]; | ||
384 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; | ||
385 | } | ||
386 | em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", | ||
387 | dev->alt, dev->max_pkt_size); | ||
388 | errCode = usb_set_interface(dev->udev, 0, dev->alt); | ||
389 | if (errCode < 0) { | ||
390 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", | ||
391 | dev->alt, errCode); | ||
392 | return errCode; | ||
393 | } | ||
394 | return 0; | ||
395 | } | ||
396 | |||
138 | /* ------------------------------------------------------------------ | 397 | /* ------------------------------------------------------------------ |
139 | DMA and thread functions | 398 | DMA and thread functions |
140 | ------------------------------------------------------------------*/ | 399 | ------------------------------------------------------------------*/ |
@@ -1817,6 +2076,113 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
1817 | return vfd; | 2076 | return vfd; |
1818 | } | 2077 | } |
1819 | 2078 | ||
2079 | static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) | ||
2080 | { | ||
2081 | memset(ctl, 0, sizeof(*ctl)); | ||
2082 | |||
2083 | ctl->fname = XC2028_DEFAULT_FIRMWARE; | ||
2084 | ctl->max_len = 64; | ||
2085 | ctl->mts = em28xx_boards[dev->model].mts_firmware; | ||
2086 | |||
2087 | switch (dev->model) { | ||
2088 | case EM2880_BOARD_EMPIRE_DUAL_TV: | ||
2089 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | ||
2090 | case EM2882_BOARD_TERRATEC_HYBRID_XS: | ||
2091 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2092 | break; | ||
2093 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | ||
2094 | case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: | ||
2095 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: | ||
2096 | ctl->demod = XC3028_FE_ZARLINK456; | ||
2097 | break; | ||
2098 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | ||
2099 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: | ||
2100 | ctl->demod = XC3028_FE_DEFAULT; | ||
2101 | break; | ||
2102 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | ||
2103 | ctl->demod = XC3028_FE_DEFAULT; | ||
2104 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2105 | break; | ||
2106 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: | ||
2107 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | ||
2108 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: | ||
2109 | /* FIXME: Better to specify the needed IF */ | ||
2110 | ctl->demod = XC3028_FE_DEFAULT; | ||
2111 | break; | ||
2112 | case EM2883_BOARD_KWORLD_HYBRID_330U: | ||
2113 | case EM2882_BOARD_DIKOM_DK300: | ||
2114 | case EM2882_BOARD_KWORLD_VS_DVBT: | ||
2115 | ctl->demod = XC3028_FE_CHINA; | ||
2116 | ctl->fname = XC2028_DEFAULT_FIRMWARE; | ||
2117 | break; | ||
2118 | case EM2882_BOARD_EVGA_INDTUBE: | ||
2119 | ctl->demod = XC3028_FE_CHINA; | ||
2120 | ctl->fname = XC3028L_DEFAULT_FIRMWARE; | ||
2121 | break; | ||
2122 | default: | ||
2123 | ctl->demod = XC3028_FE_OREN538; | ||
2124 | } | ||
2125 | } | ||
2126 | |||
2127 | void em28xx_tuner_setup(struct em28xx *dev) | ||
2128 | { | ||
2129 | struct tuner_setup tun_setup; | ||
2130 | struct v4l2_frequency f; | ||
2131 | |||
2132 | if (dev->tuner_type == TUNER_ABSENT) | ||
2133 | return; | ||
2134 | |||
2135 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
2136 | |||
2137 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
2138 | tun_setup.tuner_callback = em28xx_tuner_callback; | ||
2139 | |||
2140 | if (dev->board.radio.type) { | ||
2141 | tun_setup.type = dev->board.radio.type; | ||
2142 | tun_setup.addr = dev->board.radio_addr; | ||
2143 | |||
2144 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2145 | } | ||
2146 | |||
2147 | if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { | ||
2148 | tun_setup.type = dev->tuner_type; | ||
2149 | tun_setup.addr = dev->tuner_addr; | ||
2150 | |||
2151 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2152 | } | ||
2153 | |||
2154 | if (dev->tda9887_conf) { | ||
2155 | struct v4l2_priv_tun_config tda9887_cfg; | ||
2156 | |||
2157 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
2158 | tda9887_cfg.priv = &dev->tda9887_conf; | ||
2159 | |||
2160 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); | ||
2161 | } | ||
2162 | |||
2163 | if (dev->tuner_type == TUNER_XC2028) { | ||
2164 | struct v4l2_priv_tun_config xc2028_cfg; | ||
2165 | struct xc2028_ctrl ctl; | ||
2166 | |||
2167 | memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); | ||
2168 | memset(&ctl, 0, sizeof(ctl)); | ||
2169 | |||
2170 | em28xx_setup_xc3028(dev, &ctl); | ||
2171 | |||
2172 | xc2028_cfg.tuner = TUNER_XC2028; | ||
2173 | xc2028_cfg.priv = &ctl; | ||
2174 | |||
2175 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); | ||
2176 | } | ||
2177 | |||
2178 | /* configure tuner */ | ||
2179 | f.tuner = 0; | ||
2180 | f.type = V4L2_TUNER_ANALOG_TV; | ||
2181 | f.frequency = 9076; /* just a magic number */ | ||
2182 | dev->ctl_freq = f.frequency; | ||
2183 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); | ||
2184 | } | ||
2185 | |||
1820 | int em28xx_register_analog_devices(struct em28xx *dev) | 2186 | int em28xx_register_analog_devices(struct em28xx *dev) |
1821 | { | 2187 | { |
1822 | u8 val; | 2188 | u8 val; |