aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2013-03-25 04:38:14 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-25 07:42:22 -0400
commitc813bd3c8dce3564166e2c4f839fd36df7b0ba5d (patch)
treed9efef5267195dbc865ee234cfc4bad3fd3bd514
parentd9ebd623c1912f8f02fc71d4e645973f51f83362 (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.h15
-rw-r--r--drivers/staging/media/solo6x10/tw28.c12
-rw-r--r--drivers/staging/media/solo6x10/tw28.h1
-rw-r--r--drivers/staging/media/solo6x10/v4l2-enc.c350
-rw-r--r--drivers/staging/media/solo6x10/v4l2.c83
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
110enum SOLO_I2C_STATE { 111enum SOLO_I2C_STATE {
111 IIC_STATE_IDLE, 112 IIC_STATE_IDLE,
@@ -137,6 +138,7 @@ struct solo_p2m_dev {
137struct solo_enc_dev { 138struct 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
663bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
664{
665 return is_tw286x(solo_dev, ch / 4);
666}
667
663int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, 668int 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
56int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); 56int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
57int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); 57int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
58bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch);
58 59
59u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); 60u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
60void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); 61void 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
123static 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
132static const u32 solo_mpeg_ctrls[] = {
133 V4L2_CID_MPEG_VIDEO_ENCODING,
134 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
135 0
136};
137
138static const u32 solo_private_ctrls[] = {
139 V4L2_CID_MOTION_ENABLE,
140 V4L2_CID_MOTION_THRESHOLD,
141 0
142};
143
144static const u32 solo_fmtx_ctrls[] = {
145 V4L2_CID_RDS_TX_RADIO_TEXT,
146 0
147};
148
149static 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
157struct vop_header { 122struct 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
1344static int solo_queryctrl(struct file *file, void *priv, 1309static 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
1408static 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
1423static 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
1459static 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
1518static 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
1559static 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
1598static const struct v4l2_file_operations solo_enc_fops = { 1366static 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
1642static const struct video_device solo_enc_template = { 1403static 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
1414static const struct v4l2_ctrl_ops solo_ctrl_ops = {
1415 .s_ctrl = solo_s_ctrl,
1416};
1417
1418static 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
1429static 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
1438static 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
1653static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, 1447static 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
690static const u32 solo_motion_ctrls[] = { 690static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
691 V4L2_CID_MOTION_TRACE,
692 0
693};
694
695static const u32 *solo_ctrl_classes[] = {
696 solo_motion_ctrls,
697 NULL
698};
699
700static 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
724static 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
739static 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
802static struct video_device solo_v4l2_template = { 750static 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
761static const struct v4l2_ctrl_ops solo_ctrl_ops = {
762 .s_ctrl = solo_s_ctrl,
763};
764
765static 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
813int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) 774int 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}