diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-03-25 04:38:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-25 07:42:22 -0400 |
commit | c813bd3c8dce3564166e2c4f839fd36df7b0ba5d (patch) | |
tree | d9efef5267195dbc865ee234cfc4bad3fd3bd514 | |
parent | d9ebd623c1912f8f02fc71d4e645973f51f83362 (diff) |
[media] solo6x10: add control framework
Note that the MOTION_THRESHOLD functionality has been temporarily reduced:
only the global threshold can be set, not the per-block. This will be
addressed in a later patch: controls are not the proper way to do this.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/media/solo6x10/solo6x10.h | 15 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/tw28.c | 12 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/tw28.h | 1 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/v4l2-enc.c | 350 | ||||
-rw-r--r-- | drivers/staging/media/solo6x10/v4l2.c | 83 |
5 files changed, 132 insertions, 329 deletions
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 6501cb9afba3..4035c072fb47 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | #include <media/v4l2-dev.h> | 39 | #include <media/v4l2-dev.h> |
40 | #include <media/v4l2-device.h> | 40 | #include <media/v4l2-device.h> |
41 | #include <media/v4l2-ctrls.h> | ||
41 | #include <media/videobuf-core.h> | 42 | #include <media/videobuf-core.h> |
42 | 43 | ||
43 | #include "registers.h" | 44 | #include "registers.h" |
@@ -100,12 +101,12 @@ | |||
100 | #define V4L2_BUF_FLAG_MOTION_ON 0x0400 | 101 | #define V4L2_BUF_FLAG_MOTION_ON 0x0400 |
101 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 | 102 | #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 |
102 | #endif | 103 | #endif |
103 | #ifndef V4L2_CID_MOTION_ENABLE | 104 | |
104 | #define PRIVATE_CIDS | 105 | #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) |
105 | #define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0) | 106 | #define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0) |
106 | #define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1) | 107 | #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) |
107 | #define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2) | 108 | #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) |
108 | #endif | 109 | #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) |
109 | 110 | ||
110 | enum SOLO_I2C_STATE { | 111 | enum SOLO_I2C_STATE { |
111 | IIC_STATE_IDLE, | 112 | IIC_STATE_IDLE, |
@@ -137,6 +138,7 @@ struct solo_p2m_dev { | |||
137 | struct solo_enc_dev { | 138 | struct solo_enc_dev { |
138 | struct solo_dev *solo_dev; | 139 | struct solo_dev *solo_dev; |
139 | /* V4L2 Items */ | 140 | /* V4L2 Items */ |
141 | struct v4l2_ctrl_handler hdl; | ||
140 | struct video_device *vfd; | 142 | struct video_device *vfd; |
141 | /* General accounting */ | 143 | /* General accounting */ |
142 | struct mutex enable_lock; | 144 | struct mutex enable_lock; |
@@ -207,6 +209,7 @@ struct solo_dev { | |||
207 | unsigned int frame_blank; | 209 | unsigned int frame_blank; |
208 | u8 cur_disp_ch; | 210 | u8 cur_disp_ch; |
209 | wait_queue_head_t disp_thread_wait; | 211 | wait_queue_head_t disp_thread_wait; |
212 | struct v4l2_ctrl_handler disp_hdl; | ||
210 | 213 | ||
211 | /* V4L2 Encoder items */ | 214 | /* V4L2 Encoder items */ |
212 | struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS]; | 215 | struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS]; |
diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index 365ab1012881..69baf82a3ac4 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c | |||
@@ -660,6 +660,11 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) | |||
660 | } | 660 | } |
661 | #endif | 661 | #endif |
662 | 662 | ||
663 | bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch) | ||
664 | { | ||
665 | return is_tw286x(solo_dev, ch / 4); | ||
666 | } | ||
667 | |||
663 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, | 668 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, |
664 | s32 val) | 669 | s32 val) |
665 | { | 670 | { |
@@ -676,8 +681,6 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, | |||
676 | switch (ctrl) { | 681 | switch (ctrl) { |
677 | case V4L2_CID_SHARPNESS: | 682 | case V4L2_CID_SHARPNESS: |
678 | /* Only 286x has sharpness */ | 683 | /* Only 286x has sharpness */ |
679 | if (val > 0x0f || val < 0) | ||
680 | return -ERANGE; | ||
681 | if (is_tw286x(solo_dev, chip_num)) { | 684 | if (is_tw286x(solo_dev, chip_num)) { |
682 | u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, | 685 | u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, |
683 | TW_CHIP_OFFSET_ADDR(chip_num), | 686 | TW_CHIP_OFFSET_ADDR(chip_num), |
@@ -687,8 +690,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, | |||
687 | solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, | 690 | solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, |
688 | TW_CHIP_OFFSET_ADDR(chip_num), | 691 | TW_CHIP_OFFSET_ADDR(chip_num), |
689 | TW286x_SHARPNESS(chip_num), v); | 692 | TW286x_SHARPNESS(chip_num), v); |
690 | } else if (val != 0) | 693 | } else { |
691 | return -ERANGE; | 694 | return -EINVAL; |
695 | } | ||
692 | break; | 696 | break; |
693 | 697 | ||
694 | case V4L2_CID_HUE: | 698 | case V4L2_CID_HUE: |
diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h index a03b429d44d4..1a02c87d4cf0 100644 --- a/drivers/staging/media/solo6x10/tw28.h +++ b/drivers/staging/media/solo6x10/tw28.h | |||
@@ -55,6 +55,7 @@ int solo_tw28_init(struct solo_dev *solo_dev); | |||
55 | 55 | ||
56 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); | 56 | int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); |
57 | int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); | 57 | int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); |
58 | bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch); | ||
58 | 59 | ||
59 | u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); | 60 | u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); |
60 | void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); | 61 | void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); |
diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index d085e386e087..8296d8d9dfae 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c | |||
@@ -119,41 +119,6 @@ static unsigned char vop_6110_pal_cif[] = { | |||
119 | 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, | 119 | 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | |||
123 | static const u32 solo_user_ctrls[] = { | ||
124 | V4L2_CID_BRIGHTNESS, | ||
125 | V4L2_CID_CONTRAST, | ||
126 | V4L2_CID_SATURATION, | ||
127 | V4L2_CID_HUE, | ||
128 | V4L2_CID_SHARPNESS, | ||
129 | 0 | ||
130 | }; | ||
131 | |||
132 | static const u32 solo_mpeg_ctrls[] = { | ||
133 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
134 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
135 | 0 | ||
136 | }; | ||
137 | |||
138 | static const u32 solo_private_ctrls[] = { | ||
139 | V4L2_CID_MOTION_ENABLE, | ||
140 | V4L2_CID_MOTION_THRESHOLD, | ||
141 | 0 | ||
142 | }; | ||
143 | |||
144 | static const u32 solo_fmtx_ctrls[] = { | ||
145 | V4L2_CID_RDS_TX_RADIO_TEXT, | ||
146 | 0 | ||
147 | }; | ||
148 | |||
149 | static const u32 *solo_ctrl_classes[] = { | ||
150 | solo_user_ctrls, | ||
151 | solo_mpeg_ctrls, | ||
152 | solo_fmtx_ctrls, | ||
153 | solo_private_ctrls, | ||
154 | NULL | ||
155 | }; | ||
156 | |||
157 | struct vop_header { | 122 | struct vop_header { |
158 | /* VE_STATUS0 */ | 123 | /* VE_STATUS0 */ |
159 | u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, | 124 | u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, |
@@ -1341,128 +1306,13 @@ static int solo_s_parm(struct file *file, void *priv, | |||
1341 | return 0; | 1306 | return 0; |
1342 | } | 1307 | } |
1343 | 1308 | ||
1344 | static int solo_queryctrl(struct file *file, void *priv, | 1309 | static int solo_s_ctrl(struct v4l2_ctrl *ctrl) |
1345 | struct v4l2_queryctrl *qc) | ||
1346 | { | 1310 | { |
1347 | struct solo_enc_fh *fh = priv; | 1311 | struct solo_enc_dev *solo_enc = |
1348 | struct solo_enc_dev *solo_enc = fh->enc; | 1312 | container_of(ctrl->handler, struct solo_enc_dev, hdl); |
1349 | struct solo_dev *solo_dev = solo_enc->solo_dev; | 1313 | struct solo_dev *solo_dev = solo_enc->solo_dev; |
1350 | |||
1351 | qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id); | ||
1352 | if (!qc->id) | ||
1353 | return -EINVAL; | ||
1354 | |||
1355 | switch (qc->id) { | ||
1356 | case V4L2_CID_BRIGHTNESS: | ||
1357 | case V4L2_CID_CONTRAST: | ||
1358 | case V4L2_CID_SATURATION: | ||
1359 | case V4L2_CID_HUE: | ||
1360 | return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80); | ||
1361 | case V4L2_CID_SHARPNESS: | ||
1362 | return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00); | ||
1363 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
1364 | return v4l2_ctrl_query_fill( | ||
1365 | qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | ||
1366 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, | ||
1367 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); | ||
1368 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1369 | return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps); | ||
1370 | #ifdef PRIVATE_CIDS | ||
1371 | case V4L2_CID_MOTION_THRESHOLD: | ||
1372 | qc->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
1373 | qc->type = V4L2_CTRL_TYPE_INTEGER; | ||
1374 | qc->minimum = 0; | ||
1375 | qc->maximum = 0xffff; | ||
1376 | qc->step = 1; | ||
1377 | qc->default_value = SOLO_DEF_MOT_THRESH; | ||
1378 | strlcpy(qc->name, "Motion Detection Threshold", | ||
1379 | sizeof(qc->name)); | ||
1380 | return 0; | ||
1381 | case V4L2_CID_MOTION_ENABLE: | ||
1382 | qc->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
1383 | qc->minimum = 0; | ||
1384 | qc->maximum = qc->step = 1; | ||
1385 | qc->default_value = 0; | ||
1386 | strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name)); | ||
1387 | return 0; | ||
1388 | #else | ||
1389 | case V4L2_CID_MOTION_THRESHOLD: | ||
1390 | return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1, | ||
1391 | SOLO_DEF_MOT_THRESH); | ||
1392 | case V4L2_CID_MOTION_ENABLE: | ||
1393 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1394 | #endif | ||
1395 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1396 | qc->type = V4L2_CTRL_TYPE_STRING; | ||
1397 | qc->minimum = 0; | ||
1398 | qc->maximum = OSD_TEXT_MAX; | ||
1399 | qc->step = 1; | ||
1400 | qc->default_value = 0; | ||
1401 | strlcpy(qc->name, "OSD Text", sizeof(qc->name)); | ||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | return -EINVAL; | ||
1406 | } | ||
1407 | |||
1408 | static int solo_querymenu(struct file *file, void *priv, | ||
1409 | struct v4l2_querymenu *qmenu) | ||
1410 | { | ||
1411 | struct v4l2_queryctrl qctrl; | ||
1412 | int err; | 1314 | int err; |
1413 | 1315 | ||
1414 | qctrl.id = qmenu->id; | ||
1415 | |||
1416 | err = solo_queryctrl(file, priv, &qctrl); | ||
1417 | if (err) | ||
1418 | return err; | ||
1419 | |||
1420 | return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); | ||
1421 | } | ||
1422 | |||
1423 | static int solo_g_ctrl(struct file *file, void *priv, | ||
1424 | struct v4l2_control *ctrl) | ||
1425 | { | ||
1426 | struct solo_enc_fh *fh = priv; | ||
1427 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1428 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1429 | |||
1430 | switch (ctrl->id) { | ||
1431 | case V4L2_CID_BRIGHTNESS: | ||
1432 | case V4L2_CID_CONTRAST: | ||
1433 | case V4L2_CID_SATURATION: | ||
1434 | case V4L2_CID_HUE: | ||
1435 | case V4L2_CID_SHARPNESS: | ||
1436 | return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, | ||
1437 | &ctrl->value); | ||
1438 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
1439 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; | ||
1440 | break; | ||
1441 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1442 | if (atomic_read(&solo_enc->readers) > 0) | ||
1443 | return -EBUSY; | ||
1444 | ctrl->value = solo_enc->gop; | ||
1445 | break; | ||
1446 | case V4L2_CID_MOTION_THRESHOLD: | ||
1447 | ctrl->value = solo_enc->motion_thresh; | ||
1448 | break; | ||
1449 | case V4L2_CID_MOTION_ENABLE: | ||
1450 | ctrl->value = solo_is_motion_on(solo_enc); | ||
1451 | break; | ||
1452 | default: | ||
1453 | return -EINVAL; | ||
1454 | } | ||
1455 | |||
1456 | return 0; | ||
1457 | } | ||
1458 | |||
1459 | static int solo_s_ctrl(struct file *file, void *priv, | ||
1460 | struct v4l2_control *ctrl) | ||
1461 | { | ||
1462 | struct solo_enc_fh *fh = priv; | ||
1463 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1464 | struct solo_dev *solo_dev = solo_enc->solo_dev; | ||
1465 | |||
1466 | switch (ctrl->id) { | 1316 | switch (ctrl->id) { |
1467 | case V4L2_CID_BRIGHTNESS: | 1317 | case V4L2_CID_BRIGHTNESS: |
1468 | case V4L2_CID_CONTRAST: | 1318 | case V4L2_CID_CONTRAST: |
@@ -1470,20 +1320,15 @@ static int solo_s_ctrl(struct file *file, void *priv, | |||
1470 | case V4L2_CID_HUE: | 1320 | case V4L2_CID_HUE: |
1471 | case V4L2_CID_SHARPNESS: | 1321 | case V4L2_CID_SHARPNESS: |
1472 | return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, | 1322 | return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, |
1473 | ctrl->value); | 1323 | ctrl->val); |
1474 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 1324 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
1475 | if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) | 1325 | return 0; |
1476 | return -ERANGE; | ||
1477 | break; | ||
1478 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | 1326 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: |
1479 | if (ctrl->value < 1 || ctrl->value > 255) | 1327 | solo_enc->gop = ctrl->val; |
1480 | return -ERANGE; | 1328 | return 0; |
1481 | solo_enc->gop = ctrl->value; | 1329 | case V4L2_CID_MOTION_THRESHOLD: { |
1482 | break; | 1330 | u16 block = (ctrl->val >> 16) & 0xffff; |
1483 | case V4L2_CID_MOTION_THRESHOLD: | 1331 | u16 value = ctrl->val & 0xffff; |
1484 | { | ||
1485 | u16 block = (ctrl->value >> 16) & 0xffff; | ||
1486 | u16 value = ctrl->value & 0xffff; | ||
1487 | 1332 | ||
1488 | /* Motion thresholds are in a table of 64x64 samples, with | 1333 | /* Motion thresholds are in a table of 64x64 samples, with |
1489 | * each sample representing 16x16 pixels of the source. In | 1334 | * each sample representing 16x16 pixels of the source. In |
@@ -1492,22 +1337,25 @@ static int solo_s_ctrl(struct file *file, void *priv, | |||
1492 | * | 1337 | * |
1493 | * Block is 0 to set the threshold globally, or any positive | 1338 | * Block is 0 to set the threshold globally, or any positive |
1494 | * number under 2049 to set block-1 individually. */ | 1339 | * number under 2049 to set block-1 individually. */ |
1495 | if (block > 2049) | 1340 | /* Currently we limit support to block 0 only. A later patch |
1496 | return -ERANGE; | 1341 | * will add a new ioctl to set all other blocks. */ |
1497 | |||
1498 | if (block == 0) { | 1342 | if (block == 0) { |
1499 | solo_enc->motion_thresh = value; | 1343 | solo_enc->motion_thresh = value; |
1500 | return solo_set_motion_threshold(solo_dev, | 1344 | return solo_set_motion_threshold(solo_dev, |
1501 | solo_enc->ch, value); | 1345 | solo_enc->ch, value); |
1502 | } else { | ||
1503 | return solo_set_motion_block(solo_dev, solo_enc->ch, | ||
1504 | value, block - 1); | ||
1505 | } | 1346 | } |
1506 | break; | 1347 | return solo_set_motion_block(solo_dev, solo_enc->ch, |
1348 | value, block - 1); | ||
1507 | } | 1349 | } |
1508 | case V4L2_CID_MOTION_ENABLE: | 1350 | case V4L2_CID_MOTION_ENABLE: |
1509 | solo_motion_toggle(solo_enc, ctrl->value); | 1351 | solo_motion_toggle(solo_enc, ctrl->val); |
1510 | break; | 1352 | return 0; |
1353 | case V4L2_CID_OSD_TEXT: | ||
1354 | mutex_lock(&solo_enc->enable_lock); | ||
1355 | strcpy(solo_enc->osd_text, ctrl->string); | ||
1356 | err = solo_osd_print(solo_enc); | ||
1357 | mutex_unlock(&solo_enc->enable_lock); | ||
1358 | return err; | ||
1511 | default: | 1359 | default: |
1512 | return -EINVAL; | 1360 | return -EINVAL; |
1513 | } | 1361 | } |
@@ -1515,86 +1363,6 @@ static int solo_s_ctrl(struct file *file, void *priv, | |||
1515 | return 0; | 1363 | return 0; |
1516 | } | 1364 | } |
1517 | 1365 | ||
1518 | static int solo_s_ext_ctrls(struct file *file, void *priv, | ||
1519 | struct v4l2_ext_controls *ctrls) | ||
1520 | { | ||
1521 | struct solo_enc_fh *fh = priv; | ||
1522 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1523 | int i; | ||
1524 | |||
1525 | for (i = 0; i < ctrls->count; i++) { | ||
1526 | struct v4l2_ext_control *ctrl = (ctrls->controls + i); | ||
1527 | int err; | ||
1528 | |||
1529 | switch (ctrl->id) { | ||
1530 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1531 | if (ctrl->size - 1 > OSD_TEXT_MAX) | ||
1532 | err = -ERANGE; | ||
1533 | else { | ||
1534 | mutex_lock(&solo_enc->enable_lock); | ||
1535 | err = copy_from_user(solo_enc->osd_text, | ||
1536 | ctrl->string, | ||
1537 | OSD_TEXT_MAX); | ||
1538 | solo_enc->osd_text[OSD_TEXT_MAX] = '\0'; | ||
1539 | if (!err) | ||
1540 | err = solo_osd_print(solo_enc); | ||
1541 | else | ||
1542 | err = -EFAULT; | ||
1543 | mutex_unlock(&solo_enc->enable_lock); | ||
1544 | } | ||
1545 | break; | ||
1546 | default: | ||
1547 | err = -EINVAL; | ||
1548 | } | ||
1549 | |||
1550 | if (err < 0) { | ||
1551 | ctrls->error_idx = i; | ||
1552 | return err; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | static int solo_g_ext_ctrls(struct file *file, void *priv, | ||
1560 | struct v4l2_ext_controls *ctrls) | ||
1561 | { | ||
1562 | struct solo_enc_fh *fh = priv; | ||
1563 | struct solo_enc_dev *solo_enc = fh->enc; | ||
1564 | int i; | ||
1565 | |||
1566 | for (i = 0; i < ctrls->count; i++) { | ||
1567 | struct v4l2_ext_control *ctrl = (ctrls->controls + i); | ||
1568 | int err; | ||
1569 | |||
1570 | switch (ctrl->id) { | ||
1571 | case V4L2_CID_RDS_TX_RADIO_TEXT: | ||
1572 | if (ctrl->size < OSD_TEXT_MAX) { | ||
1573 | ctrl->size = OSD_TEXT_MAX; | ||
1574 | err = -ENOSPC; | ||
1575 | } else { | ||
1576 | mutex_lock(&solo_enc->enable_lock); | ||
1577 | err = copy_to_user(ctrl->string, | ||
1578 | solo_enc->osd_text, | ||
1579 | OSD_TEXT_MAX); | ||
1580 | if (err) | ||
1581 | err = -EFAULT; | ||
1582 | mutex_unlock(&solo_enc->enable_lock); | ||
1583 | } | ||
1584 | break; | ||
1585 | default: | ||
1586 | err = -EINVAL; | ||
1587 | } | ||
1588 | |||
1589 | if (err < 0) { | ||
1590 | ctrls->error_idx = i; | ||
1591 | return err; | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | static const struct v4l2_file_operations solo_enc_fops = { | 1366 | static const struct v4l2_file_operations solo_enc_fops = { |
1599 | .owner = THIS_MODULE, | 1367 | .owner = THIS_MODULE, |
1600 | .open = solo_enc_open, | 1368 | .open = solo_enc_open, |
@@ -1630,13 +1398,6 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { | |||
1630 | /* Video capture parameters */ | 1398 | /* Video capture parameters */ |
1631 | .vidioc_s_parm = solo_s_parm, | 1399 | .vidioc_s_parm = solo_s_parm, |
1632 | .vidioc_g_parm = solo_g_parm, | 1400 | .vidioc_g_parm = solo_g_parm, |
1633 | /* Controls */ | ||
1634 | .vidioc_queryctrl = solo_queryctrl, | ||
1635 | .vidioc_querymenu = solo_querymenu, | ||
1636 | .vidioc_g_ctrl = solo_g_ctrl, | ||
1637 | .vidioc_s_ctrl = solo_s_ctrl, | ||
1638 | .vidioc_g_ext_ctrls = solo_g_ext_ctrls, | ||
1639 | .vidioc_s_ext_ctrls = solo_s_ext_ctrls, | ||
1640 | }; | 1401 | }; |
1641 | 1402 | ||
1642 | static const struct video_device solo_enc_template = { | 1403 | static const struct video_device solo_enc_template = { |
@@ -1650,18 +1411,82 @@ static const struct video_device solo_enc_template = { | |||
1650 | .current_norm = V4L2_STD_NTSC_M, | 1411 | .current_norm = V4L2_STD_NTSC_M, |
1651 | }; | 1412 | }; |
1652 | 1413 | ||
1414 | static const struct v4l2_ctrl_ops solo_ctrl_ops = { | ||
1415 | .s_ctrl = solo_s_ctrl, | ||
1416 | }; | ||
1417 | |||
1418 | static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { | ||
1419 | .ops = &solo_ctrl_ops, | ||
1420 | .id = V4L2_CID_MOTION_THRESHOLD, | ||
1421 | .name = "Motion Detection Threshold", | ||
1422 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1423 | .max = 0xffff, | ||
1424 | .def = SOLO_DEF_MOT_THRESH, | ||
1425 | .step = 1, | ||
1426 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
1427 | }; | ||
1428 | |||
1429 | static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { | ||
1430 | .ops = &solo_ctrl_ops, | ||
1431 | .id = V4L2_CID_MOTION_ENABLE, | ||
1432 | .name = "Motion Detection Enable", | ||
1433 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1434 | .max = 1, | ||
1435 | .step = 1, | ||
1436 | }; | ||
1437 | |||
1438 | static const struct v4l2_ctrl_config solo_osd_text_ctrl = { | ||
1439 | .ops = &solo_ctrl_ops, | ||
1440 | .id = V4L2_CID_OSD_TEXT, | ||
1441 | .name = "OSD Text", | ||
1442 | .type = V4L2_CTRL_TYPE_STRING, | ||
1443 | .max = OSD_TEXT_MAX, | ||
1444 | .step = 1, | ||
1445 | }; | ||
1446 | |||
1653 | static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, | 1447 | static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, |
1654 | u8 ch, unsigned nr) | 1448 | u8 ch, unsigned nr) |
1655 | { | 1449 | { |
1656 | struct solo_enc_dev *solo_enc; | 1450 | struct solo_enc_dev *solo_enc; |
1451 | struct v4l2_ctrl_handler *hdl; | ||
1657 | int ret; | 1452 | int ret; |
1658 | 1453 | ||
1659 | solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); | 1454 | solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); |
1660 | if (!solo_enc) | 1455 | if (!solo_enc) |
1661 | return ERR_PTR(-ENOMEM); | 1456 | return ERR_PTR(-ENOMEM); |
1662 | 1457 | ||
1458 | hdl = &solo_enc->hdl; | ||
1459 | v4l2_ctrl_handler_init(hdl, 10); | ||
1460 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1461 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
1462 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1463 | V4L2_CID_CONTRAST, 0, 255, 1, 128); | ||
1464 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1465 | V4L2_CID_SATURATION, 0, 255, 1, 128); | ||
1466 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1467 | V4L2_CID_HUE, 0, 255, 1, 128); | ||
1468 | if (tw28_has_sharpness(solo_dev, ch)) | ||
1469 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1470 | V4L2_CID_SHARPNESS, 0, 15, 1, 0); | ||
1471 | v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops, | ||
1472 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
1473 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 3, | ||
1474 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); | ||
1475 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | ||
1476 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps); | ||
1477 | v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL); | ||
1478 | v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL); | ||
1479 | v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL); | ||
1480 | if (hdl->error) { | ||
1481 | ret = hdl->error; | ||
1482 | v4l2_ctrl_handler_free(hdl); | ||
1483 | kfree(solo_enc); | ||
1484 | return ERR_PTR(ret); | ||
1485 | } | ||
1486 | |||
1663 | solo_enc->vfd = video_device_alloc(); | 1487 | solo_enc->vfd = video_device_alloc(); |
1664 | if (!solo_enc->vfd) { | 1488 | if (!solo_enc->vfd) { |
1489 | v4l2_ctrl_handler_free(hdl); | ||
1665 | kfree(solo_enc); | 1490 | kfree(solo_enc); |
1666 | return ERR_PTR(-ENOMEM); | 1491 | return ERR_PTR(-ENOMEM); |
1667 | } | 1492 | } |
@@ -1671,9 +1496,11 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, | |||
1671 | 1496 | ||
1672 | *solo_enc->vfd = solo_enc_template; | 1497 | *solo_enc->vfd = solo_enc_template; |
1673 | solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; | 1498 | solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; |
1499 | solo_enc->vfd->ctrl_handler = hdl; | ||
1674 | ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); | 1500 | ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); |
1675 | if (ret < 0) { | 1501 | if (ret < 0) { |
1676 | video_device_release(solo_enc->vfd); | 1502 | video_device_release(solo_enc->vfd); |
1503 | v4l2_ctrl_handler_free(hdl); | ||
1677 | kfree(solo_enc); | 1504 | kfree(solo_enc); |
1678 | return ERR_PTR(ret); | 1505 | return ERR_PTR(ret); |
1679 | } | 1506 | } |
@@ -1714,6 +1541,7 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) | |||
1714 | return; | 1541 | return; |
1715 | 1542 | ||
1716 | video_unregister_device(solo_enc->vfd); | 1543 | video_unregister_device(solo_enc->vfd); |
1544 | v4l2_ctrl_handler_free(&solo_enc->hdl); | ||
1717 | kfree(solo_enc); | 1545 | kfree(solo_enc); |
1718 | } | 1546 | } |
1719 | 1547 | ||
diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 33171161002f..4243bbe8a3ed 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c | |||
@@ -687,64 +687,14 @@ static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) | |||
687 | return 0; | 687 | return 0; |
688 | } | 688 | } |
689 | 689 | ||
690 | static const u32 solo_motion_ctrls[] = { | 690 | static int solo_s_ctrl(struct v4l2_ctrl *ctrl) |
691 | V4L2_CID_MOTION_TRACE, | ||
692 | 0 | ||
693 | }; | ||
694 | |||
695 | static const u32 *solo_ctrl_classes[] = { | ||
696 | solo_motion_ctrls, | ||
697 | NULL | ||
698 | }; | ||
699 | |||
700 | static int solo_disp_queryctrl(struct file *file, void *priv, | ||
701 | struct v4l2_queryctrl *qc) | ||
702 | { | ||
703 | qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id); | ||
704 | if (!qc->id) | ||
705 | return -EINVAL; | ||
706 | |||
707 | switch (qc->id) { | ||
708 | #ifdef PRIVATE_CIDS | ||
709 | case V4L2_CID_MOTION_TRACE: | ||
710 | qc->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
711 | qc->minimum = 0; | ||
712 | qc->maximum = qc->step = 1; | ||
713 | qc->default_value = 0; | ||
714 | strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name)); | ||
715 | return 0; | ||
716 | #else | ||
717 | case V4L2_CID_MOTION_TRACE: | ||
718 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
719 | #endif | ||
720 | } | ||
721 | return -EINVAL; | ||
722 | } | ||
723 | |||
724 | static int solo_disp_g_ctrl(struct file *file, void *priv, | ||
725 | struct v4l2_control *ctrl) | ||
726 | { | 691 | { |
727 | struct solo_filehandle *fh = priv; | 692 | struct solo_dev *solo_dev = |
728 | struct solo_dev *solo_dev = fh->solo_dev; | 693 | container_of(ctrl->handler, struct solo_dev, disp_hdl); |
729 | 694 | ||
730 | switch (ctrl->id) { | 695 | switch (ctrl->id) { |
731 | case V4L2_CID_MOTION_TRACE: | 696 | case V4L2_CID_MOTION_TRACE: |
732 | ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR) | 697 | if (ctrl->val) { |
733 | ? 1 : 0; | ||
734 | return 0; | ||
735 | } | ||
736 | return -EINVAL; | ||
737 | } | ||
738 | |||
739 | static int solo_disp_s_ctrl(struct file *file, void *priv, | ||
740 | struct v4l2_control *ctrl) | ||
741 | { | ||
742 | struct solo_filehandle *fh = priv; | ||
743 | struct solo_dev *solo_dev = fh->solo_dev; | ||
744 | |||
745 | switch (ctrl->id) { | ||
746 | case V4L2_CID_MOTION_TRACE: | ||
747 | if (ctrl->value) { | ||
748 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, | 698 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, |
749 | SOLO_VI_MOTION_Y_ADD | | 699 | SOLO_VI_MOTION_Y_ADD | |
750 | SOLO_VI_MOTION_Y_VALUE(0x20) | | 700 | SOLO_VI_MOTION_Y_VALUE(0x20) | |
@@ -760,6 +710,8 @@ static int solo_disp_s_ctrl(struct file *file, void *priv, | |||
760 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); | 710 | solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); |
761 | } | 711 | } |
762 | return 0; | 712 | return 0; |
713 | default: | ||
714 | break; | ||
763 | } | 715 | } |
764 | return -EINVAL; | 716 | return -EINVAL; |
765 | } | 717 | } |
@@ -793,10 +745,6 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { | |||
793 | .vidioc_dqbuf = solo_dqbuf, | 745 | .vidioc_dqbuf = solo_dqbuf, |
794 | .vidioc_streamon = solo_streamon, | 746 | .vidioc_streamon = solo_streamon, |
795 | .vidioc_streamoff = solo_streamoff, | 747 | .vidioc_streamoff = solo_streamoff, |
796 | /* Controls */ | ||
797 | .vidioc_queryctrl = solo_disp_queryctrl, | ||
798 | .vidioc_g_ctrl = solo_disp_g_ctrl, | ||
799 | .vidioc_s_ctrl = solo_disp_s_ctrl, | ||
800 | }; | 748 | }; |
801 | 749 | ||
802 | static struct video_device solo_v4l2_template = { | 750 | static struct video_device solo_v4l2_template = { |
@@ -810,6 +758,19 @@ static struct video_device solo_v4l2_template = { | |||
810 | .current_norm = V4L2_STD_NTSC_M, | 758 | .current_norm = V4L2_STD_NTSC_M, |
811 | }; | 759 | }; |
812 | 760 | ||
761 | static const struct v4l2_ctrl_ops solo_ctrl_ops = { | ||
762 | .s_ctrl = solo_s_ctrl, | ||
763 | }; | ||
764 | |||
765 | static const struct v4l2_ctrl_config solo_motion_trace_ctrl = { | ||
766 | .ops = &solo_ctrl_ops, | ||
767 | .id = V4L2_CID_MOTION_TRACE, | ||
768 | .name = "Motion Detection Trace", | ||
769 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
770 | .max = 1, | ||
771 | .step = 1, | ||
772 | }; | ||
773 | |||
813 | int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) | 774 | int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) |
814 | { | 775 | { |
815 | int ret; | 776 | int ret; |
@@ -824,6 +785,11 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) | |||
824 | 785 | ||
825 | *solo_dev->vfd = solo_v4l2_template; | 786 | *solo_dev->vfd = solo_v4l2_template; |
826 | solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; | 787 | solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; |
788 | v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1); | ||
789 | v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL); | ||
790 | if (solo_dev->disp_hdl.error) | ||
791 | return solo_dev->disp_hdl.error; | ||
792 | solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; | ||
827 | 793 | ||
828 | ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); | 794 | ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); |
829 | if (ret < 0) { | 795 | if (ret < 0) { |
@@ -862,5 +828,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) | |||
862 | return; | 828 | return; |
863 | 829 | ||
864 | video_unregister_device(solo_dev->vfd); | 830 | video_unregister_device(solo_dev->vfd); |
831 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); | ||
865 | solo_dev->vfd = NULL; | 832 | solo_dev->vfd = NULL; |
866 | } | 833 | } |