0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <media/tpg/v4l2-tpg.h>
0013
0014
0015 const char * const tpg_pattern_strings[] = {
0016 "75% Colorbar",
0017 "100% Colorbar",
0018 "CSC Colorbar",
0019 "Horizontal 100% Colorbar",
0020 "100% Color Squares",
0021 "100% Black",
0022 "100% White",
0023 "100% Red",
0024 "100% Green",
0025 "100% Blue",
0026 "16x16 Checkers",
0027 "2x2 Checkers",
0028 "1x1 Checkers",
0029 "2x2 Red/Green Checkers",
0030 "1x1 Red/Green Checkers",
0031 "Alternating Hor Lines",
0032 "Alternating Vert Lines",
0033 "One Pixel Wide Cross",
0034 "Two Pixels Wide Cross",
0035 "Ten Pixels Wide Cross",
0036 "Gray Ramp",
0037 "Noise",
0038 NULL
0039 };
0040 EXPORT_SYMBOL_GPL(tpg_pattern_strings);
0041
0042
0043 const char * const tpg_aspect_strings[] = {
0044 "Source Width x Height",
0045 "4x3",
0046 "14x9",
0047 "16x9",
0048 "16x9 Anamorphic",
0049 NULL
0050 };
0051 EXPORT_SYMBOL_GPL(tpg_aspect_strings);
0052
0053
0054
0055
0056
0057
0058 static const s8 sin[257] = {
0059 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
0060 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
0061 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
0062 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
0063 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
0064 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
0065 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
0066 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
0067 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
0068 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
0069 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
0070 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
0071 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
0072 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
0073 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
0074 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
0075 0,
0076 };
0077
0078 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
0079
0080
0081 static const u8 *font8x16;
0082
0083 void tpg_set_font(const u8 *f)
0084 {
0085 font8x16 = f;
0086 }
0087 EXPORT_SYMBOL_GPL(tpg_set_font);
0088
0089 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
0090 {
0091 memset(tpg, 0, sizeof(*tpg));
0092 tpg->scaled_width = tpg->src_width = w;
0093 tpg->src_height = tpg->buf_height = h;
0094 tpg->crop.width = tpg->compose.width = w;
0095 tpg->crop.height = tpg->compose.height = h;
0096 tpg->recalc_colors = true;
0097 tpg->recalc_square_border = true;
0098 tpg->brightness = 128;
0099 tpg->contrast = 128;
0100 tpg->saturation = 128;
0101 tpg->hue = 0;
0102 tpg->mv_hor_mode = TPG_MOVE_NONE;
0103 tpg->mv_vert_mode = TPG_MOVE_NONE;
0104 tpg->field = V4L2_FIELD_NONE;
0105 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
0106 tpg->colorspace = V4L2_COLORSPACE_SRGB;
0107 tpg->perc_fill = 100;
0108 tpg->hsv_enc = V4L2_HSV_ENC_180;
0109 }
0110 EXPORT_SYMBOL_GPL(tpg_init);
0111
0112 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
0113 {
0114 unsigned pat;
0115 unsigned plane;
0116
0117 tpg->max_line_width = max_w;
0118 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
0119 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
0120 unsigned pixelsz = plane ? 2 : 4;
0121
0122 tpg->lines[pat][plane] =
0123 vzalloc(array3_size(max_w, 2, pixelsz));
0124 if (!tpg->lines[pat][plane])
0125 return -ENOMEM;
0126 if (plane == 0)
0127 continue;
0128 tpg->downsampled_lines[pat][plane] =
0129 vzalloc(array3_size(max_w, 2, pixelsz));
0130 if (!tpg->downsampled_lines[pat][plane])
0131 return -ENOMEM;
0132 }
0133 }
0134 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
0135 unsigned pixelsz = plane ? 2 : 4;
0136
0137 tpg->contrast_line[plane] =
0138 vzalloc(array_size(pixelsz, max_w));
0139 if (!tpg->contrast_line[plane])
0140 return -ENOMEM;
0141 tpg->black_line[plane] =
0142 vzalloc(array_size(pixelsz, max_w));
0143 if (!tpg->black_line[plane])
0144 return -ENOMEM;
0145 tpg->random_line[plane] =
0146 vzalloc(array3_size(max_w, 2, pixelsz));
0147 if (!tpg->random_line[plane])
0148 return -ENOMEM;
0149 }
0150 return 0;
0151 }
0152 EXPORT_SYMBOL_GPL(tpg_alloc);
0153
0154 void tpg_free(struct tpg_data *tpg)
0155 {
0156 unsigned pat;
0157 unsigned plane;
0158
0159 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
0160 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
0161 vfree(tpg->lines[pat][plane]);
0162 tpg->lines[pat][plane] = NULL;
0163 if (plane == 0)
0164 continue;
0165 vfree(tpg->downsampled_lines[pat][plane]);
0166 tpg->downsampled_lines[pat][plane] = NULL;
0167 }
0168 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
0169 vfree(tpg->contrast_line[plane]);
0170 vfree(tpg->black_line[plane]);
0171 vfree(tpg->random_line[plane]);
0172 tpg->contrast_line[plane] = NULL;
0173 tpg->black_line[plane] = NULL;
0174 tpg->random_line[plane] = NULL;
0175 }
0176 }
0177 EXPORT_SYMBOL_GPL(tpg_free);
0178
0179 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
0180 {
0181 tpg->fourcc = fourcc;
0182 tpg->planes = 1;
0183 tpg->buffers = 1;
0184 tpg->recalc_colors = true;
0185 tpg->interleaved = false;
0186 tpg->vdownsampling[0] = 1;
0187 tpg->hdownsampling[0] = 1;
0188 tpg->hmask[0] = ~0;
0189 tpg->hmask[1] = ~0;
0190 tpg->hmask[2] = ~0;
0191
0192 switch (fourcc) {
0193 case V4L2_PIX_FMT_SBGGR8:
0194 case V4L2_PIX_FMT_SGBRG8:
0195 case V4L2_PIX_FMT_SGRBG8:
0196 case V4L2_PIX_FMT_SRGGB8:
0197 case V4L2_PIX_FMT_SBGGR10:
0198 case V4L2_PIX_FMT_SGBRG10:
0199 case V4L2_PIX_FMT_SGRBG10:
0200 case V4L2_PIX_FMT_SRGGB10:
0201 case V4L2_PIX_FMT_SBGGR12:
0202 case V4L2_PIX_FMT_SGBRG12:
0203 case V4L2_PIX_FMT_SGRBG12:
0204 case V4L2_PIX_FMT_SRGGB12:
0205 case V4L2_PIX_FMT_SBGGR16:
0206 case V4L2_PIX_FMT_SGBRG16:
0207 case V4L2_PIX_FMT_SGRBG16:
0208 case V4L2_PIX_FMT_SRGGB16:
0209 tpg->interleaved = true;
0210 tpg->vdownsampling[1] = 1;
0211 tpg->hdownsampling[1] = 1;
0212 tpg->planes = 2;
0213 fallthrough;
0214 case V4L2_PIX_FMT_RGB332:
0215 case V4L2_PIX_FMT_RGB565:
0216 case V4L2_PIX_FMT_RGB565X:
0217 case V4L2_PIX_FMT_RGB444:
0218 case V4L2_PIX_FMT_XRGB444:
0219 case V4L2_PIX_FMT_ARGB444:
0220 case V4L2_PIX_FMT_RGBX444:
0221 case V4L2_PIX_FMT_RGBA444:
0222 case V4L2_PIX_FMT_XBGR444:
0223 case V4L2_PIX_FMT_ABGR444:
0224 case V4L2_PIX_FMT_BGRX444:
0225 case V4L2_PIX_FMT_BGRA444:
0226 case V4L2_PIX_FMT_RGB555:
0227 case V4L2_PIX_FMT_XRGB555:
0228 case V4L2_PIX_FMT_ARGB555:
0229 case V4L2_PIX_FMT_RGBX555:
0230 case V4L2_PIX_FMT_RGBA555:
0231 case V4L2_PIX_FMT_XBGR555:
0232 case V4L2_PIX_FMT_ABGR555:
0233 case V4L2_PIX_FMT_BGRX555:
0234 case V4L2_PIX_FMT_BGRA555:
0235 case V4L2_PIX_FMT_RGB555X:
0236 case V4L2_PIX_FMT_XRGB555X:
0237 case V4L2_PIX_FMT_ARGB555X:
0238 case V4L2_PIX_FMT_BGR666:
0239 case V4L2_PIX_FMT_RGB24:
0240 case V4L2_PIX_FMT_BGR24:
0241 case V4L2_PIX_FMT_RGB32:
0242 case V4L2_PIX_FMT_BGR32:
0243 case V4L2_PIX_FMT_XRGB32:
0244 case V4L2_PIX_FMT_XBGR32:
0245 case V4L2_PIX_FMT_ARGB32:
0246 case V4L2_PIX_FMT_ABGR32:
0247 case V4L2_PIX_FMT_RGBX32:
0248 case V4L2_PIX_FMT_BGRX32:
0249 case V4L2_PIX_FMT_RGBA32:
0250 case V4L2_PIX_FMT_BGRA32:
0251 tpg->color_enc = TGP_COLOR_ENC_RGB;
0252 break;
0253 case V4L2_PIX_FMT_GREY:
0254 case V4L2_PIX_FMT_Y10:
0255 case V4L2_PIX_FMT_Y12:
0256 case V4L2_PIX_FMT_Y16:
0257 case V4L2_PIX_FMT_Y16_BE:
0258 case V4L2_PIX_FMT_Z16:
0259 tpg->color_enc = TGP_COLOR_ENC_LUMA;
0260 break;
0261 case V4L2_PIX_FMT_YUV444:
0262 case V4L2_PIX_FMT_YUV555:
0263 case V4L2_PIX_FMT_YUV565:
0264 case V4L2_PIX_FMT_YUV32:
0265 case V4L2_PIX_FMT_AYUV32:
0266 case V4L2_PIX_FMT_XYUV32:
0267 case V4L2_PIX_FMT_VUYA32:
0268 case V4L2_PIX_FMT_VUYX32:
0269 case V4L2_PIX_FMT_YUVA32:
0270 case V4L2_PIX_FMT_YUVX32:
0271 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0272 break;
0273 case V4L2_PIX_FMT_YUV420M:
0274 case V4L2_PIX_FMT_YVU420M:
0275 tpg->buffers = 3;
0276 fallthrough;
0277 case V4L2_PIX_FMT_YUV420:
0278 case V4L2_PIX_FMT_YVU420:
0279 tpg->vdownsampling[1] = 2;
0280 tpg->vdownsampling[2] = 2;
0281 tpg->hdownsampling[1] = 2;
0282 tpg->hdownsampling[2] = 2;
0283 tpg->planes = 3;
0284 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0285 break;
0286 case V4L2_PIX_FMT_YUV422M:
0287 case V4L2_PIX_FMT_YVU422M:
0288 tpg->buffers = 3;
0289 fallthrough;
0290 case V4L2_PIX_FMT_YUV422P:
0291 tpg->vdownsampling[1] = 1;
0292 tpg->vdownsampling[2] = 1;
0293 tpg->hdownsampling[1] = 2;
0294 tpg->hdownsampling[2] = 2;
0295 tpg->planes = 3;
0296 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0297 break;
0298 case V4L2_PIX_FMT_NV16M:
0299 case V4L2_PIX_FMT_NV61M:
0300 tpg->buffers = 2;
0301 fallthrough;
0302 case V4L2_PIX_FMT_NV16:
0303 case V4L2_PIX_FMT_NV61:
0304 tpg->vdownsampling[1] = 1;
0305 tpg->hdownsampling[1] = 1;
0306 tpg->hmask[1] = ~1;
0307 tpg->planes = 2;
0308 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0309 break;
0310 case V4L2_PIX_FMT_NV12M:
0311 case V4L2_PIX_FMT_NV21M:
0312 tpg->buffers = 2;
0313 fallthrough;
0314 case V4L2_PIX_FMT_NV12:
0315 case V4L2_PIX_FMT_NV21:
0316 tpg->vdownsampling[1] = 2;
0317 tpg->hdownsampling[1] = 1;
0318 tpg->hmask[1] = ~1;
0319 tpg->planes = 2;
0320 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0321 break;
0322 case V4L2_PIX_FMT_YUV444M:
0323 case V4L2_PIX_FMT_YVU444M:
0324 tpg->buffers = 3;
0325 tpg->planes = 3;
0326 tpg->vdownsampling[1] = 1;
0327 tpg->vdownsampling[2] = 1;
0328 tpg->hdownsampling[1] = 1;
0329 tpg->hdownsampling[2] = 1;
0330 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0331 break;
0332 case V4L2_PIX_FMT_NV24:
0333 case V4L2_PIX_FMT_NV42:
0334 tpg->vdownsampling[1] = 1;
0335 tpg->hdownsampling[1] = 1;
0336 tpg->planes = 2;
0337 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0338 break;
0339 case V4L2_PIX_FMT_YUYV:
0340 case V4L2_PIX_FMT_UYVY:
0341 case V4L2_PIX_FMT_YVYU:
0342 case V4L2_PIX_FMT_VYUY:
0343 tpg->hmask[0] = ~1;
0344 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
0345 break;
0346 case V4L2_PIX_FMT_HSV24:
0347 case V4L2_PIX_FMT_HSV32:
0348 tpg->color_enc = TGP_COLOR_ENC_HSV;
0349 break;
0350 default:
0351 return false;
0352 }
0353
0354 switch (fourcc) {
0355 case V4L2_PIX_FMT_GREY:
0356 case V4L2_PIX_FMT_RGB332:
0357 tpg->twopixelsize[0] = 2;
0358 break;
0359 case V4L2_PIX_FMT_RGB565:
0360 case V4L2_PIX_FMT_RGB565X:
0361 case V4L2_PIX_FMT_RGB444:
0362 case V4L2_PIX_FMT_XRGB444:
0363 case V4L2_PIX_FMT_ARGB444:
0364 case V4L2_PIX_FMT_RGBX444:
0365 case V4L2_PIX_FMT_RGBA444:
0366 case V4L2_PIX_FMT_XBGR444:
0367 case V4L2_PIX_FMT_ABGR444:
0368 case V4L2_PIX_FMT_BGRX444:
0369 case V4L2_PIX_FMT_BGRA444:
0370 case V4L2_PIX_FMT_RGB555:
0371 case V4L2_PIX_FMT_XRGB555:
0372 case V4L2_PIX_FMT_ARGB555:
0373 case V4L2_PIX_FMT_RGBX555:
0374 case V4L2_PIX_FMT_RGBA555:
0375 case V4L2_PIX_FMT_XBGR555:
0376 case V4L2_PIX_FMT_ABGR555:
0377 case V4L2_PIX_FMT_BGRX555:
0378 case V4L2_PIX_FMT_BGRA555:
0379 case V4L2_PIX_FMT_RGB555X:
0380 case V4L2_PIX_FMT_XRGB555X:
0381 case V4L2_PIX_FMT_ARGB555X:
0382 case V4L2_PIX_FMT_YUYV:
0383 case V4L2_PIX_FMT_UYVY:
0384 case V4L2_PIX_FMT_YVYU:
0385 case V4L2_PIX_FMT_VYUY:
0386 case V4L2_PIX_FMT_YUV444:
0387 case V4L2_PIX_FMT_YUV555:
0388 case V4L2_PIX_FMT_YUV565:
0389 case V4L2_PIX_FMT_Y10:
0390 case V4L2_PIX_FMT_Y12:
0391 case V4L2_PIX_FMT_Y16:
0392 case V4L2_PIX_FMT_Y16_BE:
0393 case V4L2_PIX_FMT_Z16:
0394 tpg->twopixelsize[0] = 2 * 2;
0395 break;
0396 case V4L2_PIX_FMT_RGB24:
0397 case V4L2_PIX_FMT_BGR24:
0398 case V4L2_PIX_FMT_HSV24:
0399 tpg->twopixelsize[0] = 2 * 3;
0400 break;
0401 case V4L2_PIX_FMT_BGR666:
0402 case V4L2_PIX_FMT_RGB32:
0403 case V4L2_PIX_FMT_BGR32:
0404 case V4L2_PIX_FMT_XRGB32:
0405 case V4L2_PIX_FMT_XBGR32:
0406 case V4L2_PIX_FMT_ARGB32:
0407 case V4L2_PIX_FMT_ABGR32:
0408 case V4L2_PIX_FMT_RGBX32:
0409 case V4L2_PIX_FMT_BGRX32:
0410 case V4L2_PIX_FMT_RGBA32:
0411 case V4L2_PIX_FMT_BGRA32:
0412 case V4L2_PIX_FMT_YUV32:
0413 case V4L2_PIX_FMT_AYUV32:
0414 case V4L2_PIX_FMT_XYUV32:
0415 case V4L2_PIX_FMT_VUYA32:
0416 case V4L2_PIX_FMT_VUYX32:
0417 case V4L2_PIX_FMT_YUVA32:
0418 case V4L2_PIX_FMT_YUVX32:
0419 case V4L2_PIX_FMT_HSV32:
0420 tpg->twopixelsize[0] = 2 * 4;
0421 break;
0422 case V4L2_PIX_FMT_NV12:
0423 case V4L2_PIX_FMT_NV21:
0424 case V4L2_PIX_FMT_NV12M:
0425 case V4L2_PIX_FMT_NV21M:
0426 case V4L2_PIX_FMT_NV16:
0427 case V4L2_PIX_FMT_NV61:
0428 case V4L2_PIX_FMT_NV16M:
0429 case V4L2_PIX_FMT_NV61M:
0430 case V4L2_PIX_FMT_SBGGR8:
0431 case V4L2_PIX_FMT_SGBRG8:
0432 case V4L2_PIX_FMT_SGRBG8:
0433 case V4L2_PIX_FMT_SRGGB8:
0434 tpg->twopixelsize[0] = 2;
0435 tpg->twopixelsize[1] = 2;
0436 break;
0437 case V4L2_PIX_FMT_SRGGB10:
0438 case V4L2_PIX_FMT_SGRBG10:
0439 case V4L2_PIX_FMT_SGBRG10:
0440 case V4L2_PIX_FMT_SBGGR10:
0441 case V4L2_PIX_FMT_SRGGB12:
0442 case V4L2_PIX_FMT_SGRBG12:
0443 case V4L2_PIX_FMT_SGBRG12:
0444 case V4L2_PIX_FMT_SBGGR12:
0445 case V4L2_PIX_FMT_SRGGB16:
0446 case V4L2_PIX_FMT_SGRBG16:
0447 case V4L2_PIX_FMT_SGBRG16:
0448 case V4L2_PIX_FMT_SBGGR16:
0449 tpg->twopixelsize[0] = 4;
0450 tpg->twopixelsize[1] = 4;
0451 break;
0452 case V4L2_PIX_FMT_YUV444M:
0453 case V4L2_PIX_FMT_YVU444M:
0454 case V4L2_PIX_FMT_YUV422M:
0455 case V4L2_PIX_FMT_YVU422M:
0456 case V4L2_PIX_FMT_YUV422P:
0457 case V4L2_PIX_FMT_YUV420:
0458 case V4L2_PIX_FMT_YVU420:
0459 case V4L2_PIX_FMT_YUV420M:
0460 case V4L2_PIX_FMT_YVU420M:
0461 tpg->twopixelsize[0] = 2;
0462 tpg->twopixelsize[1] = 2;
0463 tpg->twopixelsize[2] = 2;
0464 break;
0465 case V4L2_PIX_FMT_NV24:
0466 case V4L2_PIX_FMT_NV42:
0467 tpg->twopixelsize[0] = 2;
0468 tpg->twopixelsize[1] = 4;
0469 break;
0470 }
0471 return true;
0472 }
0473 EXPORT_SYMBOL_GPL(tpg_s_fourcc);
0474
0475 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
0476 const struct v4l2_rect *compose)
0477 {
0478 tpg->crop = *crop;
0479 tpg->compose = *compose;
0480 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
0481 tpg->crop.width - 1) / tpg->crop.width;
0482 tpg->scaled_width &= ~1;
0483 if (tpg->scaled_width > tpg->max_line_width)
0484 tpg->scaled_width = tpg->max_line_width;
0485 if (tpg->scaled_width < 2)
0486 tpg->scaled_width = 2;
0487 tpg->recalc_lines = true;
0488 }
0489 EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
0490
0491 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
0492 u32 field)
0493 {
0494 unsigned p;
0495
0496 tpg->src_width = width;
0497 tpg->src_height = height;
0498 tpg->field = field;
0499 tpg->buf_height = height;
0500 if (V4L2_FIELD_HAS_T_OR_B(field))
0501 tpg->buf_height /= 2;
0502 tpg->scaled_width = width;
0503 tpg->crop.top = tpg->crop.left = 0;
0504 tpg->crop.width = width;
0505 tpg->crop.height = height;
0506 tpg->compose.top = tpg->compose.left = 0;
0507 tpg->compose.width = width;
0508 tpg->compose.height = tpg->buf_height;
0509 for (p = 0; p < tpg->planes; p++)
0510 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
0511 (2 * tpg->hdownsampling[p]);
0512 tpg->recalc_square_border = true;
0513 }
0514 EXPORT_SYMBOL_GPL(tpg_reset_source);
0515
0516 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
0517 {
0518 switch (tpg->pattern) {
0519 case TPG_PAT_BLACK:
0520 return TPG_COLOR_100_WHITE;
0521 case TPG_PAT_CSC_COLORBAR:
0522 return TPG_COLOR_CSC_BLACK;
0523 default:
0524 return TPG_COLOR_100_BLACK;
0525 }
0526 }
0527
0528 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
0529 {
0530 switch (tpg->pattern) {
0531 case TPG_PAT_75_COLORBAR:
0532 case TPG_PAT_CSC_COLORBAR:
0533 return TPG_COLOR_CSC_WHITE;
0534 case TPG_PAT_BLACK:
0535 return TPG_COLOR_100_BLACK;
0536 default:
0537 return TPG_COLOR_100_WHITE;
0538 }
0539 }
0540
0541 static inline int rec709_to_linear(int v)
0542 {
0543 v = clamp(v, 0, 0xff0);
0544 return tpg_rec709_to_linear[v];
0545 }
0546
0547 static inline int linear_to_rec709(int v)
0548 {
0549 v = clamp(v, 0, 0xff0);
0550 return tpg_linear_to_rec709[v];
0551 }
0552
0553 static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,
0554 int *h, int *s, int *v)
0555 {
0556 int max_rgb, min_rgb, diff_rgb;
0557 int aux;
0558 int third;
0559 int third_size;
0560
0561 r >>= 4;
0562 g >>= 4;
0563 b >>= 4;
0564
0565
0566 max_rgb = max3(r, g, b);
0567 *v = max_rgb;
0568 if (!max_rgb) {
0569 *h = 0;
0570 *s = 0;
0571 return;
0572 }
0573
0574
0575 min_rgb = min3(r, g, b);
0576 diff_rgb = max_rgb - min_rgb;
0577 aux = 255 * diff_rgb;
0578 aux += max_rgb / 2;
0579 aux /= max_rgb;
0580 *s = aux;
0581 if (!aux) {
0582 *h = 0;
0583 return;
0584 }
0585
0586 third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;
0587
0588
0589 if (max_rgb == r) {
0590 aux = g - b;
0591 third = 0;
0592 } else if (max_rgb == g) {
0593 aux = b - r;
0594 third = third_size;
0595 } else {
0596 aux = r - g;
0597 third = third_size * 2;
0598 }
0599
0600 aux *= third_size / 2;
0601 aux += diff_rgb / 2;
0602 aux /= diff_rgb;
0603 aux += third;
0604
0605
0606 if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {
0607 if (aux < 0)
0608 aux += 180;
0609 else if (aux > 180)
0610 aux -= 180;
0611 } else {
0612 aux = aux & 0xff;
0613 }
0614
0615 *h = aux;
0616 }
0617
0618 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
0619 int y_offset, int *y, int *cb, int *cr)
0620 {
0621 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
0622 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
0623 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
0624 }
0625
0626 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
0627 int *y, int *cb, int *cr)
0628 {
0629 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
0630
0631 static const int bt601[3][3] = {
0632 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
0633 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
0634 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
0635 };
0636 static const int bt601_full[3][3] = {
0637 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
0638 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
0639 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
0640 };
0641 static const int rec709[3][3] = {
0642 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
0643 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
0644 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
0645 };
0646 static const int rec709_full[3][3] = {
0647 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
0648 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
0649 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
0650 };
0651 static const int smpte240m[3][3] = {
0652 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
0653 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
0654 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
0655 };
0656 static const int smpte240m_full[3][3] = {
0657 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
0658 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
0659 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
0660 };
0661 static const int bt2020[3][3] = {
0662 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
0663 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
0664 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
0665 };
0666 static const int bt2020_full[3][3] = {
0667 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
0668 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
0669 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },
0670 };
0671 static const int bt2020c[4] = {
0672 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
0673 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
0674 };
0675 static const int bt2020c_full[4] = {
0676 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
0677 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
0678 };
0679
0680 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
0681 unsigned y_offset = full ? 0 : 16;
0682 int lin_y, yc;
0683
0684 switch (tpg->real_ycbcr_enc) {
0685 case V4L2_YCBCR_ENC_601:
0686 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
0687 break;
0688 case V4L2_YCBCR_ENC_XV601:
0689
0690
0691 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
0692 break;
0693 case V4L2_YCBCR_ENC_XV709:
0694
0695
0696 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
0697 break;
0698 case V4L2_YCBCR_ENC_BT2020:
0699 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
0700 break;
0701 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
0702 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
0703 COEFF(0.6780, 255) * rec709_to_linear(g) +
0704 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
0705 yc = linear_to_rec709(lin_y);
0706 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
0707 if (b <= yc)
0708 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
0709 else
0710 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
0711 if (r <= yc)
0712 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
0713 else
0714 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
0715 break;
0716 case V4L2_YCBCR_ENC_SMPTE240M:
0717 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
0718 break;
0719 case V4L2_YCBCR_ENC_709:
0720 default:
0721 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
0722 break;
0723 }
0724 }
0725
0726 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
0727 int y_offset, int *r, int *g, int *b)
0728 {
0729 y -= y_offset << 4;
0730 cb -= 128 << 4;
0731 cr -= 128 << 4;
0732 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
0733 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
0734 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
0735 *r = clamp(*r >> 12, 0, 0xff0);
0736 *g = clamp(*g >> 12, 0, 0xff0);
0737 *b = clamp(*b >> 12, 0, 0xff0);
0738 }
0739
0740 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
0741 int *r, int *g, int *b)
0742 {
0743 #undef COEFF
0744 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
0745 static const int bt601[3][3] = {
0746 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
0747 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
0748 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
0749 };
0750 static const int bt601_full[3][3] = {
0751 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
0752 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
0753 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
0754 };
0755 static const int rec709[3][3] = {
0756 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
0757 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
0758 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
0759 };
0760 static const int rec709_full[3][3] = {
0761 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
0762 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
0763 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
0764 };
0765 static const int smpte240m[3][3] = {
0766 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
0767 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
0768 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
0769 };
0770 static const int smpte240m_full[3][3] = {
0771 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
0772 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
0773 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
0774 };
0775 static const int bt2020[3][3] = {
0776 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
0777 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
0778 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
0779 };
0780 static const int bt2020_full[3][3] = {
0781 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
0782 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
0783 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
0784 };
0785 static const int bt2020c[4] = {
0786 COEFF(1.9404, 224), COEFF(1.5816, 224),
0787 COEFF(1.7184, 224), COEFF(0.9936, 224),
0788 };
0789 static const int bt2020c_full[4] = {
0790 COEFF(1.9404, 255), COEFF(1.5816, 255),
0791 COEFF(1.7184, 255), COEFF(0.9936, 255),
0792 };
0793
0794 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
0795 unsigned y_offset = full ? 0 : 16;
0796 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
0797 int lin_r, lin_g, lin_b, lin_y;
0798
0799 switch (tpg->real_ycbcr_enc) {
0800 case V4L2_YCBCR_ENC_601:
0801 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
0802 break;
0803 case V4L2_YCBCR_ENC_XV601:
0804
0805
0806 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
0807 break;
0808 case V4L2_YCBCR_ENC_XV709:
0809
0810
0811 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
0812 break;
0813 case V4L2_YCBCR_ENC_BT2020:
0814 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
0815 break;
0816 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
0817 y -= full ? 0 : 16 << 4;
0818 cb -= 128 << 4;
0819 cr -= 128 << 4;
0820
0821 if (cb <= 0)
0822 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
0823 else
0824 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
0825 *b = *b >> 12;
0826 if (cr <= 0)
0827 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
0828 else
0829 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
0830 *r = *r >> 12;
0831 lin_r = rec709_to_linear(*r);
0832 lin_b = rec709_to_linear(*b);
0833 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
0834
0835 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
0836 COEFF(0.2627 / 0.6780, 255) * lin_r -
0837 COEFF(0.0593 / 0.6780, 255) * lin_b;
0838 *g = linear_to_rec709(lin_g >> 12);
0839 break;
0840 case V4L2_YCBCR_ENC_SMPTE240M:
0841 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
0842 break;
0843 case V4L2_YCBCR_ENC_709:
0844 default:
0845 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
0846 break;
0847 }
0848 }
0849
0850
0851 static void precalculate_color(struct tpg_data *tpg, int k)
0852 {
0853 int col = k;
0854 int r = tpg_colors[col].r;
0855 int g = tpg_colors[col].g;
0856 int b = tpg_colors[col].b;
0857 int y, cb, cr;
0858 bool ycbcr_valid = false;
0859
0860 if (k == TPG_COLOR_TEXTBG) {
0861 col = tpg_get_textbg_color(tpg);
0862
0863 r = tpg_colors[col].r;
0864 g = tpg_colors[col].g;
0865 b = tpg_colors[col].b;
0866 } else if (k == TPG_COLOR_TEXTFG) {
0867 col = tpg_get_textfg_color(tpg);
0868
0869 r = tpg_colors[col].r;
0870 g = tpg_colors[col].g;
0871 b = tpg_colors[col].b;
0872 } else if (tpg->pattern == TPG_PAT_NOISE) {
0873 r = g = b = prandom_u32_max(256);
0874 } else if (k == TPG_COLOR_RANDOM) {
0875 r = g = b = tpg->qual_offset + prandom_u32_max(196);
0876 } else if (k >= TPG_COLOR_RAMP) {
0877 r = g = b = k - TPG_COLOR_RAMP;
0878 }
0879
0880 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
0881 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
0882 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
0883 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
0884 } else {
0885 r <<= 4;
0886 g <<= 4;
0887 b <<= 4;
0888 }
0889
0890 if (tpg->qual == TPG_QUAL_GRAY ||
0891 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
0892
0893
0894 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
0895 }
0896
0897
0898
0899
0900
0901
0902
0903
0904 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
0905 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&
0906 tpg->color_enc == TGP_COLOR_ENC_RGB) {
0907
0908
0909
0910
0911
0912 r = (r * 219) / 255 + (16 << 4);
0913 g = (g * 219) / 255 + (16 << 4);
0914 b = (b * 219) / 255 + (16 << 4);
0915 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
0916 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
0917 tpg->color_enc == TGP_COLOR_ENC_RGB) {
0918
0919
0920
0921
0922
0923 r = clamp(r, 16 << 4, 235 << 4);
0924 g = clamp(g, 16 << 4, 235 << 4);
0925 b = clamp(b, 16 << 4, 235 << 4);
0926 r = (r - (16 << 4)) * 255 / 219;
0927 g = (g - (16 << 4)) * 255 / 219;
0928 b = (b - (16 << 4)) * 255 / 219;
0929 }
0930
0931 if ((tpg->brightness != 128 || tpg->contrast != 128 ||
0932 tpg->saturation != 128 || tpg->hue) &&
0933 tpg->color_enc != TGP_COLOR_ENC_LUMA) {
0934
0935 int tmp_cb, tmp_cr;
0936
0937
0938
0939 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
0940
0941 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
0942 y += (tpg->brightness << 4) - (128 << 4);
0943
0944 cb -= 128 << 4;
0945 cr -= 128 << 4;
0946 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
0947 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
0948
0949 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
0950 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
0951 if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
0952 ycbcr_valid = true;
0953 else
0954 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
0955 } else if ((tpg->brightness != 128 || tpg->contrast != 128) &&
0956 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
0957 r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;
0958 r += (tpg->brightness << 4) - (128 << 4);
0959 }
0960
0961 switch (tpg->color_enc) {
0962 case TGP_COLOR_ENC_HSV:
0963 {
0964 int h, s, v;
0965
0966 color_to_hsv(tpg, r, g, b, &h, &s, &v);
0967 tpg->colors[k][0] = h;
0968 tpg->colors[k][1] = s;
0969 tpg->colors[k][2] = v;
0970 break;
0971 }
0972 case TGP_COLOR_ENC_YCBCR:
0973 {
0974
0975 if (!ycbcr_valid)
0976 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
0977
0978 y >>= 4;
0979 cb >>= 4;
0980 cr >>= 4;
0981
0982
0983
0984
0985
0986 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&
0987 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
0988 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {
0989 y = clamp(y, 16, 235);
0990 cb = clamp(cb, 16, 240);
0991 cr = clamp(cr, 16, 240);
0992 } else {
0993 y = clamp(y, 1, 254);
0994 cb = clamp(cb, 1, 254);
0995 cr = clamp(cr, 1, 254);
0996 }
0997 switch (tpg->fourcc) {
0998 case V4L2_PIX_FMT_YUV444:
0999 y >>= 4;
1000 cb >>= 4;
1001 cr >>= 4;
1002 break;
1003 case V4L2_PIX_FMT_YUV555:
1004 y >>= 3;
1005 cb >>= 3;
1006 cr >>= 3;
1007 break;
1008 case V4L2_PIX_FMT_YUV565:
1009 y >>= 3;
1010 cb >>= 2;
1011 cr >>= 3;
1012 break;
1013 }
1014 tpg->colors[k][0] = y;
1015 tpg->colors[k][1] = cb;
1016 tpg->colors[k][2] = cr;
1017 break;
1018 }
1019 case TGP_COLOR_ENC_LUMA:
1020 {
1021 tpg->colors[k][0] = r >> 4;
1022 break;
1023 }
1024 case TGP_COLOR_ENC_RGB:
1025 {
1026 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
1027 r = (r * 219) / 255 + (16 << 4);
1028 g = (g * 219) / 255 + (16 << 4);
1029 b = (b * 219) / 255 + (16 << 4);
1030 }
1031 switch (tpg->fourcc) {
1032 case V4L2_PIX_FMT_RGB332:
1033 r >>= 9;
1034 g >>= 9;
1035 b >>= 10;
1036 break;
1037 case V4L2_PIX_FMT_RGB565:
1038 case V4L2_PIX_FMT_RGB565X:
1039 r >>= 7;
1040 g >>= 6;
1041 b >>= 7;
1042 break;
1043 case V4L2_PIX_FMT_RGB444:
1044 case V4L2_PIX_FMT_XRGB444:
1045 case V4L2_PIX_FMT_ARGB444:
1046 case V4L2_PIX_FMT_RGBX444:
1047 case V4L2_PIX_FMT_RGBA444:
1048 case V4L2_PIX_FMT_XBGR444:
1049 case V4L2_PIX_FMT_ABGR444:
1050 case V4L2_PIX_FMT_BGRX444:
1051 case V4L2_PIX_FMT_BGRA444:
1052 r >>= 8;
1053 g >>= 8;
1054 b >>= 8;
1055 break;
1056 case V4L2_PIX_FMT_RGB555:
1057 case V4L2_PIX_FMT_XRGB555:
1058 case V4L2_PIX_FMT_ARGB555:
1059 case V4L2_PIX_FMT_RGBX555:
1060 case V4L2_PIX_FMT_RGBA555:
1061 case V4L2_PIX_FMT_XBGR555:
1062 case V4L2_PIX_FMT_ABGR555:
1063 case V4L2_PIX_FMT_BGRX555:
1064 case V4L2_PIX_FMT_BGRA555:
1065 case V4L2_PIX_FMT_RGB555X:
1066 case V4L2_PIX_FMT_XRGB555X:
1067 case V4L2_PIX_FMT_ARGB555X:
1068 r >>= 7;
1069 g >>= 7;
1070 b >>= 7;
1071 break;
1072 case V4L2_PIX_FMT_BGR666:
1073 r >>= 6;
1074 g >>= 6;
1075 b >>= 6;
1076 break;
1077 default:
1078 r >>= 4;
1079 g >>= 4;
1080 b >>= 4;
1081 break;
1082 }
1083
1084 tpg->colors[k][0] = r;
1085 tpg->colors[k][1] = g;
1086 tpg->colors[k][2] = b;
1087 break;
1088 }
1089 }
1090 }
1091
1092 static void tpg_precalculate_colors(struct tpg_data *tpg)
1093 {
1094 int k;
1095
1096 for (k = 0; k < TPG_COLOR_MAX; k++)
1097 precalculate_color(tpg, k);
1098 }
1099
1100
1101 static void gen_twopix(struct tpg_data *tpg,
1102 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
1103 {
1104 unsigned offset = odd * tpg->twopixelsize[0] / 2;
1105 u8 alpha = tpg->alpha_component;
1106 u8 r_y_h, g_u_s, b_v;
1107
1108 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
1109 color != TPG_COLOR_100_RED &&
1110 color != TPG_COLOR_75_RED)
1111 alpha = 0;
1112 if (color == TPG_COLOR_RANDOM)
1113 precalculate_color(tpg, color);
1114 r_y_h = tpg->colors[color][0];
1115 g_u_s = tpg->colors[color][1];
1116 b_v = tpg->colors[color][2];
1117
1118 switch (tpg->fourcc) {
1119 case V4L2_PIX_FMT_GREY:
1120 buf[0][offset] = r_y_h;
1121 break;
1122 case V4L2_PIX_FMT_Y10:
1123 buf[0][offset] = (r_y_h << 2) & 0xff;
1124 buf[0][offset+1] = r_y_h >> 6;
1125 break;
1126 case V4L2_PIX_FMT_Y12:
1127 buf[0][offset] = (r_y_h << 4) & 0xff;
1128 buf[0][offset+1] = r_y_h >> 4;
1129 break;
1130 case V4L2_PIX_FMT_Y16:
1131 case V4L2_PIX_FMT_Z16:
1132
1133
1134
1135
1136
1137
1138 buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;
1139 buf[0][offset+1] = r_y_h;
1140 break;
1141 case V4L2_PIX_FMT_Y16_BE:
1142
1143 buf[0][offset] = r_y_h;
1144 buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;
1145 break;
1146 case V4L2_PIX_FMT_YUV422M:
1147 case V4L2_PIX_FMT_YUV422P:
1148 case V4L2_PIX_FMT_YUV420:
1149 case V4L2_PIX_FMT_YUV420M:
1150 buf[0][offset] = r_y_h;
1151 if (odd) {
1152 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1153 buf[2][0] = (buf[2][0] + b_v) / 2;
1154 buf[1][1] = buf[1][0];
1155 buf[2][1] = buf[2][0];
1156 break;
1157 }
1158 buf[1][0] = g_u_s;
1159 buf[2][0] = b_v;
1160 break;
1161 case V4L2_PIX_FMT_YVU422M:
1162 case V4L2_PIX_FMT_YVU420:
1163 case V4L2_PIX_FMT_YVU420M:
1164 buf[0][offset] = r_y_h;
1165 if (odd) {
1166 buf[1][0] = (buf[1][0] + b_v) / 2;
1167 buf[2][0] = (buf[2][0] + g_u_s) / 2;
1168 buf[1][1] = buf[1][0];
1169 buf[2][1] = buf[2][0];
1170 break;
1171 }
1172 buf[1][0] = b_v;
1173 buf[2][0] = g_u_s;
1174 break;
1175
1176 case V4L2_PIX_FMT_NV12:
1177 case V4L2_PIX_FMT_NV12M:
1178 case V4L2_PIX_FMT_NV16:
1179 case V4L2_PIX_FMT_NV16M:
1180 buf[0][offset] = r_y_h;
1181 if (odd) {
1182 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1183 buf[1][1] = (buf[1][1] + b_v) / 2;
1184 break;
1185 }
1186 buf[1][0] = g_u_s;
1187 buf[1][1] = b_v;
1188 break;
1189 case V4L2_PIX_FMT_NV21:
1190 case V4L2_PIX_FMT_NV21M:
1191 case V4L2_PIX_FMT_NV61:
1192 case V4L2_PIX_FMT_NV61M:
1193 buf[0][offset] = r_y_h;
1194 if (odd) {
1195 buf[1][0] = (buf[1][0] + b_v) / 2;
1196 buf[1][1] = (buf[1][1] + g_u_s) / 2;
1197 break;
1198 }
1199 buf[1][0] = b_v;
1200 buf[1][1] = g_u_s;
1201 break;
1202
1203 case V4L2_PIX_FMT_YUV444M:
1204 buf[0][offset] = r_y_h;
1205 buf[1][offset] = g_u_s;
1206 buf[2][offset] = b_v;
1207 break;
1208
1209 case V4L2_PIX_FMT_YVU444M:
1210 buf[0][offset] = r_y_h;
1211 buf[1][offset] = b_v;
1212 buf[2][offset] = g_u_s;
1213 break;
1214
1215 case V4L2_PIX_FMT_NV24:
1216 buf[0][offset] = r_y_h;
1217 buf[1][2 * offset] = g_u_s;
1218 buf[1][(2 * offset + 1) % 8] = b_v;
1219 break;
1220
1221 case V4L2_PIX_FMT_NV42:
1222 buf[0][offset] = r_y_h;
1223 buf[1][2 * offset] = b_v;
1224 buf[1][(2 * offset + 1) % 8] = g_u_s;
1225 break;
1226
1227 case V4L2_PIX_FMT_YUYV:
1228 buf[0][offset] = r_y_h;
1229 if (odd) {
1230 buf[0][1] = (buf[0][1] + g_u_s) / 2;
1231 buf[0][3] = (buf[0][3] + b_v) / 2;
1232 break;
1233 }
1234 buf[0][1] = g_u_s;
1235 buf[0][3] = b_v;
1236 break;
1237 case V4L2_PIX_FMT_UYVY:
1238 buf[0][offset + 1] = r_y_h;
1239 if (odd) {
1240 buf[0][0] = (buf[0][0] + g_u_s) / 2;
1241 buf[0][2] = (buf[0][2] + b_v) / 2;
1242 break;
1243 }
1244 buf[0][0] = g_u_s;
1245 buf[0][2] = b_v;
1246 break;
1247 case V4L2_PIX_FMT_YVYU:
1248 buf[0][offset] = r_y_h;
1249 if (odd) {
1250 buf[0][1] = (buf[0][1] + b_v) / 2;
1251 buf[0][3] = (buf[0][3] + g_u_s) / 2;
1252 break;
1253 }
1254 buf[0][1] = b_v;
1255 buf[0][3] = g_u_s;
1256 break;
1257 case V4L2_PIX_FMT_VYUY:
1258 buf[0][offset + 1] = r_y_h;
1259 if (odd) {
1260 buf[0][0] = (buf[0][0] + b_v) / 2;
1261 buf[0][2] = (buf[0][2] + g_u_s) / 2;
1262 break;
1263 }
1264 buf[0][0] = b_v;
1265 buf[0][2] = g_u_s;
1266 break;
1267 case V4L2_PIX_FMT_RGB332:
1268 buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;
1269 break;
1270 case V4L2_PIX_FMT_YUV565:
1271 case V4L2_PIX_FMT_RGB565:
1272 buf[0][offset] = (g_u_s << 5) | b_v;
1273 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);
1274 break;
1275 case V4L2_PIX_FMT_RGB565X:
1276 buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);
1277 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1278 break;
1279 case V4L2_PIX_FMT_RGB444:
1280 case V4L2_PIX_FMT_XRGB444:
1281 alpha = 0;
1282 fallthrough;
1283 case V4L2_PIX_FMT_YUV444:
1284 case V4L2_PIX_FMT_ARGB444:
1285 buf[0][offset] = (g_u_s << 4) | b_v;
1286 buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;
1287 break;
1288 case V4L2_PIX_FMT_RGBX444:
1289 alpha = 0;
1290 fallthrough;
1291 case V4L2_PIX_FMT_RGBA444:
1292 buf[0][offset] = (b_v << 4) | (alpha >> 4);
1293 buf[0][offset + 1] = (r_y_h << 4) | g_u_s;
1294 break;
1295 case V4L2_PIX_FMT_XBGR444:
1296 alpha = 0;
1297 fallthrough;
1298 case V4L2_PIX_FMT_ABGR444:
1299 buf[0][offset] = (g_u_s << 4) | r_y_h;
1300 buf[0][offset + 1] = (alpha & 0xf0) | b_v;
1301 break;
1302 case V4L2_PIX_FMT_BGRX444:
1303 alpha = 0;
1304 fallthrough;
1305 case V4L2_PIX_FMT_BGRA444:
1306 buf[0][offset] = (r_y_h << 4) | (alpha >> 4);
1307 buf[0][offset + 1] = (b_v << 4) | g_u_s;
1308 break;
1309 case V4L2_PIX_FMT_RGB555:
1310 case V4L2_PIX_FMT_XRGB555:
1311 alpha = 0;
1312 fallthrough;
1313 case V4L2_PIX_FMT_YUV555:
1314 case V4L2_PIX_FMT_ARGB555:
1315 buf[0][offset] = (g_u_s << 5) | b_v;
1316 buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)
1317 | (g_u_s >> 3);
1318 break;
1319 case V4L2_PIX_FMT_RGBX555:
1320 alpha = 0;
1321 fallthrough;
1322 case V4L2_PIX_FMT_RGBA555:
1323 buf[0][offset] = (g_u_s << 6) | (b_v << 1) |
1324 ((alpha & 0x80) >> 7);
1325 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2);
1326 break;
1327 case V4L2_PIX_FMT_XBGR555:
1328 alpha = 0;
1329 fallthrough;
1330 case V4L2_PIX_FMT_ABGR555:
1331 buf[0][offset] = (g_u_s << 5) | r_y_h;
1332 buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)
1333 | (g_u_s >> 3);
1334 break;
1335 case V4L2_PIX_FMT_BGRX555:
1336 alpha = 0;
1337 fallthrough;
1338 case V4L2_PIX_FMT_BGRA555:
1339 buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |
1340 ((alpha & 0x80) >> 7);
1341 buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2);
1342 break;
1343 case V4L2_PIX_FMT_RGB555X:
1344 case V4L2_PIX_FMT_XRGB555X:
1345 alpha = 0;
1346 fallthrough;
1347 case V4L2_PIX_FMT_ARGB555X:
1348 buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);
1349 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1350 break;
1351 case V4L2_PIX_FMT_RGB24:
1352 case V4L2_PIX_FMT_HSV24:
1353 buf[0][offset] = r_y_h;
1354 buf[0][offset + 1] = g_u_s;
1355 buf[0][offset + 2] = b_v;
1356 break;
1357 case V4L2_PIX_FMT_BGR24:
1358 buf[0][offset] = b_v;
1359 buf[0][offset + 1] = g_u_s;
1360 buf[0][offset + 2] = r_y_h;
1361 break;
1362 case V4L2_PIX_FMT_BGR666:
1363 buf[0][offset] = (b_v << 2) | (g_u_s >> 4);
1364 buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);
1365 buf[0][offset + 2] = r_y_h << 6;
1366 buf[0][offset + 3] = 0;
1367 break;
1368 case V4L2_PIX_FMT_RGB32:
1369 case V4L2_PIX_FMT_XRGB32:
1370 case V4L2_PIX_FMT_HSV32:
1371 case V4L2_PIX_FMT_XYUV32:
1372 alpha = 0;
1373 fallthrough;
1374 case V4L2_PIX_FMT_YUV32:
1375 case V4L2_PIX_FMT_ARGB32:
1376 case V4L2_PIX_FMT_AYUV32:
1377 buf[0][offset] = alpha;
1378 buf[0][offset + 1] = r_y_h;
1379 buf[0][offset + 2] = g_u_s;
1380 buf[0][offset + 3] = b_v;
1381 break;
1382 case V4L2_PIX_FMT_RGBX32:
1383 case V4L2_PIX_FMT_YUVX32:
1384 alpha = 0;
1385 fallthrough;
1386 case V4L2_PIX_FMT_RGBA32:
1387 case V4L2_PIX_FMT_YUVA32:
1388 buf[0][offset] = r_y_h;
1389 buf[0][offset + 1] = g_u_s;
1390 buf[0][offset + 2] = b_v;
1391 buf[0][offset + 3] = alpha;
1392 break;
1393 case V4L2_PIX_FMT_BGR32:
1394 case V4L2_PIX_FMT_XBGR32:
1395 case V4L2_PIX_FMT_VUYX32:
1396 alpha = 0;
1397 fallthrough;
1398 case V4L2_PIX_FMT_ABGR32:
1399 case V4L2_PIX_FMT_VUYA32:
1400 buf[0][offset] = b_v;
1401 buf[0][offset + 1] = g_u_s;
1402 buf[0][offset + 2] = r_y_h;
1403 buf[0][offset + 3] = alpha;
1404 break;
1405 case V4L2_PIX_FMT_BGRX32:
1406 alpha = 0;
1407 fallthrough;
1408 case V4L2_PIX_FMT_BGRA32:
1409 buf[0][offset] = alpha;
1410 buf[0][offset + 1] = b_v;
1411 buf[0][offset + 2] = g_u_s;
1412 buf[0][offset + 3] = r_y_h;
1413 break;
1414 case V4L2_PIX_FMT_SBGGR8:
1415 buf[0][offset] = odd ? g_u_s : b_v;
1416 buf[1][offset] = odd ? r_y_h : g_u_s;
1417 break;
1418 case V4L2_PIX_FMT_SGBRG8:
1419 buf[0][offset] = odd ? b_v : g_u_s;
1420 buf[1][offset] = odd ? g_u_s : r_y_h;
1421 break;
1422 case V4L2_PIX_FMT_SGRBG8:
1423 buf[0][offset] = odd ? r_y_h : g_u_s;
1424 buf[1][offset] = odd ? g_u_s : b_v;
1425 break;
1426 case V4L2_PIX_FMT_SRGGB8:
1427 buf[0][offset] = odd ? g_u_s : r_y_h;
1428 buf[1][offset] = odd ? b_v : g_u_s;
1429 break;
1430 case V4L2_PIX_FMT_SBGGR10:
1431 buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;
1432 buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1433 buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1434 buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1435 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1436 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1437 break;
1438 case V4L2_PIX_FMT_SGBRG10:
1439 buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;
1440 buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1441 buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1442 buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1443 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1444 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1445 break;
1446 case V4L2_PIX_FMT_SGRBG10:
1447 buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1448 buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1449 buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;
1450 buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1451 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1452 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1453 break;
1454 case V4L2_PIX_FMT_SRGGB10:
1455 buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1456 buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1457 buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;
1458 buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1459 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1460 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1461 break;
1462 case V4L2_PIX_FMT_SBGGR12:
1463 buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;
1464 buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1465 buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1466 buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1467 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1468 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1469 break;
1470 case V4L2_PIX_FMT_SGBRG12:
1471 buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;
1472 buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1473 buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1474 buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1475 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1476 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1477 break;
1478 case V4L2_PIX_FMT_SGRBG12:
1479 buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1480 buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1481 buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;
1482 buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1483 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1484 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1485 break;
1486 case V4L2_PIX_FMT_SRGGB12:
1487 buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1488 buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1489 buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;
1490 buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1491 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1492 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1493 break;
1494 case V4L2_PIX_FMT_SBGGR16:
1495 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;
1496 buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;
1497 break;
1498 case V4L2_PIX_FMT_SGBRG16:
1499 buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;
1500 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;
1501 break;
1502 case V4L2_PIX_FMT_SGRBG16:
1503 buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;
1504 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;
1505 break;
1506 case V4L2_PIX_FMT_SRGGB16:
1507 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;
1508 buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;
1509 break;
1510 }
1511 }
1512
1513 unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1514 {
1515 switch (tpg->fourcc) {
1516 case V4L2_PIX_FMT_SBGGR8:
1517 case V4L2_PIX_FMT_SGBRG8:
1518 case V4L2_PIX_FMT_SGRBG8:
1519 case V4L2_PIX_FMT_SRGGB8:
1520 case V4L2_PIX_FMT_SBGGR10:
1521 case V4L2_PIX_FMT_SGBRG10:
1522 case V4L2_PIX_FMT_SGRBG10:
1523 case V4L2_PIX_FMT_SRGGB10:
1524 case V4L2_PIX_FMT_SBGGR12:
1525 case V4L2_PIX_FMT_SGBRG12:
1526 case V4L2_PIX_FMT_SGRBG12:
1527 case V4L2_PIX_FMT_SRGGB12:
1528 case V4L2_PIX_FMT_SBGGR16:
1529 case V4L2_PIX_FMT_SGBRG16:
1530 case V4L2_PIX_FMT_SGRBG16:
1531 case V4L2_PIX_FMT_SRGGB16:
1532 return buf_line & 1;
1533 default:
1534 return 0;
1535 }
1536 }
1537 EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
1538
1539
1540 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
1541 {
1542 switch (tpg->pattern) {
1543 case TPG_PAT_CHECKERS_16X16:
1544 case TPG_PAT_CHECKERS_2X2:
1545 case TPG_PAT_CHECKERS_1X1:
1546 case TPG_PAT_COLOR_CHECKERS_2X2:
1547 case TPG_PAT_COLOR_CHECKERS_1X1:
1548 case TPG_PAT_ALTERNATING_HLINES:
1549 case TPG_PAT_CROSS_1_PIXEL:
1550 case TPG_PAT_CROSS_2_PIXELS:
1551 case TPG_PAT_CROSS_10_PIXELS:
1552 return 2;
1553 case TPG_PAT_100_COLORSQUARES:
1554 case TPG_PAT_100_HCOLORBAR:
1555 return 8;
1556 default:
1557 return 1;
1558 }
1559 }
1560
1561
1562 static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
1563 {
1564 switch (tpg->pattern) {
1565 case TPG_PAT_CHECKERS_16X16:
1566 return (line >> 4) & 1;
1567 case TPG_PAT_CHECKERS_1X1:
1568 case TPG_PAT_COLOR_CHECKERS_1X1:
1569 case TPG_PAT_ALTERNATING_HLINES:
1570 return line & 1;
1571 case TPG_PAT_CHECKERS_2X2:
1572 case TPG_PAT_COLOR_CHECKERS_2X2:
1573 return (line & 2) >> 1;
1574 case TPG_PAT_100_COLORSQUARES:
1575 case TPG_PAT_100_HCOLORBAR:
1576 return (line * 8) / tpg->src_height;
1577 case TPG_PAT_CROSS_1_PIXEL:
1578 return line == tpg->src_height / 2;
1579 case TPG_PAT_CROSS_2_PIXELS:
1580 return (line + 1) / 2 == tpg->src_height / 4;
1581 case TPG_PAT_CROSS_10_PIXELS:
1582 return (line + 10) / 20 == tpg->src_height / 40;
1583 default:
1584 return 0;
1585 }
1586 }
1587
1588
1589
1590
1591
1592 static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1593 unsigned pat_line, unsigned x)
1594 {
1595
1596
1597 static const enum tpg_color bars[3][8] = {
1598
1599 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1600 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1601 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1602 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1603
1604 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1605 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1606 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1607 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1608
1609 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1610 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1611 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1612 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1613 };
1614
1615 switch (tpg->pattern) {
1616 case TPG_PAT_75_COLORBAR:
1617 case TPG_PAT_100_COLORBAR:
1618 case TPG_PAT_CSC_COLORBAR:
1619 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1620 case TPG_PAT_100_COLORSQUARES:
1621 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1622 case TPG_PAT_100_HCOLORBAR:
1623 return bars[1][pat_line];
1624 case TPG_PAT_BLACK:
1625 return TPG_COLOR_100_BLACK;
1626 case TPG_PAT_WHITE:
1627 return TPG_COLOR_100_WHITE;
1628 case TPG_PAT_RED:
1629 return TPG_COLOR_100_RED;
1630 case TPG_PAT_GREEN:
1631 return TPG_COLOR_100_GREEN;
1632 case TPG_PAT_BLUE:
1633 return TPG_COLOR_100_BLUE;
1634 case TPG_PAT_CHECKERS_16X16:
1635 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1636 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1637 case TPG_PAT_CHECKERS_1X1:
1638 return ((x & 1) ^ (pat_line & 1)) ?
1639 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1640 case TPG_PAT_COLOR_CHECKERS_1X1:
1641 return ((x & 1) ^ (pat_line & 1)) ?
1642 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1643 case TPG_PAT_CHECKERS_2X2:
1644 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1645 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1646 case TPG_PAT_COLOR_CHECKERS_2X2:
1647 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1648 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1649 case TPG_PAT_ALTERNATING_HLINES:
1650 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1651 case TPG_PAT_ALTERNATING_VLINES:
1652 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1653 case TPG_PAT_CROSS_1_PIXEL:
1654 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1655 return TPG_COLOR_100_BLACK;
1656 return TPG_COLOR_100_WHITE;
1657 case TPG_PAT_CROSS_2_PIXELS:
1658 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1659 return TPG_COLOR_100_BLACK;
1660 return TPG_COLOR_100_WHITE;
1661 case TPG_PAT_CROSS_10_PIXELS:
1662 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1663 return TPG_COLOR_100_BLACK;
1664 return TPG_COLOR_100_WHITE;
1665 case TPG_PAT_GRAY_RAMP:
1666 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1667 default:
1668 return TPG_COLOR_100_RED;
1669 }
1670 }
1671
1672
1673
1674
1675
1676
1677
1678 static void tpg_calculate_square_border(struct tpg_data *tpg)
1679 {
1680 unsigned w = tpg->src_width;
1681 unsigned h = tpg->src_height;
1682 unsigned sq_w, sq_h;
1683
1684 sq_w = (w * 2 / 5) & ~1;
1685 if (((w - sq_w) / 2) & 1)
1686 sq_w += 2;
1687 sq_h = sq_w;
1688 tpg->square.width = sq_w;
1689 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1690 unsigned ana_sq_w = (sq_w / 4) * 3;
1691
1692 if (((w - ana_sq_w) / 2) & 1)
1693 ana_sq_w += 2;
1694 tpg->square.width = ana_sq_w;
1695 }
1696 tpg->square.left = (w - tpg->square.width) / 2;
1697 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1698 sq_h = sq_w * 10 / 11;
1699 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1700 sq_h = sq_w * 59 / 54;
1701 tpg->square.height = sq_h;
1702 tpg->square.top = (h - sq_h) / 2;
1703 tpg->border.left = 0;
1704 tpg->border.width = w;
1705 tpg->border.top = 0;
1706 tpg->border.height = h;
1707 switch (tpg->vid_aspect) {
1708 case TPG_VIDEO_ASPECT_4X3:
1709 if (tpg->pix_aspect)
1710 return;
1711 if (3 * w >= 4 * h) {
1712 tpg->border.width = ((4 * h) / 3) & ~1;
1713 if (((w - tpg->border.width) / 2) & ~1)
1714 tpg->border.width -= 2;
1715 tpg->border.left = (w - tpg->border.width) / 2;
1716 break;
1717 }
1718 tpg->border.height = ((3 * w) / 4) & ~1;
1719 tpg->border.top = (h - tpg->border.height) / 2;
1720 break;
1721 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1722 if (tpg->pix_aspect) {
1723 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1724 tpg->border.top = (h - tpg->border.height) / 2;
1725 break;
1726 }
1727 if (9 * w >= 14 * h) {
1728 tpg->border.width = ((14 * h) / 9) & ~1;
1729 if (((w - tpg->border.width) / 2) & ~1)
1730 tpg->border.width -= 2;
1731 tpg->border.left = (w - tpg->border.width) / 2;
1732 break;
1733 }
1734 tpg->border.height = ((9 * w) / 14) & ~1;
1735 tpg->border.top = (h - tpg->border.height) / 2;
1736 break;
1737 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1738 if (tpg->pix_aspect) {
1739 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1740 tpg->border.top = (h - tpg->border.height) / 2;
1741 break;
1742 }
1743 if (9 * w >= 16 * h) {
1744 tpg->border.width = ((16 * h) / 9) & ~1;
1745 if (((w - tpg->border.width) / 2) & ~1)
1746 tpg->border.width -= 2;
1747 tpg->border.left = (w - tpg->border.width) / 2;
1748 break;
1749 }
1750 tpg->border.height = ((9 * w) / 16) & ~1;
1751 tpg->border.top = (h - tpg->border.height) / 2;
1752 break;
1753 default:
1754 break;
1755 }
1756 }
1757
1758 static void tpg_precalculate_line(struct tpg_data *tpg)
1759 {
1760 enum tpg_color contrast;
1761 u8 pix[TPG_MAX_PLANES][8];
1762 unsigned pat;
1763 unsigned p;
1764 unsigned x;
1765
1766 switch (tpg->pattern) {
1767 case TPG_PAT_GREEN:
1768 contrast = TPG_COLOR_100_RED;
1769 break;
1770 case TPG_PAT_CSC_COLORBAR:
1771 contrast = TPG_COLOR_CSC_GREEN;
1772 break;
1773 default:
1774 contrast = TPG_COLOR_100_GREEN;
1775 break;
1776 }
1777
1778 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1779
1780 unsigned int_part = tpg->src_width / tpg->scaled_width;
1781 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1782 unsigned src_x = 0;
1783 unsigned error = 0;
1784
1785 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1786 unsigned real_x = src_x;
1787 enum tpg_color color1, color2;
1788
1789 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1790 color1 = tpg_get_color(tpg, pat, real_x);
1791
1792 src_x += int_part;
1793 error += fract_part;
1794 if (error >= tpg->scaled_width) {
1795 error -= tpg->scaled_width;
1796 src_x++;
1797 }
1798
1799 real_x = src_x;
1800 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1801 color2 = tpg_get_color(tpg, pat, real_x);
1802
1803 src_x += int_part;
1804 error += fract_part;
1805 if (error >= tpg->scaled_width) {
1806 error -= tpg->scaled_width;
1807 src_x++;
1808 }
1809
1810 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1811 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1812 for (p = 0; p < tpg->planes; p++) {
1813 unsigned twopixsize = tpg->twopixelsize[p];
1814 unsigned hdiv = tpg->hdownsampling[p];
1815 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
1816
1817 memcpy(pos, pix[p], twopixsize / hdiv);
1818 }
1819 }
1820 }
1821
1822 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1823 unsigned pat_lines = tpg_get_pat_lines(tpg);
1824
1825 for (pat = 0; pat < pat_lines; pat++) {
1826 unsigned next_pat = (pat + 1) % pat_lines;
1827
1828 for (p = 1; p < tpg->planes; p++) {
1829 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1830 u8 *pos1 = tpg->lines[pat][p];
1831 u8 *pos2 = tpg->lines[next_pat][p];
1832 u8 *dest = tpg->downsampled_lines[pat][p];
1833
1834 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1835 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1836 }
1837 }
1838 }
1839
1840 gen_twopix(tpg, pix, contrast, 0);
1841 gen_twopix(tpg, pix, contrast, 1);
1842 for (p = 0; p < tpg->planes; p++) {
1843 unsigned twopixsize = tpg->twopixelsize[p];
1844 u8 *pos = tpg->contrast_line[p];
1845
1846 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1847 memcpy(pos, pix[p], twopixsize);
1848 }
1849
1850 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1851 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1852 for (p = 0; p < tpg->planes; p++) {
1853 unsigned twopixsize = tpg->twopixelsize[p];
1854 u8 *pos = tpg->black_line[p];
1855
1856 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1857 memcpy(pos, pix[p], twopixsize);
1858 }
1859
1860 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1861 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1862 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1863 for (p = 0; p < tpg->planes; p++) {
1864 unsigned twopixsize = tpg->twopixelsize[p];
1865 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1866
1867 memcpy(pos, pix[p], twopixsize);
1868 }
1869 }
1870
1871 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1872 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1873 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1874 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1875 }
1876
1877
1878 typedef struct { u16 __; u8 _; } __packed x24;
1879
1880 #define PRINTSTR(PIXTYPE) do { \
1881 unsigned vdiv = tpg->vdownsampling[p]; \
1882 unsigned hdiv = tpg->hdownsampling[p]; \
1883 int line; \
1884 PIXTYPE fg; \
1885 PIXTYPE bg; \
1886 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1887 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1888 \
1889 for (line = first; line < 16; line += vdiv * step) { \
1890 int l = tpg->vflip ? 15 - line : line; \
1891 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1892 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1893 (x / hdiv) * sizeof(PIXTYPE)); \
1894 unsigned s; \
1895 \
1896 for (s = 0; s < len; s++) { \
1897 u8 chr = font8x16[(u8)text[s] * 16 + line]; \
1898 \
1899 if (hdiv == 2 && tpg->hflip) { \
1900 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1901 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1902 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1903 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1904 } else if (hdiv == 2) { \
1905 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1906 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1907 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1908 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1909 } else if (tpg->hflip) { \
1910 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1911 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1912 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1913 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1914 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1915 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1916 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1917 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1918 } else { \
1919 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1920 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1921 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1922 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1923 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1924 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1925 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1926 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1927 } \
1928 \
1929 pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \
1930 } \
1931 } \
1932 } while (0)
1933
1934 static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1935 unsigned p, unsigned first, unsigned div, unsigned step,
1936 int y, int x, const char *text, unsigned len)
1937 {
1938 PRINTSTR(u8);
1939 }
1940
1941 static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1942 unsigned p, unsigned first, unsigned div, unsigned step,
1943 int y, int x, const char *text, unsigned len)
1944 {
1945 PRINTSTR(u16);
1946 }
1947
1948 static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1949 unsigned p, unsigned first, unsigned div, unsigned step,
1950 int y, int x, const char *text, unsigned len)
1951 {
1952 PRINTSTR(x24);
1953 }
1954
1955 static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1956 unsigned p, unsigned first, unsigned div, unsigned step,
1957 int y, int x, const char *text, unsigned len)
1958 {
1959 PRINTSTR(u32);
1960 }
1961
1962 void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1963 int y, int x, const char *text)
1964 {
1965 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1966 unsigned div = step;
1967 unsigned first = 0;
1968 unsigned len;
1969 unsigned p;
1970
1971 if (font8x16 == NULL || basep == NULL || text == NULL)
1972 return;
1973
1974 len = strlen(text);
1975
1976
1977 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1978 return;
1979
1980 if (len > (tpg->compose.width - x) / 8)
1981 len = (tpg->compose.width - x) / 8;
1982 if (tpg->vflip)
1983 y = tpg->compose.height - y - 16;
1984 if (tpg->hflip)
1985 x = tpg->compose.width - x - 8;
1986 y += tpg->compose.top;
1987 x += tpg->compose.left;
1988 if (tpg->field == V4L2_FIELD_BOTTOM)
1989 first = 1;
1990 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1991 div = 2;
1992
1993 for (p = 0; p < tpg->planes; p++) {
1994
1995 switch (tpg->twopixelsize[p]) {
1996 case 2:
1997 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
1998 text, len);
1999 break;
2000 case 4:
2001 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
2002 text, len);
2003 break;
2004 case 6:
2005 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
2006 text, len);
2007 break;
2008 case 8:
2009 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
2010 text, len);
2011 break;
2012 }
2013 }
2014 }
2015 EXPORT_SYMBOL_GPL(tpg_gen_text);
2016
2017 const char *tpg_g_color_order(const struct tpg_data *tpg)
2018 {
2019 switch (tpg->pattern) {
2020 case TPG_PAT_75_COLORBAR:
2021 case TPG_PAT_100_COLORBAR:
2022 case TPG_PAT_CSC_COLORBAR:
2023 case TPG_PAT_100_HCOLORBAR:
2024 return "White, yellow, cyan, green, magenta, red, blue, black";
2025 case TPG_PAT_BLACK:
2026 return "Black";
2027 case TPG_PAT_WHITE:
2028 return "White";
2029 case TPG_PAT_RED:
2030 return "Red";
2031 case TPG_PAT_GREEN:
2032 return "Green";
2033 case TPG_PAT_BLUE:
2034 return "Blue";
2035 default:
2036 return NULL;
2037 }
2038 }
2039 EXPORT_SYMBOL_GPL(tpg_g_color_order);
2040
2041 void tpg_update_mv_step(struct tpg_data *tpg)
2042 {
2043 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
2044
2045 if (tpg->hflip)
2046 factor = -factor;
2047 switch (tpg->mv_hor_mode) {
2048 case TPG_MOVE_NEG_FAST:
2049 case TPG_MOVE_POS_FAST:
2050 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
2051 break;
2052 case TPG_MOVE_NEG:
2053 case TPG_MOVE_POS:
2054 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
2055 break;
2056 case TPG_MOVE_NEG_SLOW:
2057 case TPG_MOVE_POS_SLOW:
2058 tpg->mv_hor_step = 2;
2059 break;
2060 case TPG_MOVE_NONE:
2061 tpg->mv_hor_step = 0;
2062 break;
2063 }
2064 if (factor < 0)
2065 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
2066
2067 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
2068 switch (tpg->mv_vert_mode) {
2069 case TPG_MOVE_NEG_FAST:
2070 case TPG_MOVE_POS_FAST:
2071 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
2072 break;
2073 case TPG_MOVE_NEG:
2074 case TPG_MOVE_POS:
2075 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
2076 break;
2077 case TPG_MOVE_NEG_SLOW:
2078 case TPG_MOVE_POS_SLOW:
2079 tpg->mv_vert_step = 1;
2080 break;
2081 case TPG_MOVE_NONE:
2082 tpg->mv_vert_step = 0;
2083 break;
2084 }
2085 if (factor < 0)
2086 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
2087 }
2088 EXPORT_SYMBOL_GPL(tpg_update_mv_step);
2089
2090
2091 static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
2092 unsigned field)
2093 {
2094 switch (field) {
2095 case V4L2_FIELD_TOP:
2096 return tpg->crop.top + src_y * 2;
2097 case V4L2_FIELD_BOTTOM:
2098 return tpg->crop.top + src_y * 2 + 1;
2099 default:
2100 return src_y + tpg->crop.top;
2101 }
2102 }
2103
2104
2105
2106
2107
2108 static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
2109 unsigned field)
2110 {
2111 y += tpg->compose.top;
2112 switch (field) {
2113 case V4L2_FIELD_SEQ_TB:
2114 if (y & 1)
2115 return tpg->buf_height / 2 + y / 2;
2116 return y / 2;
2117 case V4L2_FIELD_SEQ_BT:
2118 if (y & 1)
2119 return y / 2;
2120 return tpg->buf_height / 2 + y / 2;
2121 default:
2122 return y;
2123 }
2124 }
2125
2126 static void tpg_recalc(struct tpg_data *tpg)
2127 {
2128 if (tpg->recalc_colors) {
2129 tpg->recalc_colors = false;
2130 tpg->recalc_lines = true;
2131 tpg->real_xfer_func = tpg->xfer_func;
2132 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
2133 tpg->real_hsv_enc = tpg->hsv_enc;
2134 tpg->real_quantization = tpg->quantization;
2135
2136 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
2137 tpg->real_xfer_func =
2138 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
2139
2140 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
2141 tpg->real_ycbcr_enc =
2142 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
2143
2144 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
2145 tpg->real_quantization =
2146 V4L2_MAP_QUANTIZATION_DEFAULT(
2147 tpg->color_enc != TGP_COLOR_ENC_YCBCR,
2148 tpg->colorspace, tpg->real_ycbcr_enc);
2149
2150 tpg_precalculate_colors(tpg);
2151 }
2152 if (tpg->recalc_square_border) {
2153 tpg->recalc_square_border = false;
2154 tpg_calculate_square_border(tpg);
2155 }
2156 if (tpg->recalc_lines) {
2157 tpg->recalc_lines = false;
2158 tpg_precalculate_line(tpg);
2159 }
2160 }
2161
2162 void tpg_calc_text_basep(struct tpg_data *tpg,
2163 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
2164 {
2165 unsigned stride = tpg->bytesperline[p];
2166 unsigned h = tpg->buf_height;
2167
2168 tpg_recalc(tpg);
2169
2170 basep[p][0] = vbuf;
2171 basep[p][1] = vbuf;
2172 h /= tpg->vdownsampling[p];
2173 if (tpg->field == V4L2_FIELD_SEQ_TB)
2174 basep[p][1] += h * stride / 2;
2175 else if (tpg->field == V4L2_FIELD_SEQ_BT)
2176 basep[p][0] += h * stride / 2;
2177 if (p == 0 && tpg->interleaved)
2178 tpg_calc_text_basep(tpg, basep, 1, vbuf);
2179 }
2180 EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
2181
2182 static int tpg_pattern_avg(const struct tpg_data *tpg,
2183 unsigned pat1, unsigned pat2)
2184 {
2185 unsigned pat_lines = tpg_get_pat_lines(tpg);
2186
2187 if (pat1 == (pat2 + 1) % pat_lines)
2188 return pat2;
2189 if (pat2 == (pat1 + 1) % pat_lines)
2190 return pat1;
2191 return -1;
2192 }
2193
2194 static const char *tpg_color_enc_str(enum tgp_color_enc
2195 color_enc)
2196 {
2197 switch (color_enc) {
2198 case TGP_COLOR_ENC_HSV:
2199 return "HSV";
2200 case TGP_COLOR_ENC_YCBCR:
2201 return "Y'CbCr";
2202 case TGP_COLOR_ENC_LUMA:
2203 return "Luma";
2204 case TGP_COLOR_ENC_RGB:
2205 default:
2206 return "R'G'B";
2207
2208 }
2209 }
2210
2211 void tpg_log_status(struct tpg_data *tpg)
2212 {
2213 pr_info("tpg source WxH: %ux%u (%s)\n",
2214 tpg->src_width, tpg->src_height,
2215 tpg_color_enc_str(tpg->color_enc));
2216 pr_info("tpg field: %u\n", tpg->field);
2217 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
2218 tpg->crop.left, tpg->crop.top);
2219 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
2220 tpg->compose.left, tpg->compose.top);
2221 pr_info("tpg colorspace: %d\n", tpg->colorspace);
2222 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
2223 if (tpg->color_enc == TGP_COLOR_ENC_HSV)
2224 pr_info("tpg HSV encoding: %d/%d\n",
2225 tpg->hsv_enc, tpg->real_hsv_enc);
2226 else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
2227 pr_info("tpg Y'CbCr encoding: %d/%d\n",
2228 tpg->ycbcr_enc, tpg->real_ycbcr_enc);
2229 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
2230 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
2231 }
2232 EXPORT_SYMBOL_GPL(tpg_log_status);
2233
2234
2235
2236
2237
2238 struct tpg_draw_params {
2239
2240 bool is_tv;
2241 bool is_60hz;
2242 unsigned twopixsize;
2243 unsigned img_width;
2244 unsigned stride;
2245 unsigned hmax;
2246 unsigned frame_line;
2247 unsigned frame_line_next;
2248
2249
2250 unsigned mv_hor_old;
2251 unsigned mv_hor_new;
2252 unsigned mv_vert_old;
2253 unsigned mv_vert_new;
2254
2255
2256 unsigned wss_width;
2257 unsigned wss_random_offset;
2258 unsigned sav_eav_f;
2259 unsigned left_pillar_width;
2260 unsigned right_pillar_start;
2261 };
2262
2263 static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
2264 struct tpg_draw_params *params)
2265 {
2266 params->mv_hor_old =
2267 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
2268 params->mv_hor_new =
2269 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
2270 tpg->src_width);
2271 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
2272 params->mv_vert_new =
2273 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
2274 }
2275
2276 static void tpg_fill_params_extras(const struct tpg_data *tpg,
2277 unsigned p,
2278 struct tpg_draw_params *params)
2279 {
2280 unsigned left_pillar_width = 0;
2281 unsigned right_pillar_start = params->img_width;
2282
2283 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
2284 tpg->src_width / 2 - tpg->crop.left : 0;
2285 if (params->wss_width > tpg->crop.width)
2286 params->wss_width = tpg->crop.width;
2287 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
2288 params->wss_random_offset =
2289 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
2290
2291 if (tpg->crop.left < tpg->border.left) {
2292 left_pillar_width = tpg->border.left - tpg->crop.left;
2293 if (left_pillar_width > tpg->crop.width)
2294 left_pillar_width = tpg->crop.width;
2295 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
2296 }
2297 params->left_pillar_width = left_pillar_width;
2298
2299 if (tpg->crop.left + tpg->crop.width >
2300 tpg->border.left + tpg->border.width) {
2301 right_pillar_start =
2302 tpg->border.left + tpg->border.width - tpg->crop.left;
2303 right_pillar_start =
2304 tpg_hscale_div(tpg, p, right_pillar_start);
2305 if (right_pillar_start > params->img_width)
2306 right_pillar_start = params->img_width;
2307 }
2308 params->right_pillar_start = right_pillar_start;
2309
2310 params->sav_eav_f = tpg->field ==
2311 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
2312 }
2313
2314 static void tpg_fill_plane_extras(const struct tpg_data *tpg,
2315 const struct tpg_draw_params *params,
2316 unsigned p, unsigned h, u8 *vbuf)
2317 {
2318 unsigned twopixsize = params->twopixsize;
2319 unsigned img_width = params->img_width;
2320 unsigned frame_line = params->frame_line;
2321 const struct v4l2_rect *sq = &tpg->square;
2322 const struct v4l2_rect *b = &tpg->border;
2323 const struct v4l2_rect *c = &tpg->crop;
2324
2325 if (params->is_tv && !params->is_60hz &&
2326 frame_line == 0 && params->wss_width) {
2327
2328
2329
2330
2331 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
2332
2333 memcpy(vbuf, wss, params->wss_width);
2334 }
2335
2336 if (tpg->show_border && frame_line >= b->top &&
2337 frame_line < b->top + b->height) {
2338 unsigned bottom = b->top + b->height - 1;
2339 unsigned left = params->left_pillar_width;
2340 unsigned right = params->right_pillar_start;
2341
2342 if (frame_line == b->top || frame_line == b->top + 1 ||
2343 frame_line == bottom || frame_line == bottom - 1) {
2344 memcpy(vbuf + left, tpg->contrast_line[p],
2345 right - left);
2346 } else {
2347 if (b->left >= c->left &&
2348 b->left < c->left + c->width)
2349 memcpy(vbuf + left,
2350 tpg->contrast_line[p], twopixsize);
2351 if (b->left + b->width > c->left &&
2352 b->left + b->width <= c->left + c->width)
2353 memcpy(vbuf + right - twopixsize,
2354 tpg->contrast_line[p], twopixsize);
2355 }
2356 }
2357 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2358 frame_line < b->top + b->height) {
2359 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2360 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2361 img_width - params->right_pillar_start);
2362 }
2363 if (tpg->show_square && frame_line >= sq->top &&
2364 frame_line < sq->top + sq->height &&
2365 sq->left < c->left + c->width &&
2366 sq->left + sq->width >= c->left) {
2367 unsigned left = sq->left;
2368 unsigned width = sq->width;
2369
2370 if (c->left > left) {
2371 width -= c->left - left;
2372 left = c->left;
2373 }
2374 if (c->left + c->width < left + width)
2375 width -= left + width - c->left - c->width;
2376 left -= c->left;
2377 left = tpg_hscale_div(tpg, p, left);
2378 width = tpg_hscale_div(tpg, p, width);
2379 memcpy(vbuf + left, tpg->contrast_line[p], width);
2380 }
2381 if (tpg->insert_sav) {
2382 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
2383 u8 *p = vbuf + offset;
2384 unsigned vact = 0, hact = 0;
2385
2386 p[0] = 0xff;
2387 p[1] = 0;
2388 p[2] = 0;
2389 p[3] = 0x80 | (params->sav_eav_f << 6) |
2390 (vact << 5) | (hact << 4) |
2391 ((hact ^ vact) << 3) |
2392 ((hact ^ params->sav_eav_f) << 2) |
2393 ((params->sav_eav_f ^ vact) << 1) |
2394 (hact ^ vact ^ params->sav_eav_f);
2395 }
2396 if (tpg->insert_eav) {
2397 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
2398 u8 *p = vbuf + offset;
2399 unsigned vact = 0, hact = 1;
2400
2401 p[0] = 0xff;
2402 p[1] = 0;
2403 p[2] = 0;
2404 p[3] = 0x80 | (params->sav_eav_f << 6) |
2405 (vact << 5) | (hact << 4) |
2406 ((hact ^ vact) << 3) |
2407 ((hact ^ params->sav_eav_f) << 2) |
2408 ((params->sav_eav_f ^ vact) << 1) |
2409 (hact ^ vact ^ params->sav_eav_f);
2410 }
2411 if (tpg->insert_hdmi_video_guard_band) {
2412 unsigned int i;
2413
2414 switch (tpg->fourcc) {
2415 case V4L2_PIX_FMT_BGR24:
2416 case V4L2_PIX_FMT_RGB24:
2417 for (i = 0; i < 3 * 4; i += 3) {
2418 vbuf[i] = 0xab;
2419 vbuf[i + 1] = 0x55;
2420 vbuf[i + 2] = 0xab;
2421 }
2422 break;
2423 case V4L2_PIX_FMT_RGB32:
2424 case V4L2_PIX_FMT_ARGB32:
2425 case V4L2_PIX_FMT_XRGB32:
2426 case V4L2_PIX_FMT_BGRX32:
2427 case V4L2_PIX_FMT_BGRA32:
2428 for (i = 0; i < 4 * 4; i += 4) {
2429 vbuf[i] = 0x00;
2430 vbuf[i + 1] = 0xab;
2431 vbuf[i + 2] = 0x55;
2432 vbuf[i + 3] = 0xab;
2433 }
2434 break;
2435 case V4L2_PIX_FMT_BGR32:
2436 case V4L2_PIX_FMT_XBGR32:
2437 case V4L2_PIX_FMT_ABGR32:
2438 case V4L2_PIX_FMT_RGBX32:
2439 case V4L2_PIX_FMT_RGBA32:
2440 for (i = 0; i < 4 * 4; i += 4) {
2441 vbuf[i] = 0xab;
2442 vbuf[i + 1] = 0x55;
2443 vbuf[i + 2] = 0xab;
2444 vbuf[i + 3] = 0x00;
2445 }
2446 break;
2447 }
2448 }
2449 }
2450
2451 static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2452 const struct tpg_draw_params *params,
2453 unsigned p, unsigned h, u8 *vbuf)
2454 {
2455 unsigned twopixsize = params->twopixsize;
2456 unsigned img_width = params->img_width;
2457 unsigned mv_hor_old = params->mv_hor_old;
2458 unsigned mv_hor_new = params->mv_hor_new;
2459 unsigned mv_vert_old = params->mv_vert_old;
2460 unsigned mv_vert_new = params->mv_vert_new;
2461 unsigned frame_line = params->frame_line;
2462 unsigned frame_line_next = params->frame_line_next;
2463 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
2464 bool even;
2465 bool fill_blank = false;
2466 unsigned pat_line_old;
2467 unsigned pat_line_new;
2468 u8 *linestart_older;
2469 u8 *linestart_newer;
2470 u8 *linestart_top;
2471 u8 *linestart_bottom;
2472
2473 even = !(frame_line & 1);
2474
2475 if (h >= params->hmax) {
2476 if (params->hmax == tpg->compose.height)
2477 return;
2478 if (!tpg->perc_fill_blank)
2479 return;
2480 fill_blank = true;
2481 }
2482
2483 if (tpg->vflip) {
2484 frame_line = tpg->src_height - frame_line - 1;
2485 frame_line_next = tpg->src_height - frame_line_next - 1;
2486 }
2487
2488 if (fill_blank) {
2489 linestart_older = tpg->contrast_line[p];
2490 linestart_newer = tpg->contrast_line[p];
2491 } else if (tpg->qual != TPG_QUAL_NOISE &&
2492 (frame_line < tpg->border.top ||
2493 frame_line >= tpg->border.top + tpg->border.height)) {
2494 linestart_older = tpg->black_line[p];
2495 linestart_newer = tpg->black_line[p];
2496 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2497 linestart_older = tpg->random_line[p] +
2498 twopixsize * prandom_u32_max(tpg->src_width / 2);
2499 linestart_newer = tpg->random_line[p] +
2500 twopixsize * prandom_u32_max(tpg->src_width / 2);
2501 } else {
2502 unsigned frame_line_old =
2503 (frame_line + mv_vert_old) % tpg->src_height;
2504 unsigned frame_line_new =
2505 (frame_line + mv_vert_new) % tpg->src_height;
2506 unsigned pat_line_next_old;
2507 unsigned pat_line_next_new;
2508
2509 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
2510 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
2511 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2512 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2513
2514 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2515 int avg_pat;
2516
2517
2518
2519
2520
2521 pat_line_next_old = tpg_get_pat_line(tpg,
2522 (frame_line_next + mv_vert_old) % tpg->src_height);
2523 pat_line_next_new = tpg_get_pat_line(tpg,
2524 (frame_line_next + mv_vert_new) % tpg->src_height);
2525
2526 switch (tpg->field) {
2527 case V4L2_FIELD_INTERLACED:
2528 case V4L2_FIELD_INTERLACED_BT:
2529 case V4L2_FIELD_INTERLACED_TB:
2530 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2531 if (avg_pat < 0)
2532 break;
2533 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2534 linestart_newer = linestart_older;
2535 break;
2536 case V4L2_FIELD_NONE:
2537 case V4L2_FIELD_TOP:
2538 case V4L2_FIELD_BOTTOM:
2539 case V4L2_FIELD_SEQ_BT:
2540 case V4L2_FIELD_SEQ_TB:
2541 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2542 if (avg_pat >= 0)
2543 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2544 mv_hor_old;
2545 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2546 if (avg_pat >= 0)
2547 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2548 mv_hor_new;
2549 break;
2550 }
2551 }
2552 linestart_older += line_offset;
2553 linestart_newer += line_offset;
2554 }
2555 if (tpg->field_alternate) {
2556 linestart_top = linestart_bottom = linestart_older;
2557 } else if (params->is_60hz) {
2558 linestart_top = linestart_newer;
2559 linestart_bottom = linestart_older;
2560 } else {
2561 linestart_top = linestart_older;
2562 linestart_bottom = linestart_newer;
2563 }
2564
2565 switch (tpg->field) {
2566 case V4L2_FIELD_INTERLACED:
2567 case V4L2_FIELD_INTERLACED_TB:
2568 case V4L2_FIELD_SEQ_TB:
2569 case V4L2_FIELD_SEQ_BT:
2570 if (even)
2571 memcpy(vbuf, linestart_top, img_width);
2572 else
2573 memcpy(vbuf, linestart_bottom, img_width);
2574 break;
2575 case V4L2_FIELD_INTERLACED_BT:
2576 if (even)
2577 memcpy(vbuf, linestart_bottom, img_width);
2578 else
2579 memcpy(vbuf, linestart_top, img_width);
2580 break;
2581 case V4L2_FIELD_TOP:
2582 memcpy(vbuf, linestart_top, img_width);
2583 break;
2584 case V4L2_FIELD_BOTTOM:
2585 memcpy(vbuf, linestart_bottom, img_width);
2586 break;
2587 case V4L2_FIELD_NONE:
2588 default:
2589 memcpy(vbuf, linestart_older, img_width);
2590 break;
2591 }
2592 }
2593
2594 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2595 unsigned p, u8 *vbuf)
2596 {
2597 struct tpg_draw_params params;
2598 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
2599
2600
2601 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2602 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2603 unsigned src_y = 0;
2604 unsigned error = 0;
2605 unsigned h;
2606
2607 tpg_recalc(tpg);
2608
2609 params.is_tv = std;
2610 params.is_60hz = std & V4L2_STD_525_60;
2611 params.twopixsize = tpg->twopixelsize[p];
2612 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2613 params.stride = tpg->bytesperline[p];
2614 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2615
2616 tpg_fill_params_pattern(tpg, p, ¶ms);
2617 tpg_fill_params_extras(tpg, p, ¶ms);
2618
2619 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
2620
2621 for (h = 0; h < tpg->compose.height; h++) {
2622 unsigned buf_line;
2623
2624 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2625 params.frame_line_next = params.frame_line;
2626 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2627 src_y += int_part;
2628 error += fract_part;
2629 if (error >= tpg->compose.height) {
2630 error -= tpg->compose.height;
2631 src_y++;
2632 }
2633
2634
2635
2636
2637
2638 if (tpg_g_interleaved(tpg))
2639 p = tpg_g_interleaved_plane(tpg, buf_line);
2640
2641 if (tpg->vdownsampling[p] > 1) {
2642
2643
2644
2645
2646
2647
2648
2649
2650 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2651 tpg->field == V4L2_FIELD_SEQ_TB) {
2652 unsigned next_src_y = src_y;
2653
2654 if ((h & 3) >= 2)
2655 continue;
2656 next_src_y += int_part;
2657 if (error + fract_part >= tpg->compose.height)
2658 next_src_y++;
2659 params.frame_line_next =
2660 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2661 } else {
2662 if (h & 1)
2663 continue;
2664 params.frame_line_next =
2665 tpg_calc_frameline(tpg, src_y, tpg->field);
2666 }
2667
2668 buf_line /= tpg->vdownsampling[p];
2669 }
2670 tpg_fill_plane_pattern(tpg, ¶ms, p, h,
2671 vbuf + buf_line * params.stride);
2672 tpg_fill_plane_extras(tpg, ¶ms, p, h,
2673 vbuf + buf_line * params.stride);
2674 }
2675 }
2676 EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
2677
2678 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2679 {
2680 unsigned offset = 0;
2681 unsigned i;
2682
2683 if (tpg->buffers > 1) {
2684 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2685 return;
2686 }
2687
2688 for (i = 0; i < tpg_g_planes(tpg); i++) {
2689 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2690 offset += tpg_calc_plane_size(tpg, i);
2691 }
2692 }
2693 EXPORT_SYMBOL_GPL(tpg_fillbuffer);
2694
2695 MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2696 MODULE_AUTHOR("Hans Verkuil");
2697 MODULE_LICENSE("GPL");