aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2010-12-31 08:22:52 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:31:49 -0400
commita75b9be1c2fb52dee765d35f29031dd788d522eb (patch)
treea4f4616c01d3fe7628640accc54cd356cbf9f609
parent34a078da8e20ca40a09bfa635ff2c4e2c4b648b1 (diff)
[media] cx18: Use the control framework
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c92
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c175
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h12
-rw-r--r--drivers/media/video/cx18/cx18-controls.c285
-rw-r--r--drivers/media/video/cx18/cx18-controls.h7
-rw-r--r--drivers/media/video/cx18/cx18-driver.c30
-rw-r--r--drivers/media/video/cx18/cx18-driver.h2
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c32
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c24
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c5
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h5
-rw-r--r--drivers/media/video/cx18/cx18-streams.c16
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
345static 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
356static void set_volume(struct cx18 *cx, int volume) 345static 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
372static 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
382static void set_bass(struct cx18 *cx, int bass) 361static 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
388static 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
398static void set_treble(struct cx18 *cx, int treble) 367static 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
404static 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
418static void set_balance(struct cx18 *cx, int balance) 373static 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
434static int get_mute(struct cx18 *cx)
435{
436 /* check SRC1_MUTE_EN */
437 return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
438}
439
440static void set_mute(struct cx18 *cx, int mute) 389static 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
493int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) 442static 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
517int 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
469const 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
254static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) 270static 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
904static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 920static 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
963static 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
992static 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
1024static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) 949static 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
1284static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
1285 .s_ctrl = cx18_av_s_ctrl,
1286};
1287
1359static const struct v4l2_subdev_core_ops cx18_av_general_ops = { 1288static 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
30struct cx18; 31struct cx18;
31 32
@@ -95,13 +96,14 @@ enum cx18_av_audio_input {
95 96
96struct cx18_av_state { 97struct 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
352static 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 */
352int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); 359int 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 */
372int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
373int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
374int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); 379int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
375void cx18_av_audio_set_path(struct cx18 *cx); 380void cx18_av_audio_set_path(struct cx18 *cx);
381extern 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! */ 33static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
34static 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
49static const u32 *ctrl_classes[] = {
50 user_ctrls,
51 cx2341x_mpeg_ctrls,
52 NULL
53};
54
55int 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
96int 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
107static 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
123static 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
148static 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
173static 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
233int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 92static 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
259int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 106static 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
328int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) 118static 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
126struct 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
24int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); 24extern struct cx2341x_handler_ops cx18_cxhdl_ops;
25int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
26int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
27int cx18_try_ext_ctrls(struct file *file, void *fh,
28 struct v4l2_ext_controls *a);
29int 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
1101free_streams: 1107free_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);
160static void cx18_dualwatch(struct cx18 *cx) 160static 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
1146void cx18_set_funcs(struct video_device *vdev) 1142void 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)
716int cx18_api_func(void *priv, u32 cmd, int in, int out, 716int 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
82struct cx18_stream; 82struct cx18_stream;
83 83
84struct cx18_api_func_private {
85 struct cx18 *cx;
86 struct cx18_stream *s;
87};
88
89int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); 84int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
90int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, 85int 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