diff options
-rw-r--r-- | drivers/media/video/cx18/cx18-av-audio.c | 92 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.c | 175 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.h | 12 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.c | 285 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.h | 7 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 30 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 32 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 24 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 5 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.h | 5 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 16 |
12 files changed, 173 insertions, 512 deletions
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 43d09a24b262..4a24ffb17a7d 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c | |||
@@ -342,17 +342,6 @@ void cx18_av_audio_set_path(struct cx18 *cx) | |||
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 | static void set_volume(struct cx18 *cx, int volume) | 345 | static void set_volume(struct cx18 *cx, int volume) |
357 | { | 346 | { |
358 | /* First convert the volume to msp3400 values (0-127) */ | 347 | /* First convert the volume to msp3400 values (0-127) */ |
@@ -369,52 +358,18 @@ static void set_volume(struct cx18 *cx, int volume) | |||
369 | cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); | 358 | cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); |
370 | } | 359 | } |
371 | 360 | ||
372 | static int get_bass(struct cx18 *cx) | ||
373 | { | ||
374 | /* bass is 49 steps +12dB to -12dB */ | ||
375 | |||
376 | /* check PATH1_EQ_BASS_VOL */ | ||
377 | int bass = cx18_av_read(cx, 0x8d9) & 0x3f; | ||
378 | bass = (((48 - bass) * 0xffff) + 47) / 48; | ||
379 | return bass; | ||
380 | } | ||
381 | |||
382 | static void set_bass(struct cx18 *cx, int bass) | 361 | static void set_bass(struct cx18 *cx, int bass) |
383 | { | 362 | { |
384 | /* PATH1_EQ_BASS_VOL */ | 363 | /* PATH1_EQ_BASS_VOL */ |
385 | cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); | 364 | cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); |
386 | } | 365 | } |
387 | 366 | ||
388 | static int get_treble(struct cx18 *cx) | ||
389 | { | ||
390 | /* treble is 49 steps +12dB to -12dB */ | ||
391 | |||
392 | /* check PATH1_EQ_TREBLE_VOL */ | ||
393 | int treble = cx18_av_read(cx, 0x8db) & 0x3f; | ||
394 | treble = (((48 - treble) * 0xffff) + 47) / 48; | ||
395 | return treble; | ||
396 | } | ||
397 | |||
398 | static void set_treble(struct cx18 *cx, int treble) | 367 | static void set_treble(struct cx18 *cx, int treble) |
399 | { | 368 | { |
400 | /* PATH1_EQ_TREBLE_VOL */ | 369 | /* PATH1_EQ_TREBLE_VOL */ |
401 | cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); | 370 | cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); |
402 | } | 371 | } |
403 | 372 | ||
404 | static int get_balance(struct cx18 *cx) | ||
405 | { | ||
406 | /* balance is 7 bit, 0 to -96dB */ | ||
407 | |||
408 | /* check PATH1_BAL_LEVEL */ | ||
409 | int balance = cx18_av_read(cx, 0x8d5) & 0x7f; | ||
410 | /* check PATH1_BAL_LEFT */ | ||
411 | if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) | ||
412 | balance = 0x80 - balance; | ||
413 | else | ||
414 | balance = 0x80 + balance; | ||
415 | return balance << 8; | ||
416 | } | ||
417 | |||
418 | static void set_balance(struct cx18 *cx, int balance) | 373 | static void set_balance(struct cx18 *cx, int balance) |
419 | { | 374 | { |
420 | int bal = balance >> 8; | 375 | int bal = balance >> 8; |
@@ -431,12 +386,6 @@ static void set_balance(struct cx18 *cx, int balance) | |||
431 | } | 386 | } |
432 | } | 387 | } |
433 | 388 | ||
434 | static int get_mute(struct cx18 *cx) | ||
435 | { | ||
436 | /* check SRC1_MUTE_EN */ | ||
437 | return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; | ||
438 | } | ||
439 | |||
440 | static void set_mute(struct cx18 *cx, int mute) | 389 | static void set_mute(struct cx18 *cx, int mute) |
441 | { | 390 | { |
442 | struct cx18_av_state *state = &cx->av_state; | 391 | struct cx18_av_state *state = &cx->av_state; |
@@ -490,50 +439,33 @@ int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
490 | return retval; | 439 | return retval; |
491 | } | 440 | } |
492 | 441 | ||
493 | int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) | 442 | static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) |
494 | { | 443 | { |
495 | switch (ctrl->id) { | 444 | struct v4l2_subdev *sd = to_sd(ctrl); |
496 | case V4L2_CID_AUDIO_VOLUME: | 445 | struct cx18 *cx = v4l2_get_subdevdata(sd); |
497 | ctrl->value = get_volume(cx); | ||
498 | break; | ||
499 | case V4L2_CID_AUDIO_BASS: | ||
500 | ctrl->value = get_bass(cx); | ||
501 | break; | ||
502 | case V4L2_CID_AUDIO_TREBLE: | ||
503 | ctrl->value = get_treble(cx); | ||
504 | break; | ||
505 | case V4L2_CID_AUDIO_BALANCE: | ||
506 | ctrl->value = get_balance(cx); | ||
507 | break; | ||
508 | case V4L2_CID_AUDIO_MUTE: | ||
509 | ctrl->value = get_mute(cx); | ||
510 | break; | ||
511 | default: | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | return 0; | ||
515 | } | ||
516 | 446 | ||
517 | int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) | ||
518 | { | ||
519 | switch (ctrl->id) { | 447 | switch (ctrl->id) { |
520 | case V4L2_CID_AUDIO_VOLUME: | 448 | case V4L2_CID_AUDIO_VOLUME: |
521 | set_volume(cx, ctrl->value); | 449 | set_volume(cx, ctrl->val); |
522 | break; | 450 | break; |
523 | case V4L2_CID_AUDIO_BASS: | 451 | case V4L2_CID_AUDIO_BASS: |
524 | set_bass(cx, ctrl->value); | 452 | set_bass(cx, ctrl->val); |
525 | break; | 453 | break; |
526 | case V4L2_CID_AUDIO_TREBLE: | 454 | case V4L2_CID_AUDIO_TREBLE: |
527 | set_treble(cx, ctrl->value); | 455 | set_treble(cx, ctrl->val); |
528 | break; | 456 | break; |
529 | case V4L2_CID_AUDIO_BALANCE: | 457 | case V4L2_CID_AUDIO_BALANCE: |
530 | set_balance(cx, ctrl->value); | 458 | set_balance(cx, ctrl->val); |
531 | break; | 459 | break; |
532 | case V4L2_CID_AUDIO_MUTE: | 460 | case V4L2_CID_AUDIO_MUTE: |
533 | set_mute(cx, ctrl->value); | 461 | set_mute(cx, ctrl->val); |
534 | break; | 462 | break; |
535 | default: | 463 | default: |
536 | return -EINVAL; | 464 | return -EINVAL; |
537 | } | 465 | } |
538 | return 0; | 466 | return 0; |
539 | } | 467 | } |
468 | |||
469 | const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { | ||
470 | .s_ctrl = cx18_av_audio_s_ctrl, | ||
471 | }; | ||
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index a41951cab276..f164b7f610a5 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c | |||
@@ -129,6 +129,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) | |||
129 | { | 129 | { |
130 | struct cx18_av_state *state = to_cx18_av_state(sd); | 130 | struct cx18_av_state *state = to_cx18_av_state(sd); |
131 | struct cx18 *cx = v4l2_get_subdevdata(sd); | 131 | struct cx18 *cx = v4l2_get_subdevdata(sd); |
132 | int default_volume; | ||
132 | u32 v; | 133 | u32 v; |
133 | 134 | ||
134 | cx18_av_loadfw(cx); | 135 | cx18_av_loadfw(cx); |
@@ -247,8 +248,23 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) | |||
247 | /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ | 248 | /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ |
248 | /* } */ | 249 | /* } */ |
249 | cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); | 250 | cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); |
250 | state->default_volume = 228 - cx18_av_read(cx, 0x8d4); | 251 | default_volume = cx18_av_read(cx, 0x8d4); |
251 | state->default_volume = ((state->default_volume / 2) + 23) << 9; | 252 | /* |
253 | * Enforce the legacy volume scale mapping limits to avoid | ||
254 | * -ERANGE errors when initializing the volume control | ||
255 | */ | ||
256 | if (default_volume > 228) { | ||
257 | /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ | ||
258 | default_volume = 228; | ||
259 | cx18_av_write(cx, 0x8d4, 228); | ||
260 | } else if (default_volume < 20) { | ||
261 | /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ | ||
262 | default_volume = 20; | ||
263 | cx18_av_write(cx, 0x8d4, 20); | ||
264 | } | ||
265 | default_volume = (((228 - default_volume) >> 1) + 23) << 9; | ||
266 | state->volume->cur.val = state->volume->default_value = default_volume; | ||
267 | v4l2_ctrl_handler_setup(&state->hdl); | ||
252 | } | 268 | } |
253 | 269 | ||
254 | static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) | 270 | static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) |
@@ -901,126 +917,35 @@ static int cx18_av_s_radio(struct v4l2_subdev *sd) | |||
901 | return 0; | 917 | return 0; |
902 | } | 918 | } |
903 | 919 | ||
904 | static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 920 | static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) |
905 | { | 921 | { |
922 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
906 | struct cx18 *cx = v4l2_get_subdevdata(sd); | 923 | struct cx18 *cx = v4l2_get_subdevdata(sd); |
907 | 924 | ||
908 | switch (ctrl->id) { | 925 | switch (ctrl->id) { |
909 | case V4L2_CID_BRIGHTNESS: | 926 | case V4L2_CID_BRIGHTNESS: |
910 | if (ctrl->value < 0 || ctrl->value > 255) { | 927 | cx18_av_write(cx, 0x414, ctrl->val - 128); |
911 | CX18_ERR_DEV(sd, "invalid brightness setting %d\n", | ||
912 | ctrl->value); | ||
913 | return -ERANGE; | ||
914 | } | ||
915 | |||
916 | cx18_av_write(cx, 0x414, ctrl->value - 128); | ||
917 | break; | 928 | break; |
918 | 929 | ||
919 | case V4L2_CID_CONTRAST: | 930 | case V4L2_CID_CONTRAST: |
920 | if (ctrl->value < 0 || ctrl->value > 127) { | 931 | cx18_av_write(cx, 0x415, ctrl->val << 1); |
921 | CX18_ERR_DEV(sd, "invalid contrast setting %d\n", | ||
922 | ctrl->value); | ||
923 | return -ERANGE; | ||
924 | } | ||
925 | |||
926 | cx18_av_write(cx, 0x415, ctrl->value << 1); | ||
927 | break; | 932 | break; |
928 | 933 | ||
929 | case V4L2_CID_SATURATION: | 934 | case V4L2_CID_SATURATION: |
930 | if (ctrl->value < 0 || ctrl->value > 127) { | 935 | cx18_av_write(cx, 0x420, ctrl->val << 1); |
931 | CX18_ERR_DEV(sd, "invalid saturation setting %d\n", | 936 | cx18_av_write(cx, 0x421, ctrl->val << 1); |
932 | ctrl->value); | ||
933 | return -ERANGE; | ||
934 | } | ||
935 | |||
936 | cx18_av_write(cx, 0x420, ctrl->value << 1); | ||
937 | cx18_av_write(cx, 0x421, ctrl->value << 1); | ||
938 | break; | 937 | break; |
939 | 938 | ||
940 | case V4L2_CID_HUE: | 939 | case V4L2_CID_HUE: |
941 | if (ctrl->value < -128 || ctrl->value > 127) { | 940 | cx18_av_write(cx, 0x422, ctrl->val); |
942 | CX18_ERR_DEV(sd, "invalid hue setting %d\n", | ||
943 | ctrl->value); | ||
944 | return -ERANGE; | ||
945 | } | ||
946 | |||
947 | cx18_av_write(cx, 0x422, ctrl->value); | ||
948 | break; | 941 | break; |
949 | 942 | ||
950 | case V4L2_CID_AUDIO_VOLUME: | ||
951 | case V4L2_CID_AUDIO_BASS: | ||
952 | case V4L2_CID_AUDIO_TREBLE: | ||
953 | case V4L2_CID_AUDIO_BALANCE: | ||
954 | case V4L2_CID_AUDIO_MUTE: | ||
955 | return cx18_av_audio_s_ctrl(cx, ctrl); | ||
956 | |||
957 | default: | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
964 | { | ||
965 | struct cx18 *cx = v4l2_get_subdevdata(sd); | ||
966 | |||
967 | switch (ctrl->id) { | ||
968 | case V4L2_CID_BRIGHTNESS: | ||
969 | ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; | ||
970 | break; | ||
971 | case V4L2_CID_CONTRAST: | ||
972 | ctrl->value = cx18_av_read(cx, 0x415) >> 1; | ||
973 | break; | ||
974 | case V4L2_CID_SATURATION: | ||
975 | ctrl->value = cx18_av_read(cx, 0x420) >> 1; | ||
976 | break; | ||
977 | case V4L2_CID_HUE: | ||
978 | ctrl->value = (s8)cx18_av_read(cx, 0x422); | ||
979 | break; | ||
980 | case V4L2_CID_AUDIO_VOLUME: | ||
981 | case V4L2_CID_AUDIO_BASS: | ||
982 | case V4L2_CID_AUDIO_TREBLE: | ||
983 | case V4L2_CID_AUDIO_BALANCE: | ||
984 | case V4L2_CID_AUDIO_MUTE: | ||
985 | return cx18_av_audio_g_ctrl(cx, ctrl); | ||
986 | default: | 943 | default: |
987 | return -EINVAL; | 944 | return -EINVAL; |
988 | } | 945 | } |
989 | return 0; | 946 | return 0; |
990 | } | 947 | } |
991 | 948 | ||
992 | static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
993 | { | ||
994 | struct cx18_av_state *state = to_cx18_av_state(sd); | ||
995 | |||
996 | switch (qc->id) { | ||
997 | case V4L2_CID_BRIGHTNESS: | ||
998 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
999 | case V4L2_CID_CONTRAST: | ||
1000 | case V4L2_CID_SATURATION: | ||
1001 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); | ||
1002 | case V4L2_CID_HUE: | ||
1003 | return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); | ||
1004 | default: | ||
1005 | break; | ||
1006 | } | ||
1007 | |||
1008 | switch (qc->id) { | ||
1009 | case V4L2_CID_AUDIO_VOLUME: | ||
1010 | return v4l2_ctrl_query_fill(qc, 0, 65535, | ||
1011 | 65535 / 100, state->default_volume); | ||
1012 | case V4L2_CID_AUDIO_MUTE: | ||
1013 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1014 | case V4L2_CID_AUDIO_BALANCE: | ||
1015 | case V4L2_CID_AUDIO_BASS: | ||
1016 | case V4L2_CID_AUDIO_TREBLE: | ||
1017 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | ||
1018 | default: | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | return -EINVAL; | ||
1022 | } | ||
1023 | |||
1024 | static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) | 949 | static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) |
1025 | { | 950 | { |
1026 | struct cx18_av_state *state = to_cx18_av_state(sd); | 951 | struct cx18_av_state *state = to_cx18_av_state(sd); |
@@ -1356,14 +1281,22 @@ static int cx18_av_s_register(struct v4l2_subdev *sd, | |||
1356 | } | 1281 | } |
1357 | #endif | 1282 | #endif |
1358 | 1283 | ||
1284 | static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { | ||
1285 | .s_ctrl = cx18_av_s_ctrl, | ||
1286 | }; | ||
1287 | |||
1359 | static const struct v4l2_subdev_core_ops cx18_av_general_ops = { | 1288 | static const struct v4l2_subdev_core_ops cx18_av_general_ops = { |
1360 | .g_chip_ident = cx18_av_g_chip_ident, | 1289 | .g_chip_ident = cx18_av_g_chip_ident, |
1361 | .log_status = cx18_av_log_status, | 1290 | .log_status = cx18_av_log_status, |
1362 | .load_fw = cx18_av_load_fw, | 1291 | .load_fw = cx18_av_load_fw, |
1363 | .reset = cx18_av_reset, | 1292 | .reset = cx18_av_reset, |
1364 | .queryctrl = cx18_av_queryctrl, | 1293 | .g_ctrl = v4l2_subdev_g_ctrl, |
1365 | .g_ctrl = cx18_av_g_ctrl, | 1294 | .s_ctrl = v4l2_subdev_s_ctrl, |
1366 | .s_ctrl = cx18_av_s_ctrl, | 1295 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
1296 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
1297 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
1298 | .queryctrl = v4l2_subdev_queryctrl, | ||
1299 | .querymenu = v4l2_subdev_querymenu, | ||
1367 | .s_std = cx18_av_s_std, | 1300 | .s_std = cx18_av_s_std, |
1368 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1301 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1369 | .g_register = cx18_av_g_register, | 1302 | .g_register = cx18_av_g_register, |
@@ -1427,8 +1360,42 @@ int cx18_av_probe(struct cx18 *cx) | |||
1427 | snprintf(sd->name, sizeof(sd->name), | 1360 | snprintf(sd->name, sizeof(sd->name), |
1428 | "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); | 1361 | "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); |
1429 | sd->grp_id = CX18_HW_418_AV; | 1362 | sd->grp_id = CX18_HW_418_AV; |
1363 | v4l2_ctrl_handler_init(&state->hdl, 9); | ||
1364 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, | ||
1365 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
1366 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, | ||
1367 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
1368 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, | ||
1369 | V4L2_CID_SATURATION, 0, 127, 1, 64); | ||
1370 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, | ||
1371 | V4L2_CID_HUE, -128, 127, 1, 0); | ||
1372 | |||
1373 | state->volume = v4l2_ctrl_new_std(&state->hdl, | ||
1374 | &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, | ||
1375 | 0, 65535, 65535 / 100, 0); | ||
1376 | v4l2_ctrl_new_std(&state->hdl, | ||
1377 | &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, | ||
1378 | 0, 1, 1, 0); | ||
1379 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, | ||
1380 | V4L2_CID_AUDIO_BALANCE, | ||
1381 | 0, 65535, 65535 / 100, 32768); | ||
1382 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, | ||
1383 | V4L2_CID_AUDIO_BASS, | ||
1384 | 0, 65535, 65535 / 100, 32768); | ||
1385 | v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, | ||
1386 | V4L2_CID_AUDIO_TREBLE, | ||
1387 | 0, 65535, 65535 / 100, 32768); | ||
1388 | sd->ctrl_handler = &state->hdl; | ||
1389 | if (state->hdl.error) { | ||
1390 | int err = state->hdl.error; | ||
1391 | |||
1392 | v4l2_ctrl_handler_free(&state->hdl); | ||
1393 | return err; | ||
1394 | } | ||
1430 | err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); | 1395 | err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); |
1431 | if (!err) | 1396 | if (err) |
1397 | v4l2_ctrl_handler_free(&state->hdl); | ||
1398 | else | ||
1432 | cx18_av_init(cx); | 1399 | cx18_av_init(cx); |
1433 | return err; | 1400 | return err; |
1434 | } | 1401 | } |
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index 1956991795e3..188c9c3d2db1 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define _CX18_AV_CORE_H_ | 26 | #define _CX18_AV_CORE_H_ |
27 | 27 | ||
28 | #include <media/v4l2-device.h> | 28 | #include <media/v4l2-device.h> |
29 | #include <media/v4l2-ctrls.h> | ||
29 | 30 | ||
30 | struct cx18; | 31 | struct cx18; |
31 | 32 | ||
@@ -95,13 +96,14 @@ enum cx18_av_audio_input { | |||
95 | 96 | ||
96 | struct cx18_av_state { | 97 | struct cx18_av_state { |
97 | struct v4l2_subdev sd; | 98 | struct v4l2_subdev sd; |
99 | struct v4l2_ctrl_handler hdl; | ||
100 | struct v4l2_ctrl *volume; | ||
98 | int radio; | 101 | int radio; |
99 | v4l2_std_id std; | 102 | v4l2_std_id std; |
100 | enum cx18_av_video_input vid_input; | 103 | enum cx18_av_video_input vid_input; |
101 | enum cx18_av_audio_input aud_input; | 104 | enum cx18_av_audio_input aud_input; |
102 | u32 audclk_freq; | 105 | u32 audclk_freq; |
103 | int audmode; | 106 | int audmode; |
104 | int default_volume; | ||
105 | u32 id; | 107 | u32 id; |
106 | u32 rev; | 108 | u32 rev; |
107 | int is_initialized; | 109 | int is_initialized; |
@@ -347,6 +349,11 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd) | |||
347 | return container_of(sd, struct cx18_av_state, sd); | 349 | return container_of(sd, struct cx18_av_state, sd); |
348 | } | 350 | } |
349 | 351 | ||
352 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
353 | { | ||
354 | return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; | ||
355 | } | ||
356 | |||
350 | /* ----------------------------------------------------------------------- */ | 357 | /* ----------------------------------------------------------------------- */ |
351 | /* cx18_av-core.c */ | 358 | /* cx18_av-core.c */ |
352 | int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); | 359 | int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); |
@@ -369,10 +376,9 @@ int cx18_av_loadfw(struct cx18 *cx); | |||
369 | 376 | ||
370 | /* ----------------------------------------------------------------------- */ | 377 | /* ----------------------------------------------------------------------- */ |
371 | /* cx18_av-audio.c */ | 378 | /* cx18_av-audio.c */ |
372 | int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); | ||
373 | int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); | ||
374 | int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); | 379 | int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); |
375 | void cx18_av_audio_set_path(struct cx18 *cx); | 380 | void cx18_av_audio_set_path(struct cx18 *cx); |
381 | extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; | ||
376 | 382 | ||
377 | /* ----------------------------------------------------------------------- */ | 383 | /* ----------------------------------------------------------------------- */ |
378 | /* cx18_av-vbi.c */ | 384 | /* cx18_av-vbi.c */ |
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 97d7b7e100a3..282a3d29fdaa 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c | |||
@@ -30,152 +30,11 @@ | |||
30 | #include "cx18-mailbox.h" | 30 | #include "cx18-mailbox.h" |
31 | #include "cx18-controls.h" | 31 | #include "cx18-controls.h" |
32 | 32 | ||
33 | /* Must be sorted from low to high control ID! */ | 33 | static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) |
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) | ||
56 | { | ||
57 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
58 | const char *name; | ||
59 | |||
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 | { | 34 | { |
98 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | 35 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
99 | struct v4l2_queryctrl qctrl; | 36 | int type = cxhdl->stream_type->val; |
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 | 37 | ||
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 | if (atomic_read(&cx->ana_capturing) > 0) | 38 | if (atomic_read(&cx->ana_capturing) > 0) |
180 | return -EBUSY; | 39 | return -EBUSY; |
181 | 40 | ||
@@ -230,121 +89,43 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, | |||
230 | return 0; | 89 | return 0; |
231 | } | 90 | } |
232 | 91 | ||
233 | int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 92 | static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) |
234 | { | 93 | { |
235 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | 94 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
236 | struct v4l2_control ctrl; | 95 | int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; |
237 | 96 | struct v4l2_mbus_framefmt fmt; | |
238 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | 97 | |
239 | int i; | 98 | /* fix videodecoder resolution */ |
240 | int err = 0; | 99 | fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); |
241 | 100 | fmt.height = cxhdl->height; | |
242 | for (i = 0; i < c->count; i++) { | 101 | fmt.code = V4L2_MBUS_FMT_FIXED; |
243 | ctrl.id = c->controls[i].id; | 102 | v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); |
244 | ctrl.value = c->controls[i].value; | 103 | return 0; |
245 | err = cx18_g_ctrl(cx, &ctrl); | ||
246 | c->controls[i].value = ctrl.value; | ||
247 | if (err) { | ||
248 | c->error_idx = i; | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | return err; | ||
253 | } | ||
254 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
255 | return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS); | ||
256 | return -EINVAL; | ||
257 | } | 104 | } |
258 | 105 | ||
259 | int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 106 | static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) |
260 | { | 107 | { |
261 | struct cx18_open_id *id = fh; | 108 | static const u32 freqs[3] = { 44100, 48000, 32000 }; |
262 | struct cx18 *cx = id->cx; | 109 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
263 | int ret; | ||
264 | struct v4l2_control ctrl; | ||
265 | |||
266 | ret = v4l2_prio_check(&cx->prio, id->prio); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
271 | int i; | ||
272 | int err = 0; | ||
273 | |||
274 | for (i = 0; i < c->count; i++) { | ||
275 | ctrl.id = c->controls[i].id; | ||
276 | ctrl.value = c->controls[i].value; | ||
277 | err = cx18_s_ctrl(cx, &ctrl); | ||
278 | c->controls[i].value = ctrl.value; | ||
279 | if (err) { | ||
280 | c->error_idx = i; | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | return err; | ||
285 | } | ||
286 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
287 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
288 | struct cx18_api_func_private priv; | ||
289 | struct cx2341x_mpeg_params p = cx->params; | ||
290 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), | ||
291 | c, VIDIOC_S_EXT_CTRLS); | ||
292 | unsigned int idx; | ||
293 | |||
294 | if (err) | ||
295 | return err; | ||
296 | 110 | ||
297 | if (p.video_encoding != cx->params.video_encoding) { | 111 | /* The audio clock of the digitizer must match the codec sample |
298 | int is_mpeg1 = p.video_encoding == | 112 | rate otherwise you get some very strange effects. */ |
299 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | 113 | if (idx < ARRAY_SIZE(freqs)) |
300 | struct v4l2_mbus_framefmt fmt; | 114 | cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); |
301 | 115 | return 0; | |
302 | /* fix videodecoder resolution */ | ||
303 | fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1); | ||
304 | fmt.height = cx->params.height; | ||
305 | fmt.code = V4L2_MBUS_FMT_FIXED; | ||
306 | v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); | ||
307 | } | ||
308 | priv.cx = cx; | ||
309 | priv.s = &cx->streams[id->type]; | ||
310 | err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p); | ||
311 | if (!err && | ||
312 | (cx->params.stream_vbi_fmt != p.stream_vbi_fmt || | ||
313 | cx->params.stream_type != p.stream_type)) | ||
314 | err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt, | ||
315 | p.stream_type); | ||
316 | cx->params = p; | ||
317 | cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
318 | idx = p.audio_properties & 0x03; | ||
319 | /* The audio clock of the digitizer must match the codec sample | ||
320 | rate otherwise you get some very strange effects. */ | ||
321 | if (idx < ARRAY_SIZE(freqs)) | ||
322 | cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); | ||
323 | return err; | ||
324 | } | ||
325 | return -EINVAL; | ||
326 | } | 116 | } |
327 | 117 | ||
328 | int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) | 118 | static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) |
329 | { | 119 | { |
330 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | 120 | struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); |
331 | 121 | ||
332 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | 122 | cx->dualwatch_stereo_mode = val; |
333 | int i; | 123 | return 0; |
334 | int err = 0; | ||
335 | |||
336 | for (i = 0; i < c->count; i++) { | ||
337 | err = cx18_try_ctrl(file, fh, &c->controls[i]); | ||
338 | if (err) { | ||
339 | c->error_idx = i; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | return err; | ||
344 | } | ||
345 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
346 | return cx2341x_ext_ctrls(&cx->params, | ||
347 | atomic_read(&cx->ana_capturing), | ||
348 | c, VIDIOC_TRY_EXT_CTRLS); | ||
349 | return -EINVAL; | ||
350 | } | 124 | } |
125 | |||
126 | struct cx2341x_handler_ops cx18_cxhdl_ops = { | ||
127 | .s_audio_mode = cx18_s_audio_mode, | ||
128 | .s_audio_sampling_freq = cx18_s_audio_sampling_freq, | ||
129 | .s_video_encoding = cx18_s_video_encoding, | ||
130 | .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, | ||
131 | }; | ||
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h index e46323700b81..cb5dfc7b2054 100644 --- a/drivers/media/video/cx18/cx18-controls.h +++ b/drivers/media/video/cx18/cx18-controls.h | |||
@@ -21,9 +21,4 @@ | |||
21 | * 02111-1307 USA | 21 | * 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); | 24 | extern struct cx2341x_handler_ops cx18_cxhdl_ops; |
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); | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index b1c3cbd92743..b988ec62af58 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "cx18-scb.h" | 36 | #include "cx18-scb.h" |
37 | #include "cx18-mailbox.h" | 37 | #include "cx18-mailbox.h" |
38 | #include "cx18-ioctl.h" | 38 | #include "cx18-ioctl.h" |
39 | #include "cx18-controls.h" | ||
39 | #include "tuner-xc2028.h" | 40 | #include "tuner-xc2028.h" |
40 | 41 | ||
41 | #include <media/tveeprom.h> | 42 | #include <media/tveeprom.h> |
@@ -729,15 +730,21 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) | |||
729 | cx->open_id = 1; | 730 | cx->open_id = 1; |
730 | 731 | ||
731 | /* Initial settings */ | 732 | /* Initial settings */ |
732 | cx2341x_fill_defaults(&cx->params); | 733 | cx->cxhdl.port = CX2341X_PORT_MEMORY; |
733 | cx->temporal_strength = cx->params.video_temporal_filter; | 734 | cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; |
734 | cx->spatial_strength = cx->params.video_spatial_filter; | 735 | cx->cxhdl.ops = &cx18_cxhdl_ops; |
735 | cx->filter_mode = cx->params.video_spatial_filter_mode | | 736 | cx->cxhdl.func = cx18_api_func; |
736 | (cx->params.video_temporal_filter_mode << 1) | | 737 | ret = cx2341x_handler_init(&cx->cxhdl, 50); |
737 | (cx->params.video_median_filter_type << 2); | 738 | if (ret) |
738 | cx->params.port = CX2341X_PORT_MEMORY; | 739 | return ret; |
739 | cx->params.capabilities = | 740 | cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; |
740 | CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; | 741 | |
742 | cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; | ||
743 | cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; | ||
744 | cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | | ||
745 | (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | | ||
746 | (cx->cxhdl.video_median_filter_type->cur.val << 2); | ||
747 | |||
741 | init_waitqueue_head(&cx->cap_w); | 748 | init_waitqueue_head(&cx->cap_w); |
742 | init_waitqueue_head(&cx->mb_apu_waitq); | 749 | init_waitqueue_head(&cx->mb_apu_waitq); |
743 | init_waitqueue_head(&cx->mb_cpu_waitq); | 750 | init_waitqueue_head(&cx->mb_cpu_waitq); |
@@ -1049,7 +1056,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1049 | else | 1056 | else |
1050 | cx->is_50hz = 1; | 1057 | cx->is_50hz = 1; |
1051 | 1058 | ||
1052 | cx->params.video_gop_size = cx->is_60hz ? 15 : 12; | 1059 | cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); |
1053 | 1060 | ||
1054 | if (cx->options.radio > 0) | 1061 | if (cx->options.radio > 0) |
1055 | cx->v4l2_cap |= V4L2_CAP_RADIO; | 1062 | cx->v4l2_cap |= V4L2_CAP_RADIO; |
@@ -1095,7 +1102,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1095 | 1102 | ||
1096 | /* Load cx18 submodules (cx18-alsa) */ | 1103 | /* Load cx18 submodules (cx18-alsa) */ |
1097 | request_modules(cx); | 1104 | request_modules(cx); |
1098 | |||
1099 | return 0; | 1105 | return 0; |
1100 | 1106 | ||
1101 | free_streams: | 1107 | free_streams: |
@@ -1278,6 +1284,8 @@ static void cx18_remove(struct pci_dev *pci_dev) | |||
1278 | for (i = 0; i < CX18_VBI_FRAMES; i++) | 1284 | for (i = 0; i < CX18_VBI_FRAMES; i++) |
1279 | kfree(cx->vbi.sliced_mpeg_data[i]); | 1285 | kfree(cx->vbi.sliced_mpeg_data[i]); |
1280 | 1286 | ||
1287 | v4l2_ctrl_handler_free(&cx->av_state.hdl); | ||
1288 | |||
1281 | CX18_INFO("Removed %s\n", cx->card_name); | 1289 | CX18_INFO("Removed %s\n", cx->card_name); |
1282 | 1290 | ||
1283 | v4l2_device_unregister(v4l2_dev); | 1291 | v4l2_device_unregister(v4l2_dev); |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index f736679d2517..de2457741e26 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -565,7 +565,7 @@ struct cx18 { | |||
565 | struct cx18_av_state av_state; | 565 | struct cx18_av_state av_state; |
566 | 566 | ||
567 | /* codec settings */ | 567 | /* codec settings */ |
568 | struct cx2341x_mpeg_params params; | 568 | struct cx2341x_handler cxhdl; |
569 | u32 filter_mode; | 569 | u32 filter_mode; |
570 | u32 temporal_strength; | 570 | u32 temporal_strength; |
571 | u32 spatial_strength; | 571 | u32 spatial_strength; |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 9f23b90732f2..98ef33e4326a 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -160,13 +160,10 @@ EXPORT_SYMBOL(cx18_release_stream); | |||
160 | static void cx18_dualwatch(struct cx18 *cx) | 160 | static void cx18_dualwatch(struct cx18 *cx) |
161 | { | 161 | { |
162 | struct v4l2_tuner vt; | 162 | struct v4l2_tuner vt; |
163 | u32 new_bitmap; | ||
164 | u32 new_stereo_mode; | 163 | u32 new_stereo_mode; |
165 | const u32 stereo_mask = 0x0300; | ||
166 | const u32 dual = 0x0200; | 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 | memset(&vt, 0, sizeof(vt)); | 167 | memset(&vt, 0, sizeof(vt)); |
171 | cx18_call_all(cx, tuner, g_tuner, &vt); | 168 | cx18_call_all(cx, tuner, g_tuner, &vt); |
172 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && | 169 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && |
@@ -176,25 +173,10 @@ static void cx18_dualwatch(struct cx18 *cx) | |||
176 | if (new_stereo_mode == cx->dualwatch_stereo_mode) | 173 | if (new_stereo_mode == cx->dualwatch_stereo_mode) |
177 | return; | 174 | return; |
178 | 175 | ||
179 | new_bitmap = new_stereo_mode | 176 | CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", |
180 | | (cx->params.audio_properties & ~stereo_mask); | 177 | cx->dualwatch_stereo_mode, new_stereo_mode); |
181 | 178 | if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) | |
182 | CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. " | 179 | CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); |
183 | "new audio_bitmask=0x%ux\n", | ||
184 | cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); | ||
185 | |||
186 | h = cx18_find_handle(cx); | ||
187 | if (h == CX18_INVALID_TASK_HANDLE) { | ||
188 | CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n"); | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | if (cx18_vapi(cx, | ||
193 | CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) { | ||
194 | cx->dualwatch_stereo_mode = new_stereo_mode; | ||
195 | return; | ||
196 | } | ||
197 | CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); | ||
198 | } | 180 | } |
199 | 181 | ||
200 | 182 | ||
@@ -724,8 +706,8 @@ int cx18_v4l2_close(struct file *filp) | |||
724 | if (atomic_read(&cx->ana_capturing) > 0) { | 706 | if (atomic_read(&cx->ana_capturing) > 0) { |
725 | /* Undo video mute */ | 707 | /* Undo video mute */ |
726 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, | 708 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, |
727 | cx->params.video_mute | | 709 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | |
728 | (cx->params.video_mute_yuv << 8)); | 710 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); |
729 | } | 711 | } |
730 | /* Done! Unmute and continue. */ | 712 | /* Done! Unmute and continue. */ |
731 | cx18_unmute(cx); | 713 | cx18_unmute(cx); |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 7150195740dc..36b018c943e5 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -152,8 +152,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
152 | struct cx18 *cx = id->cx; | 152 | struct cx18 *cx = id->cx; |
153 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | 153 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; |
154 | 154 | ||
155 | pixfmt->width = cx->params.width; | 155 | pixfmt->width = cx->cxhdl.width; |
156 | pixfmt->height = cx->params.height; | 156 | pixfmt->height = cx->cxhdl.height; |
157 | pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | 157 | pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
158 | pixfmt->field = V4L2_FIELD_INTERLACED; | 158 | pixfmt->field = V4L2_FIELD_INTERLACED; |
159 | pixfmt->priv = 0; | 159 | pixfmt->priv = 0; |
@@ -287,14 +287,14 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
287 | w = fmt->fmt.pix.width; | 287 | w = fmt->fmt.pix.width; |
288 | h = fmt->fmt.pix.height; | 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 | return 0; | 291 | return 0; |
292 | 292 | ||
293 | if (atomic_read(&cx->ana_capturing) > 0) | 293 | if (atomic_read(&cx->ana_capturing) > 0) |
294 | return -EBUSY; | 294 | return -EBUSY; |
295 | 295 | ||
296 | mbus_fmt.width = cx->params.width = w; | 296 | mbus_fmt.width = cx->cxhdl.width = w; |
297 | mbus_fmt.height = cx->params.height = h; | 297 | mbus_fmt.height = cx->cxhdl.height = h; |
298 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; | 298 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; |
299 | v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); | 299 | v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); |
300 | return cx18_g_fmt_vid_cap(file, fh, fmt); | 300 | return cx18_g_fmt_vid_cap(file, fh, fmt); |
@@ -696,9 +696,10 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) | |||
696 | 696 | ||
697 | cx->std = *std; | 697 | cx->std = *std; |
698 | cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; | 698 | cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; |
699 | cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; | 699 | cx->is_50hz = !cx->is_60hz; |
700 | cx->params.width = 720; | 700 | cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); |
701 | cx->params.height = cx->is_50hz ? 576 : 480; | 701 | cx->cxhdl.width = 720; |
702 | cx->cxhdl.height = cx->is_50hz ? 576 : 480; | ||
702 | cx->vbi.count = cx->is_50hz ? 18 : 12; | 703 | cx->vbi.count = cx->is_50hz ? 18 : 12; |
703 | cx->vbi.start[0] = cx->is_50hz ? 6 : 10; | 704 | cx->vbi.start[0] = cx->is_50hz ? 6 : 10; |
704 | cx->vbi.start[1] = cx->is_50hz ? 318 : 273; | 705 | cx->vbi.start[1] = cx->is_50hz ? 318 : 273; |
@@ -1035,7 +1036,7 @@ static int cx18_log_status(struct file *file, void *fh) | |||
1035 | mutex_unlock(&cx->gpio_lock); | 1036 | mutex_unlock(&cx->gpio_lock); |
1036 | CX18_INFO("Tuner: %s\n", | 1037 | CX18_INFO("Tuner: %s\n", |
1037 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); | 1038 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); |
1038 | cx2341x_log_status(&cx->params, cx->v4l2_dev.name); | 1039 | v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); |
1039 | CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); | 1040 | CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); |
1040 | for (i = 0; i < CX18_MAX_STREAMS; i++) { | 1041 | for (i = 0; i < CX18_MAX_STREAMS; i++) { |
1041 | struct cx18_stream *s = &cx->streams[i]; | 1042 | struct cx18_stream *s = &cx->streams[i]; |
@@ -1136,11 +1137,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { | |||
1136 | .vidioc_s_register = cx18_s_register, | 1137 | .vidioc_s_register = cx18_s_register, |
1137 | #endif | 1138 | #endif |
1138 | .vidioc_default = cx18_default, | 1139 | .vidioc_default = cx18_default, |
1139 | .vidioc_queryctrl = cx18_queryctrl, | ||
1140 | .vidioc_querymenu = cx18_querymenu, | ||
1141 | .vidioc_g_ext_ctrls = cx18_g_ext_ctrls, | ||
1142 | .vidioc_s_ext_ctrls = cx18_s_ext_ctrls, | ||
1143 | .vidioc_try_ext_ctrls = cx18_try_ext_ctrls, | ||
1144 | }; | 1140 | }; |
1145 | 1141 | ||
1146 | void cx18_set_funcs(struct video_device *vdev) | 1142 | void cx18_set_funcs(struct video_device *vdev) |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index c545f3beef78..9605d54bd083 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -716,9 +716,8 @@ static int cx18_set_filter_param(struct cx18_stream *s) | |||
716 | int cx18_api_func(void *priv, u32 cmd, int in, int out, | 716 | int cx18_api_func(void *priv, u32 cmd, int in, int out, |
717 | u32 data[CX2341X_MBOX_MAX_DATA]) | 717 | u32 data[CX2341X_MBOX_MAX_DATA]) |
718 | { | 718 | { |
719 | struct cx18_api_func_private *api_priv = priv; | 719 | struct cx18_stream *s = priv; |
720 | struct cx18 *cx = api_priv->cx; | 720 | struct cx18 *cx = s->cx; |
721 | struct cx18_stream *s = api_priv->s; | ||
722 | 721 | ||
723 | switch (cmd) { | 722 | switch (cmd) { |
724 | case CX2341X_ENC_SET_OUTPUT_PORT: | 723 | case CX2341X_ENC_SET_OUTPUT_PORT: |
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 077952fcbcca..05fe6bdbe062 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h | |||
@@ -81,11 +81,6 @@ struct cx18_mailbox { | |||
81 | 81 | ||
82 | struct cx18_stream; | 82 | struct cx18_stream; |
83 | 83 | ||
84 | struct cx18_api_func_private { | ||
85 | struct cx18 *cx; | ||
86 | struct cx18_stream *s; | ||
87 | }; | ||
88 | |||
89 | int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); | 84 | int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); |
90 | int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, | 85 | int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, |
91 | int args, ...); | 86 | int args, ...); |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 94f5d7967c5c..2d248560770e 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -572,7 +572,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) | |||
572 | * Set the MDL size to the exact size needed for one frame. | 572 | * Set the MDL size to the exact size needed for one frame. |
573 | * Use enough buffers per MDL to cover the MDL size | 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 | s->bufs_per_mdl = s->mdl_size / s->buf_size; | 576 | s->bufs_per_mdl = s->mdl_size / s->buf_size; |
577 | if (s->mdl_size % s->buf_size) | 577 | if (s->mdl_size % s->buf_size) |
578 | s->bufs_per_mdl++; | 578 | s->bufs_per_mdl++; |
@@ -607,7 +607,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
607 | u32 data[MAX_MB_ARGUMENTS]; | 607 | u32 data[MAX_MB_ARGUMENTS]; |
608 | struct cx18 *cx = s->cx; | 608 | struct cx18 *cx = s->cx; |
609 | int captype = 0; | 609 | int captype = 0; |
610 | struct cx18_api_func_private priv; | ||
611 | struct cx18_stream *s_idx; | 610 | struct cx18_stream *s_idx; |
612 | 611 | ||
613 | if (!cx18_stream_enabled(s)) | 612 | if (!cx18_stream_enabled(s)) |
@@ -620,7 +619,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
620 | captype = CAPTURE_CHANNEL_TYPE_MPEG; | 619 | captype = CAPTURE_CHANNEL_TYPE_MPEG; |
621 | cx->mpg_data_received = cx->vbi_data_inserted = 0; | 620 | cx->mpg_data_received = cx->vbi_data_inserted = 0; |
622 | cx->dualwatch_jiffies = jiffies; | 621 | cx->dualwatch_jiffies = jiffies; |
623 | cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; | 622 | cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); |
624 | cx->search_pack_header = 0; | 623 | cx->search_pack_header = 0; |
625 | break; | 624 | break; |
626 | 625 | ||
@@ -710,21 +709,21 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
710 | s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); | 709 | s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); |
711 | 710 | ||
712 | /* Call out to the common CX2341x API setup for user controls */ | 711 | /* Call out to the common CX2341x API setup for user controls */ |
713 | priv.cx = cx; | 712 | cx->cxhdl.priv = s; |
714 | priv.s = s; | 713 | cx2341x_handler_setup(&cx->cxhdl); |
715 | cx2341x_update(&priv, cx18_api_func, NULL, &cx->params); | ||
716 | 714 | ||
717 | /* | 715 | /* |
718 | * When starting a capture and we're set for radio, | 716 | * When starting a capture and we're set for radio, |
719 | * ensure the video is muted, despite the user control. | 717 | * ensure the video is muted, despite the user control. |
720 | */ | 718 | */ |
721 | if (!cx->params.video_mute && | 719 | if (!cx->cxhdl.video_mute && |
722 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) | 720 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) |
723 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, | 721 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, |
724 | (cx->params.video_mute_yuv << 8) | 1); | 722 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); |
725 | } | 723 | } |
726 | 724 | ||
727 | if (atomic_read(&cx->tot_capturing) == 0) { | 725 | if (atomic_read(&cx->tot_capturing) == 0) { |
726 | cx2341x_handler_set_busy(&cx->cxhdl, 1); | ||
728 | clear_bit(CX18_F_I_EOS, &cx->i_flags); | 727 | clear_bit(CX18_F_I_EOS, &cx->i_flags); |
729 | cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); | 728 | cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); |
730 | } | 729 | } |
@@ -826,6 +825,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) | |||
826 | if (atomic_read(&cx->tot_capturing) > 0) | 825 | if (atomic_read(&cx->tot_capturing) > 0) |
827 | return 0; | 826 | return 0; |
828 | 827 | ||
828 | cx2341x_handler_set_busy(&cx->cxhdl, 0); | ||
829 | cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); | 829 | cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); |
830 | wake_up(&s->waitq); | 830 | wake_up(&s->waitq); |
831 | 831 | ||