Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] cx18: Use the control framework

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
a75b9be1 34a078da

+172 -511
+12 -80
drivers/media/video/cx18/cx18-av-audio.c
··· 342 342 } 343 343 } 344 344 345 - static int get_volume(struct cx18 *cx) 346 - { 347 - /* Volume runs +18dB to -96dB in 1/2dB steps 348 - * change to fit the msp3400 -114dB to +12dB range */ 349 - 350 - /* check PATH1_VOLUME */ 351 - int vol = 228 - cx18_av_read(cx, 0x8d4); 352 - vol = (vol / 2) + 23; 353 - return vol << 9; 354 - } 355 - 356 345 static void set_volume(struct cx18 *cx, int volume) 357 346 { 358 347 /* First convert the volume to msp3400 values (0-127) */ ··· 358 369 cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); 359 370 } 360 371 361 - static int get_bass(struct cx18 *cx) 362 - { 363 - /* bass is 49 steps +12dB to -12dB */ 364 - 365 - /* check PATH1_EQ_BASS_VOL */ 366 - int bass = cx18_av_read(cx, 0x8d9) & 0x3f; 367 - bass = (((48 - bass) * 0xffff) + 47) / 48; 368 - return bass; 369 - } 370 - 371 372 static void set_bass(struct cx18 *cx, int bass) 372 373 { 373 374 /* PATH1_EQ_BASS_VOL */ 374 375 cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); 375 376 } 376 377 377 - static int get_treble(struct cx18 *cx) 378 - { 379 - /* treble is 49 steps +12dB to -12dB */ 380 - 381 - /* check PATH1_EQ_TREBLE_VOL */ 382 - int treble = cx18_av_read(cx, 0x8db) & 0x3f; 383 - treble = (((48 - treble) * 0xffff) + 47) / 48; 384 - return treble; 385 - } 386 - 387 378 static void set_treble(struct cx18 *cx, int treble) 388 379 { 389 380 /* PATH1_EQ_TREBLE_VOL */ 390 381 cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); 391 - } 392 - 393 - static int get_balance(struct cx18 *cx) 394 - { 395 - /* balance is 7 bit, 0 to -96dB */ 396 - 397 - /* check PATH1_BAL_LEVEL */ 398 - int balance = cx18_av_read(cx, 0x8d5) & 0x7f; 399 - /* check PATH1_BAL_LEFT */ 400 - if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) 401 - balance = 0x80 - balance; 402 - else 403 - balance = 0x80 + balance; 404 - return balance << 8; 405 382 } 406 383 407 384 static void set_balance(struct cx18 *cx, int balance) ··· 384 429 /* PATH1_BAL_LEVEL */ 385 430 cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); 386 431 } 387 - } 388 - 389 - static int get_mute(struct cx18 *cx) 390 - { 391 - /* check SRC1_MUTE_EN */ 392 - return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; 393 432 } 394 433 395 434 static void set_mute(struct cx18 *cx, int mute) ··· 439 490 return retval; 440 491 } 441 492 442 - int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) 493 + static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) 443 494 { 495 + struct v4l2_subdev *sd = to_sd(ctrl); 496 + struct cx18 *cx = v4l2_get_subdevdata(sd); 497 + 444 498 switch (ctrl->id) { 445 499 case V4L2_CID_AUDIO_VOLUME: 446 - ctrl->value = get_volume(cx); 500 + set_volume(cx, ctrl->val); 447 501 break; 448 502 case V4L2_CID_AUDIO_BASS: 449 - ctrl->value = get_bass(cx); 503 + set_bass(cx, ctrl->val); 450 504 break; 451 505 case V4L2_CID_AUDIO_TREBLE: 452 - ctrl->value = get_treble(cx); 506 + set_treble(cx, ctrl->val); 453 507 break; 454 508 case V4L2_CID_AUDIO_BALANCE: 455 - ctrl->value = get_balance(cx); 509 + set_balance(cx, ctrl->val); 456 510 break; 457 511 case V4L2_CID_AUDIO_MUTE: 458 - ctrl->value = get_mute(cx); 512 + set_mute(cx, ctrl->val); 459 513 break; 460 514 default: 461 515 return -EINVAL; ··· 466 514 return 0; 467 515 } 468 516 469 - int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) 470 - { 471 - switch (ctrl->id) { 472 - case V4L2_CID_AUDIO_VOLUME: 473 - set_volume(cx, ctrl->value); 474 - break; 475 - case V4L2_CID_AUDIO_BASS: 476 - set_bass(cx, ctrl->value); 477 - break; 478 - case V4L2_CID_AUDIO_TREBLE: 479 - set_treble(cx, ctrl->value); 480 - break; 481 - case V4L2_CID_AUDIO_BALANCE: 482 - set_balance(cx, ctrl->value); 483 - break; 484 - case V4L2_CID_AUDIO_MUTE: 485 - set_mute(cx, ctrl->value); 486 - break; 487 - default: 488 - return -EINVAL; 489 - } 490 - return 0; 491 - } 517 + const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { 518 + .s_ctrl = cx18_av_audio_s_ctrl, 519 + };
+71 -104
drivers/media/video/cx18/cx18-av-core.c
··· 129 129 { 130 130 struct cx18_av_state *state = to_cx18_av_state(sd); 131 131 struct cx18 *cx = v4l2_get_subdevdata(sd); 132 + int default_volume; 132 133 u32 v; 133 134 134 135 cx18_av_loadfw(cx); ··· 248 247 /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ 249 248 /* } */ 250 249 cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); 251 - state->default_volume = 228 - cx18_av_read(cx, 0x8d4); 252 - state->default_volume = ((state->default_volume / 2) + 23) << 9; 250 + default_volume = cx18_av_read(cx, 0x8d4); 251 + /* 252 + * Enforce the legacy volume scale mapping limits to avoid 253 + * -ERANGE errors when initializing the volume control 254 + */ 255 + if (default_volume > 228) { 256 + /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ 257 + default_volume = 228; 258 + cx18_av_write(cx, 0x8d4, 228); 259 + } else if (default_volume < 20) { 260 + /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ 261 + default_volume = 20; 262 + cx18_av_write(cx, 0x8d4, 20); 263 + } 264 + default_volume = (((228 - default_volume) >> 1) + 23) << 9; 265 + state->volume->cur.val = state->volume->default_value = default_volume; 266 + v4l2_ctrl_handler_setup(&state->hdl); 253 267 } 254 268 255 269 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) ··· 917 901 return 0; 918 902 } 919 903 920 - static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 904 + static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) 921 905 { 906 + struct v4l2_subdev *sd = to_sd(ctrl); 922 907 struct cx18 *cx = v4l2_get_subdevdata(sd); 923 908 924 909 switch (ctrl->id) { 925 910 case V4L2_CID_BRIGHTNESS: 926 - if (ctrl->value < 0 || ctrl->value > 255) { 927 - CX18_ERR_DEV(sd, "invalid brightness setting %d\n", 928 - ctrl->value); 929 - return -ERANGE; 930 - } 931 - 932 - cx18_av_write(cx, 0x414, ctrl->value - 128); 911 + cx18_av_write(cx, 0x414, ctrl->val - 128); 933 912 break; 934 913 935 914 case V4L2_CID_CONTRAST: 936 - if (ctrl->value < 0 || ctrl->value > 127) { 937 - CX18_ERR_DEV(sd, "invalid contrast setting %d\n", 938 - ctrl->value); 939 - return -ERANGE; 940 - } 941 - 942 - cx18_av_write(cx, 0x415, ctrl->value << 1); 915 + cx18_av_write(cx, 0x415, ctrl->val << 1); 943 916 break; 944 917 945 918 case V4L2_CID_SATURATION: 946 - if (ctrl->value < 0 || ctrl->value > 127) { 947 - CX18_ERR_DEV(sd, "invalid saturation setting %d\n", 948 - ctrl->value); 949 - return -ERANGE; 950 - } 951 - 952 - cx18_av_write(cx, 0x420, ctrl->value << 1); 953 - cx18_av_write(cx, 0x421, ctrl->value << 1); 919 + cx18_av_write(cx, 0x420, ctrl->val << 1); 920 + cx18_av_write(cx, 0x421, ctrl->val << 1); 954 921 break; 955 922 956 923 case V4L2_CID_HUE: 957 - if (ctrl->value < -128 || ctrl->value > 127) { 958 - CX18_ERR_DEV(sd, "invalid hue setting %d\n", 959 - ctrl->value); 960 - return -ERANGE; 961 - } 962 - 963 - cx18_av_write(cx, 0x422, ctrl->value); 924 + cx18_av_write(cx, 0x422, ctrl->val); 964 925 break; 965 - 966 - case V4L2_CID_AUDIO_VOLUME: 967 - case V4L2_CID_AUDIO_BASS: 968 - case V4L2_CID_AUDIO_TREBLE: 969 - case V4L2_CID_AUDIO_BALANCE: 970 - case V4L2_CID_AUDIO_MUTE: 971 - return cx18_av_audio_s_ctrl(cx, ctrl); 972 926 973 927 default: 974 928 return -EINVAL; 975 929 } 976 930 return 0; 977 - } 978 - 979 - static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 980 - { 981 - struct cx18 *cx = v4l2_get_subdevdata(sd); 982 - 983 - switch (ctrl->id) { 984 - case V4L2_CID_BRIGHTNESS: 985 - ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; 986 - break; 987 - case V4L2_CID_CONTRAST: 988 - ctrl->value = cx18_av_read(cx, 0x415) >> 1; 989 - break; 990 - case V4L2_CID_SATURATION: 991 - ctrl->value = cx18_av_read(cx, 0x420) >> 1; 992 - break; 993 - case V4L2_CID_HUE: 994 - ctrl->value = (s8)cx18_av_read(cx, 0x422); 995 - break; 996 - case V4L2_CID_AUDIO_VOLUME: 997 - case V4L2_CID_AUDIO_BASS: 998 - case V4L2_CID_AUDIO_TREBLE: 999 - case V4L2_CID_AUDIO_BALANCE: 1000 - case V4L2_CID_AUDIO_MUTE: 1001 - return cx18_av_audio_g_ctrl(cx, ctrl); 1002 - default: 1003 - return -EINVAL; 1004 - } 1005 - return 0; 1006 - } 1007 - 1008 - static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) 1009 - { 1010 - struct cx18_av_state *state = to_cx18_av_state(sd); 1011 - 1012 - switch (qc->id) { 1013 - case V4L2_CID_BRIGHTNESS: 1014 - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); 1015 - case V4L2_CID_CONTRAST: 1016 - case V4L2_CID_SATURATION: 1017 - return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); 1018 - case V4L2_CID_HUE: 1019 - return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); 1020 - default: 1021 - break; 1022 - } 1023 - 1024 - switch (qc->id) { 1025 - case V4L2_CID_AUDIO_VOLUME: 1026 - return v4l2_ctrl_query_fill(qc, 0, 65535, 1027 - 65535 / 100, state->default_volume); 1028 - case V4L2_CID_AUDIO_MUTE: 1029 - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); 1030 - case V4L2_CID_AUDIO_BALANCE: 1031 - case V4L2_CID_AUDIO_BASS: 1032 - case V4L2_CID_AUDIO_TREBLE: 1033 - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); 1034 - default: 1035 - return -EINVAL; 1036 - } 1037 - return -EINVAL; 1038 931 } 1039 932 1040 933 static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) ··· 1281 1356 } 1282 1357 #endif 1283 1358 1359 + static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { 1360 + .s_ctrl = cx18_av_s_ctrl, 1361 + }; 1362 + 1284 1363 static const struct v4l2_subdev_core_ops cx18_av_general_ops = { 1285 1364 .g_chip_ident = cx18_av_g_chip_ident, 1286 1365 .log_status = cx18_av_log_status, 1287 1366 .load_fw = cx18_av_load_fw, 1288 1367 .reset = cx18_av_reset, 1289 - .queryctrl = cx18_av_queryctrl, 1290 - .g_ctrl = cx18_av_g_ctrl, 1291 - .s_ctrl = cx18_av_s_ctrl, 1368 + .g_ctrl = v4l2_subdev_g_ctrl, 1369 + .s_ctrl = v4l2_subdev_s_ctrl, 1370 + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, 1371 + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, 1372 + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, 1373 + .queryctrl = v4l2_subdev_queryctrl, 1374 + .querymenu = v4l2_subdev_querymenu, 1292 1375 .s_std = cx18_av_s_std, 1293 1376 #ifdef CONFIG_VIDEO_ADV_DEBUG 1294 1377 .g_register = cx18_av_g_register, ··· 1360 1427 snprintf(sd->name, sizeof(sd->name), 1361 1428 "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); 1362 1429 sd->grp_id = CX18_HW_418_AV; 1430 + v4l2_ctrl_handler_init(&state->hdl, 9); 1431 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, 1432 + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); 1433 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, 1434 + V4L2_CID_CONTRAST, 0, 127, 1, 64); 1435 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, 1436 + V4L2_CID_SATURATION, 0, 127, 1, 64); 1437 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, 1438 + V4L2_CID_HUE, -128, 127, 1, 0); 1439 + 1440 + state->volume = v4l2_ctrl_new_std(&state->hdl, 1441 + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 1442 + 0, 65535, 65535 / 100, 0); 1443 + v4l2_ctrl_new_std(&state->hdl, 1444 + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, 1445 + 0, 1, 1, 0); 1446 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, 1447 + V4L2_CID_AUDIO_BALANCE, 1448 + 0, 65535, 65535 / 100, 32768); 1449 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, 1450 + V4L2_CID_AUDIO_BASS, 1451 + 0, 65535, 65535 / 100, 32768); 1452 + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, 1453 + V4L2_CID_AUDIO_TREBLE, 1454 + 0, 65535, 65535 / 100, 32768); 1455 + sd->ctrl_handler = &state->hdl; 1456 + if (state->hdl.error) { 1457 + int err = state->hdl.error; 1458 + 1459 + v4l2_ctrl_handler_free(&state->hdl); 1460 + return err; 1461 + } 1363 1462 err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); 1364 - if (!err) 1463 + if (err) 1464 + v4l2_ctrl_handler_free(&state->hdl); 1465 + else 1365 1466 cx18_av_init(cx); 1366 1467 return err; 1367 1468 }
+9 -3
drivers/media/video/cx18/cx18-av-core.h
··· 26 26 #define _CX18_AV_CORE_H_ 27 27 28 28 #include <media/v4l2-device.h> 29 + #include <media/v4l2-ctrls.h> 29 30 30 31 struct cx18; 31 32 ··· 96 95 97 96 struct cx18_av_state { 98 97 struct v4l2_subdev sd; 98 + struct v4l2_ctrl_handler hdl; 99 + struct v4l2_ctrl *volume; 99 100 int radio; 100 101 v4l2_std_id std; 101 102 enum cx18_av_video_input vid_input; 102 103 enum cx18_av_audio_input aud_input; 103 104 u32 audclk_freq; 104 105 int audmode; 105 - int default_volume; 106 106 u32 id; 107 107 u32 rev; 108 108 int is_initialized; ··· 349 347 return container_of(sd, struct cx18_av_state, sd); 350 348 } 351 349 350 + static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 351 + { 352 + return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; 353 + } 354 + 352 355 /* ----------------------------------------------------------------------- */ 353 356 /* cx18_av-core.c */ 354 357 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); ··· 376 369 377 370 /* ----------------------------------------------------------------------- */ 378 371 /* cx18_av-audio.c */ 379 - int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); 380 - int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); 381 372 int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); 382 373 void cx18_av_audio_set_path(struct cx18 *cx); 374 + extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; 383 375 384 376 /* ----------------------------------------------------------------------- */ 385 377 /* cx18_av-vbi.c */
+32 -251
drivers/media/video/cx18/cx18-controls.c
··· 30 30 #include "cx18-mailbox.h" 31 31 #include "cx18-controls.h" 32 32 33 - /* Must be sorted from low to high control ID! */ 34 - static const u32 user_ctrls[] = { 35 - V4L2_CID_USER_CLASS, 36 - V4L2_CID_BRIGHTNESS, 37 - V4L2_CID_CONTRAST, 38 - V4L2_CID_SATURATION, 39 - V4L2_CID_HUE, 40 - V4L2_CID_AUDIO_VOLUME, 41 - V4L2_CID_AUDIO_BALANCE, 42 - V4L2_CID_AUDIO_BASS, 43 - V4L2_CID_AUDIO_TREBLE, 44 - V4L2_CID_AUDIO_MUTE, 45 - V4L2_CID_AUDIO_LOUDNESS, 46 - 0 47 - }; 48 - 49 - static const u32 *ctrl_classes[] = { 50 - user_ctrls, 51 - cx2341x_mpeg_ctrls, 52 - NULL 53 - }; 54 - 55 - int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) 33 + static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) 56 34 { 57 - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; 58 - const char *name; 35 + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 36 + int type = cxhdl->stream_type->val; 59 37 60 - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); 61 - if (qctrl->id == 0) 62 - return -EINVAL; 63 - 64 - switch (qctrl->id) { 65 - /* Standard V4L2 controls */ 66 - case V4L2_CID_USER_CLASS: 67 - return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); 68 - case V4L2_CID_BRIGHTNESS: 69 - case V4L2_CID_HUE: 70 - case V4L2_CID_SATURATION: 71 - case V4L2_CID_CONTRAST: 72 - if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) 73 - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 74 - return 0; 75 - 76 - case V4L2_CID_AUDIO_VOLUME: 77 - case V4L2_CID_AUDIO_MUTE: 78 - case V4L2_CID_AUDIO_BALANCE: 79 - case V4L2_CID_AUDIO_BASS: 80 - case V4L2_CID_AUDIO_TREBLE: 81 - case V4L2_CID_AUDIO_LOUDNESS: 82 - if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) 83 - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 84 - return 0; 85 - 86 - default: 87 - if (cx2341x_ctrl_query(&cx->params, qctrl)) 88 - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; 89 - return 0; 90 - } 91 - strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); 92 - qctrl->name[sizeof(qctrl->name) - 1] = 0; 93 - return 0; 94 - } 95 - 96 - int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) 97 - { 98 - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; 99 - struct v4l2_queryctrl qctrl; 100 - 101 - qctrl.id = qmenu->id; 102 - cx18_queryctrl(file, fh, &qctrl); 103 - return v4l2_ctrl_query_menu(qmenu, &qctrl, 104 - cx2341x_ctrl_get_menu(&cx->params, qmenu->id)); 105 - } 106 - 107 - static int cx18_try_ctrl(struct file *file, void *fh, 108 - struct v4l2_ext_control *vctrl) 109 - { 110 - struct v4l2_queryctrl qctrl; 111 - const char * const *menu_items = NULL; 112 - int err; 113 - 114 - qctrl.id = vctrl->id; 115 - err = cx18_queryctrl(file, fh, &qctrl); 116 - if (err) 117 - return err; 118 - if (qctrl.type == V4L2_CTRL_TYPE_MENU) 119 - menu_items = v4l2_ctrl_get_menu(qctrl.id); 120 - return v4l2_ctrl_check(vctrl, &qctrl, menu_items); 121 - } 122 - 123 - static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) 124 - { 125 - switch (vctrl->id) { 126 - /* Standard V4L2 controls */ 127 - case V4L2_CID_BRIGHTNESS: 128 - case V4L2_CID_HUE: 129 - case V4L2_CID_SATURATION: 130 - case V4L2_CID_CONTRAST: 131 - return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); 132 - 133 - case V4L2_CID_AUDIO_VOLUME: 134 - case V4L2_CID_AUDIO_MUTE: 135 - case V4L2_CID_AUDIO_BALANCE: 136 - case V4L2_CID_AUDIO_BASS: 137 - case V4L2_CID_AUDIO_TREBLE: 138 - case V4L2_CID_AUDIO_LOUDNESS: 139 - return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); 140 - 141 - default: 142 - CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); 143 - return -EINVAL; 144 - } 145 - return 0; 146 - } 147 - 148 - static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) 149 - { 150 - switch (vctrl->id) { 151 - /* Standard V4L2 controls */ 152 - case V4L2_CID_BRIGHTNESS: 153 - case V4L2_CID_HUE: 154 - case V4L2_CID_SATURATION: 155 - case V4L2_CID_CONTRAST: 156 - return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); 157 - 158 - case V4L2_CID_AUDIO_VOLUME: 159 - case V4L2_CID_AUDIO_MUTE: 160 - case V4L2_CID_AUDIO_BALANCE: 161 - case V4L2_CID_AUDIO_BASS: 162 - case V4L2_CID_AUDIO_TREBLE: 163 - case V4L2_CID_AUDIO_LOUDNESS: 164 - return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); 165 - 166 - default: 167 - CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); 168 - return -EINVAL; 169 - } 170 - return 0; 171 - } 172 - 173 - static int cx18_setup_vbi_fmt(struct cx18 *cx, 174 - enum v4l2_mpeg_stream_vbi_fmt fmt, 175 - enum v4l2_mpeg_stream_type type) 176 - { 177 - if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) 178 - return -EINVAL; 179 38 if (atomic_read(&cx->ana_capturing) > 0) 180 39 return -EBUSY; 181 40 ··· 89 230 return 0; 90 231 } 91 232 92 - int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 233 + static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) 93 234 { 94 - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; 95 - struct v4l2_control ctrl; 235 + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 236 + int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; 237 + struct v4l2_mbus_framefmt fmt; 96 238 97 - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { 98 - int i; 99 - int err = 0; 100 - 101 - for (i = 0; i < c->count; i++) { 102 - ctrl.id = c->controls[i].id; 103 - ctrl.value = c->controls[i].value; 104 - err = cx18_g_ctrl(cx, &ctrl); 105 - c->controls[i].value = ctrl.value; 106 - if (err) { 107 - c->error_idx = i; 108 - break; 109 - } 110 - } 111 - return err; 112 - } 113 - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) 114 - return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS); 115 - return -EINVAL; 239 + /* fix videodecoder resolution */ 240 + fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); 241 + fmt.height = cxhdl->height; 242 + fmt.code = V4L2_MBUS_FMT_FIXED; 243 + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); 244 + return 0; 116 245 } 117 246 118 - int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 247 + static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) 119 248 { 120 - struct cx18_open_id *id = fh; 121 - struct cx18 *cx = id->cx; 122 - int ret; 123 - struct v4l2_control ctrl; 249 + static const u32 freqs[3] = { 44100, 48000, 32000 }; 250 + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 124 251 125 - ret = v4l2_prio_check(&cx->prio, id->prio); 126 - if (ret) 127 - return ret; 128 - 129 - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { 130 - int i; 131 - int err = 0; 132 - 133 - for (i = 0; i < c->count; i++) { 134 - ctrl.id = c->controls[i].id; 135 - ctrl.value = c->controls[i].value; 136 - err = cx18_s_ctrl(cx, &ctrl); 137 - c->controls[i].value = ctrl.value; 138 - if (err) { 139 - c->error_idx = i; 140 - break; 141 - } 142 - } 143 - return err; 144 - } 145 - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { 146 - static u32 freqs[3] = { 44100, 48000, 32000 }; 147 - struct cx18_api_func_private priv; 148 - struct cx2341x_mpeg_params p = cx->params; 149 - int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), 150 - c, VIDIOC_S_EXT_CTRLS); 151 - unsigned int idx; 152 - 153 - if (err) 154 - return err; 155 - 156 - if (p.video_encoding != cx->params.video_encoding) { 157 - int is_mpeg1 = p.video_encoding == 158 - V4L2_MPEG_VIDEO_ENCODING_MPEG_1; 159 - struct v4l2_mbus_framefmt fmt; 160 - 161 - /* fix videodecoder resolution */ 162 - fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1); 163 - fmt.height = cx->params.height; 164 - fmt.code = V4L2_MBUS_FMT_FIXED; 165 - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); 166 - } 167 - priv.cx = cx; 168 - priv.s = &cx->streams[id->type]; 169 - err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p); 170 - if (!err && 171 - (cx->params.stream_vbi_fmt != p.stream_vbi_fmt || 172 - cx->params.stream_type != p.stream_type)) 173 - err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt, 174 - p.stream_type); 175 - cx->params = p; 176 - cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; 177 - idx = p.audio_properties & 0x03; 178 - /* The audio clock of the digitizer must match the codec sample 179 - rate otherwise you get some very strange effects. */ 180 - if (idx < ARRAY_SIZE(freqs)) 181 - cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); 182 - return err; 183 - } 184 - return -EINVAL; 252 + /* The audio clock of the digitizer must match the codec sample 253 + rate otherwise you get some very strange effects. */ 254 + if (idx < ARRAY_SIZE(freqs)) 255 + cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); 256 + return 0; 185 257 } 186 258 187 - int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 259 + static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) 188 260 { 189 - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; 261 + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); 190 262 191 - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { 192 - int i; 193 - int err = 0; 194 - 195 - for (i = 0; i < c->count; i++) { 196 - err = cx18_try_ctrl(file, fh, &c->controls[i]); 197 - if (err) { 198 - c->error_idx = i; 199 - break; 200 - } 201 - } 202 - return err; 203 - } 204 - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) 205 - return cx2341x_ext_ctrls(&cx->params, 206 - atomic_read(&cx->ana_capturing), 207 - c, VIDIOC_TRY_EXT_CTRLS); 208 - return -EINVAL; 263 + cx->dualwatch_stereo_mode = val; 264 + return 0; 209 265 } 266 + 267 + struct cx2341x_handler_ops cx18_cxhdl_ops = { 268 + .s_audio_mode = cx18_s_audio_mode, 269 + .s_audio_sampling_freq = cx18_s_audio_sampling_freq, 270 + .s_video_encoding = cx18_s_video_encoding, 271 + .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, 272 + };
+1 -6
drivers/media/video/cx18/cx18-controls.h
··· 21 21 * 02111-1307 USA 22 22 */ 23 23 24 - int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); 25 - int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); 26 - int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); 27 - int cx18_try_ext_ctrls(struct file *file, void *fh, 28 - struct v4l2_ext_controls *a); 29 - int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); 24 + extern struct cx2341x_handler_ops cx18_cxhdl_ops;
+19 -11
drivers/media/video/cx18/cx18-driver.c
··· 36 36 #include "cx18-scb.h" 37 37 #include "cx18-mailbox.h" 38 38 #include "cx18-ioctl.h" 39 + #include "cx18-controls.h" 39 40 #include "tuner-xc2028.h" 40 41 41 42 #include <media/tveeprom.h> ··· 730 729 cx->open_id = 1; 731 730 732 731 /* Initial settings */ 733 - cx2341x_fill_defaults(&cx->params); 734 - cx->temporal_strength = cx->params.video_temporal_filter; 735 - cx->spatial_strength = cx->params.video_spatial_filter; 736 - cx->filter_mode = cx->params.video_spatial_filter_mode | 737 - (cx->params.video_temporal_filter_mode << 1) | 738 - (cx->params.video_median_filter_type << 2); 739 - cx->params.port = CX2341X_PORT_MEMORY; 740 - cx->params.capabilities = 741 - CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; 732 + cx->cxhdl.port = CX2341X_PORT_MEMORY; 733 + cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; 734 + cx->cxhdl.ops = &cx18_cxhdl_ops; 735 + cx->cxhdl.func = cx18_api_func; 736 + ret = cx2341x_handler_init(&cx->cxhdl, 50); 737 + if (ret) 738 + return ret; 739 + cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; 740 + 741 + cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; 742 + cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; 743 + cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | 744 + (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | 745 + (cx->cxhdl.video_median_filter_type->cur.val << 2); 746 + 742 747 init_waitqueue_head(&cx->cap_w); 743 748 init_waitqueue_head(&cx->mb_apu_waitq); 744 749 init_waitqueue_head(&cx->mb_cpu_waitq); ··· 1056 1049 else 1057 1050 cx->is_50hz = 1; 1058 1051 1059 - cx->params.video_gop_size = cx->is_60hz ? 15 : 12; 1052 + cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); 1060 1053 1061 1054 if (cx->options.radio > 0) 1062 1055 cx->v4l2_cap |= V4L2_CAP_RADIO; ··· 1102 1095 1103 1096 /* Load cx18 submodules (cx18-alsa) */ 1104 1097 request_modules(cx); 1105 - 1106 1098 return 0; 1107 1099 1108 1100 free_streams: ··· 1283 1277 if (cx->vbi.sliced_mpeg_data[0] != NULL) 1284 1278 for (i = 0; i < CX18_VBI_FRAMES; i++) 1285 1279 kfree(cx->vbi.sliced_mpeg_data[i]); 1280 + 1281 + v4l2_ctrl_handler_free(&cx->av_state.hdl); 1286 1282 1287 1283 CX18_INFO("Removed %s\n", cx->card_name); 1288 1284
+1 -1
drivers/media/video/cx18/cx18-driver.h
··· 565 565 struct cx18_av_state av_state; 566 566 567 567 /* codec settings */ 568 - struct cx2341x_mpeg_params params; 568 + struct cx2341x_handler cxhdl; 569 569 u32 filter_mode; 570 570 u32 temporal_strength; 571 571 u32 spatial_strength;
+7 -25
drivers/media/video/cx18/cx18-fileops.c
··· 160 160 static void cx18_dualwatch(struct cx18 *cx) 161 161 { 162 162 struct v4l2_tuner vt; 163 - u32 new_bitmap; 164 163 u32 new_stereo_mode; 165 - const u32 stereo_mask = 0x0300; 166 164 const u32 dual = 0x0200; 167 - u32 h; 168 165 169 - new_stereo_mode = cx->params.audio_properties & stereo_mask; 166 + new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); 170 167 memset(&vt, 0, sizeof(vt)); 171 168 cx18_call_all(cx, tuner, g_tuner, &vt); 172 169 if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && ··· 173 176 if (new_stereo_mode == cx->dualwatch_stereo_mode) 174 177 return; 175 178 176 - new_bitmap = new_stereo_mode 177 - | (cx->params.audio_properties & ~stereo_mask); 178 - 179 - CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. " 180 - "new audio_bitmask=0x%ux\n", 181 - cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); 182 - 183 - h = cx18_find_handle(cx); 184 - if (h == CX18_INVALID_TASK_HANDLE) { 185 - CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n"); 186 - return; 187 - } 188 - 189 - if (cx18_vapi(cx, 190 - CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) { 191 - cx->dualwatch_stereo_mode = new_stereo_mode; 192 - return; 193 - } 194 - CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); 179 + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", 180 + cx->dualwatch_stereo_mode, new_stereo_mode); 181 + if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) 182 + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); 195 183 } 196 184 197 185 ··· 706 724 if (atomic_read(&cx->ana_capturing) > 0) { 707 725 /* Undo video mute */ 708 726 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, 709 - cx->params.video_mute | 710 - (cx->params.video_mute_yuv << 8)); 727 + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | 728 + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); 711 729 } 712 730 /* Done! Unmute and continue. */ 713 731 cx18_unmute(cx);
+10 -14
drivers/media/video/cx18/cx18-ioctl.c
··· 152 152 struct cx18 *cx = id->cx; 153 153 struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; 154 154 155 - pixfmt->width = cx->params.width; 156 - pixfmt->height = cx->params.height; 155 + pixfmt->width = cx->cxhdl.width; 156 + pixfmt->height = cx->cxhdl.height; 157 157 pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 158 158 pixfmt->field = V4L2_FIELD_INTERLACED; 159 159 pixfmt->priv = 0; ··· 287 287 w = fmt->fmt.pix.width; 288 288 h = fmt->fmt.pix.height; 289 289 290 - if (cx->params.width == w && cx->params.height == h) 290 + if (cx->cxhdl.width == w && cx->cxhdl.height == h) 291 291 return 0; 292 292 293 293 if (atomic_read(&cx->ana_capturing) > 0) 294 294 return -EBUSY; 295 295 296 - mbus_fmt.width = cx->params.width = w; 297 - mbus_fmt.height = cx->params.height = h; 296 + mbus_fmt.width = cx->cxhdl.width = w; 297 + mbus_fmt.height = cx->cxhdl.height = h; 298 298 mbus_fmt.code = V4L2_MBUS_FMT_FIXED; 299 299 v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); 300 300 return cx18_g_fmt_vid_cap(file, fh, fmt); ··· 696 696 697 697 cx->std = *std; 698 698 cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; 699 - cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; 700 - cx->params.width = 720; 701 - cx->params.height = cx->is_50hz ? 576 : 480; 699 + cx->is_50hz = !cx->is_60hz; 700 + cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); 701 + cx->cxhdl.width = 720; 702 + cx->cxhdl.height = cx->is_50hz ? 576 : 480; 702 703 cx->vbi.count = cx->is_50hz ? 18 : 12; 703 704 cx->vbi.start[0] = cx->is_50hz ? 6 : 10; 704 705 cx->vbi.start[1] = cx->is_50hz ? 318 : 273; ··· 1036 1035 mutex_unlock(&cx->gpio_lock); 1037 1036 CX18_INFO("Tuner: %s\n", 1038 1037 test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); 1039 - cx2341x_log_status(&cx->params, cx->v4l2_dev.name); 1038 + v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); 1040 1039 CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); 1041 1040 for (i = 0; i < CX18_MAX_STREAMS; i++) { 1042 1041 struct cx18_stream *s = &cx->streams[i]; ··· 1137 1136 .vidioc_s_register = cx18_s_register, 1138 1137 #endif 1139 1138 .vidioc_default = cx18_default, 1140 - .vidioc_queryctrl = cx18_queryctrl, 1141 - .vidioc_querymenu = cx18_querymenu, 1142 - .vidioc_g_ext_ctrls = cx18_g_ext_ctrls, 1143 - .vidioc_s_ext_ctrls = cx18_s_ext_ctrls, 1144 - .vidioc_try_ext_ctrls = cx18_try_ext_ctrls, 1145 1139 }; 1146 1140 1147 1141 void cx18_set_funcs(struct video_device *vdev)
+2 -3
drivers/media/video/cx18/cx18-mailbox.c
··· 716 716 int cx18_api_func(void *priv, u32 cmd, int in, int out, 717 717 u32 data[CX2341X_MBOX_MAX_DATA]) 718 718 { 719 - struct cx18_api_func_private *api_priv = priv; 720 - struct cx18 *cx = api_priv->cx; 721 - struct cx18_stream *s = api_priv->s; 719 + struct cx18_stream *s = priv; 720 + struct cx18 *cx = s->cx; 722 721 723 722 switch (cmd) { 724 723 case CX2341X_ENC_SET_OUTPUT_PORT:
-5
drivers/media/video/cx18/cx18-mailbox.h
··· 81 81 82 82 struct cx18_stream; 83 83 84 - struct cx18_api_func_private { 85 - struct cx18 *cx; 86 - struct cx18_stream *s; 87 - }; 88 - 89 84 int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); 90 85 int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, 91 86 int args, ...);
+8 -8
drivers/media/video/cx18/cx18-streams.c
··· 572 572 * Set the MDL size to the exact size needed for one frame. 573 573 * Use enough buffers per MDL to cover the MDL size 574 574 */ 575 - s->mdl_size = 720 * s->cx->params.height * 3 / 2; 575 + s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; 576 576 s->bufs_per_mdl = s->mdl_size / s->buf_size; 577 577 if (s->mdl_size % s->buf_size) 578 578 s->bufs_per_mdl++; ··· 607 607 u32 data[MAX_MB_ARGUMENTS]; 608 608 struct cx18 *cx = s->cx; 609 609 int captype = 0; 610 - struct cx18_api_func_private priv; 611 610 struct cx18_stream *s_idx; 612 611 613 612 if (!cx18_stream_enabled(s)) ··· 619 620 captype = CAPTURE_CHANNEL_TYPE_MPEG; 620 621 cx->mpg_data_received = cx->vbi_data_inserted = 0; 621 622 cx->dualwatch_jiffies = jiffies; 622 - cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; 623 + cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); 623 624 cx->search_pack_header = 0; 624 625 break; 625 626 ··· 709 710 s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); 710 711 711 712 /* Call out to the common CX2341x API setup for user controls */ 712 - priv.cx = cx; 713 - priv.s = s; 714 - cx2341x_update(&priv, cx18_api_func, NULL, &cx->params); 713 + cx->cxhdl.priv = s; 714 + cx2341x_handler_setup(&cx->cxhdl); 715 715 716 716 /* 717 717 * When starting a capture and we're set for radio, 718 718 * ensure the video is muted, despite the user control. 719 719 */ 720 - if (!cx->params.video_mute && 720 + if (!cx->cxhdl.video_mute && 721 721 test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) 722 722 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, 723 - (cx->params.video_mute_yuv << 8) | 1); 723 + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); 724 724 } 725 725 726 726 if (atomic_read(&cx->tot_capturing) == 0) { 727 + cx2341x_handler_set_busy(&cx->cxhdl, 1); 727 728 clear_bit(CX18_F_I_EOS, &cx->i_flags); 728 729 cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); 729 730 } ··· 825 826 if (atomic_read(&cx->tot_capturing) > 0) 826 827 return 0; 827 828 829 + cx2341x_handler_set_busy(&cx->cxhdl, 0); 828 830 cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); 829 831 wake_up(&s->waitq); 830 832