aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-core
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-03-18 14:25:37 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-18 19:33:03 -0400
commit52dee392f491e166cef21c787d1736f052a902cd (patch)
tree652a6489f4c05970cfe2c329e4c1de5ae8c0ced1 /drivers/media/dvb-core
parentbe431b16c6bd22020abc5f5f30a89f1e2934de8e (diff)
[media] dvb_frontend: Simplify the emulation logic
The current logic was broken and too complex; while it works fine for DVB-S2/DVB-S, it is broken for ISDB-T. Make the logic simpler, fixes it for ISDB-T and make it clearer. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c219
1 files changed, 109 insertions, 110 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index d0d193d1404a..eaa0a74e6a87 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1509,9 +1509,17 @@ static bool is_dvbv3_delsys(u32 delsys)
1509 return status; 1509 return status;
1510} 1510}
1511 1511
1512static int emulate_delivery_system(struct dvb_frontend *fe, 1512/**
1513 enum dvbv3_emulation_type type, 1513 * emulate_delivery_system - emulate a DVBv5 delivery system with a DVBv3 type
1514 u32 delsys, u32 desired_system) 1514 * @fe: struct frontend;
1515 * @delsys: DVBv5 type that will be used for emulation
1516 *
1517 * Provides emulation for delivery systems that are compatible with the old
1518 * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows
1519 * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent
1520 * parameters are compatible with DVB-S spec.
1521 */
1522static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys)
1515{ 1523{
1516 int i; 1524 int i;
1517 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1525 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1519,51 +1527,52 @@ static int emulate_delivery_system(struct dvb_frontend *fe,
1519 c->delivery_system = delsys; 1527 c->delivery_system = delsys;
1520 1528
1521 /* 1529 /*
1522 * The DVBv3 or DVBv5 call is requesting a different system. So, 1530 * If the call is for ISDB-T, put it into full-seg, auto mode, TV
1523 * emulation is needed.
1524 *
1525 * Emulate newer delivery systems like ISDBT, DVBT and DTMB
1526 * for older DVBv5 applications. The emulation will try to use
1527 * the auto mode for most things, and will assume that the desired
1528 * delivery system is the last one at the ops.delsys[] array
1529 */ 1531 */
1530 dev_dbg(fe->dvb->device, 1532 if (c->delivery_system == SYS_ISDBT) {
1531 "%s: Using delivery system %d emulated as if it were a %d\n", 1533 dev_dbg(fe->dvb->device,
1532 __func__, delsys, desired_system); 1534 "%s: Using defaults for SYS_ISDBT\n",
1535 __func__);
1533 1536
1534 /* 1537 if (!c->bandwidth_hz)
1535 * For now, handles ISDB-T calls. More code may be needed here for the 1538 c->bandwidth_hz = 6000000;
1536 * other emulated stuff 1539
1537 */ 1540 c->isdbt_partial_reception = 0;
1538 if (type == DVBV3_OFDM) { 1541 c->isdbt_sb_mode = 0;
1539 if (c->delivery_system == SYS_ISDBT) { 1542 c->isdbt_sb_subchannel = 0;
1540 dev_dbg(fe->dvb->device, 1543 c->isdbt_sb_segment_idx = 0;
1541 "%s: Using defaults for SYS_ISDBT\n", 1544 c->isdbt_sb_segment_count = 0;
1542 __func__); 1545 c->isdbt_layer_enabled = 7;
1543 1546 for (i = 0; i < 3; i++) {
1544 if (!c->bandwidth_hz) 1547 c->layer[i].fec = FEC_AUTO;
1545 c->bandwidth_hz = 6000000; 1548 c->layer[i].modulation = QAM_AUTO;
1546 1549 c->layer[i].interleaving = 0;
1547 c->isdbt_partial_reception = 0; 1550 c->layer[i].segment_count = 0;
1548 c->isdbt_sb_mode = 0;
1549 c->isdbt_sb_subchannel = 0;
1550 c->isdbt_sb_segment_idx = 0;
1551 c->isdbt_sb_segment_count = 0;
1552 c->isdbt_layer_enabled = 0;
1553 for (i = 0; i < 3; i++) {
1554 c->layer[i].fec = FEC_AUTO;
1555 c->layer[i].modulation = QAM_AUTO;
1556 c->layer[i].interleaving = 0;
1557 c->layer[i].segment_count = 0;
1558 }
1559 } 1551 }
1560 } 1552 }
1561 dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n", 1553 dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
1562 __func__, c->delivery_system); 1554 __func__, c->delivery_system);
1563 1555
1564 return 0; 1556 return 0;
1565} 1557}
1566 1558
1559/**
1560 * dvbv5_set_delivery_system - Sets the delivery system for a DVBv5 API call
1561 * @fe: frontend struct
1562 * @desired_system: delivery system requested by the user
1563 *
1564 * A DVBv5 call know what's the desired system it wants. So, set it.
1565 *
1566 * There are, however, a few known issues with early DVBv5 applications that
1567 * are also handled by this logic:
1568 *
1569 * 1) Some early apps use SYS_UNDEFINED as the desired delivery system.
1570 * This is an API violation, but, as we don't want to break userspace,
1571 * convert it to the first supported delivery system.
1572 * 2) Some apps might be using a DVBv5 call in a wrong way, passing, for
1573 * example, SYS_DVBT instead of SYS_ISDBT. This is because early usage of
1574 * ISDB-T provided backward compat with DVB-T.
1575 */
1567static int dvbv5_set_delivery_system(struct dvb_frontend *fe, 1576static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
1568 u32 desired_system) 1577 u32 desired_system)
1569{ 1578{
@@ -1578,15 +1587,14 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
1578 * assume that the application wants to use the first supported 1587 * assume that the application wants to use the first supported
1579 * delivery system. 1588 * delivery system.
1580 */ 1589 */
1581 if (c->delivery_system == SYS_UNDEFINED) 1590 if (desired_system == SYS_UNDEFINED)
1582 c->delivery_system = fe->ops.delsys[0]; 1591 desired_system = fe->ops.delsys[0];
1583 1592
1584 /* 1593 /*
1585 * This is a DVBv5 call. So, it likely knows the supported 1594 * This is a DVBv5 call. So, it likely knows the supported
1586 * delivery systems. 1595 * delivery systems. So, check if the desired delivery system is
1587 */ 1596 * supported
1588 1597 */
1589 /* Check if the desired delivery system is supported */
1590 ncaps = 0; 1598 ncaps = 0;
1591 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { 1599 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1592 if (fe->ops.delsys[ncaps] == desired_system) { 1600 if (fe->ops.delsys[ncaps] == desired_system) {
@@ -1600,70 +1608,86 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
1600 } 1608 }
1601 1609
1602 /* 1610 /*
1603 * Need to emulate a delivery system 1611 * The requested delivery system isn't supported. Maybe userspace
1612 * is requesting a DVBv3 compatible delivery system.
1613 *
1614 * The emulation only works if the desired system is one of the
1615 * delivery systems supported by DVBv3 API
1604 */ 1616 */
1605
1606 type = dvbv3_type(desired_system);
1607
1608 /*
1609 * The delivery system is not supported. See if it can be
1610 * emulated.
1611 * The emulation only works if the desired system is one of the
1612 * DVBv3 delivery systems
1613 */
1614 if (!is_dvbv3_delsys(desired_system)) { 1617 if (!is_dvbv3_delsys(desired_system)) {
1615 dev_dbg(fe->dvb->device, 1618 dev_dbg(fe->dvb->device,
1616 "%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n", 1619 "%s: Delivery system %d not supported.\n",
1617 __func__); 1620 __func__, desired_system);
1618 return -EINVAL; 1621 return -EINVAL;
1619 } 1622 }
1620 1623
1624 type = dvbv3_type(desired_system);
1625
1621 /* 1626 /*
1622 * Get the last non-DVBv3 delivery system that has the same type 1627 * Get the last non-DVBv3 delivery system that has the same type
1623 * of the desired system 1628 * of the desired system
1624 */ 1629 */
1625 ncaps = 0; 1630 ncaps = 0;
1626 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { 1631 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1627 if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && 1632 if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
1628 !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
1629 delsys = fe->ops.delsys[ncaps]; 1633 delsys = fe->ops.delsys[ncaps];
1630 ncaps++; 1634 ncaps++;
1631 } 1635 }
1636
1632 /* There's nothing compatible with the desired delivery system */ 1637 /* There's nothing compatible with the desired delivery system */
1633 if (delsys == SYS_UNDEFINED) { 1638 if (delsys == SYS_UNDEFINED) {
1634 dev_dbg(fe->dvb->device, 1639 dev_dbg(fe->dvb->device,
1635 "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", 1640 "%s: Delivery system %d not supported on emulation mode.\n",
1636 __func__); 1641 __func__, desired_system);
1637 return -EINVAL; 1642 return -EINVAL;
1638 } 1643 }
1639 1644
1640 return emulate_delivery_system(fe, type, delsys, desired_system); 1645 dev_dbg(fe->dvb->device,
1646 "%s: Using delivery system %d emulated as if it were %d\n",
1647 __func__, delsys, desired_system);
1648
1649 return emulate_delivery_system(fe, desired_system);
1641} 1650}
1642 1651
1652/**
1653 * dvbv3_set_delivery_system - Sets the delivery system for a DVBv3 API call
1654 * @fe: frontend struct
1655 *
1656 * A DVBv3 call doesn't know what's the desired system it wants. It also
1657 * doesn't allow to switch between different types. Due to that, userspace
1658 * should use DVBv5 instead.
1659 * However, in order to avoid breaking userspace API, limited backward
1660 * compatibility support is provided.
1661 *
1662 * There are some delivery systems that are incompatible with DVBv3 calls.
1663 *
1664 * This routine should work fine for frontends that support just one delivery
1665 * system.
1666 *
1667 * For frontends that support multiple frontends:
1668 * 1) It defaults to use the first supported delivery system. There's an
1669 * userspace application that allows changing it at runtime;
1670 *
1671 * 2) If the current delivery system is not compatible with DVBv3, it gets
1672 * the first one that it is compatible.
1673 *
1674 * NOTE: in order for this to work with applications like Kaffeine that
1675 * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
1676 * DVB-S, drivers that support both DVB-S and DVB-S2 should have the
1677 * SYS_DVBS entry before the SYS_DVBS2, otherwise it won't switch back
1678 * to DVB-S.
1679 */
1643static int dvbv3_set_delivery_system(struct dvb_frontend *fe) 1680static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
1644{ 1681{
1645 int ncaps; 1682 int ncaps;
1646 u32 desired_system;
1647 u32 delsys = SYS_UNDEFINED; 1683 u32 delsys = SYS_UNDEFINED;
1648 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1684 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1649 enum dvbv3_emulation_type type;
1650 1685
1651 /* If not set yet, defaults to the first supported delivery system */ 1686 /* If not set yet, defaults to the first supported delivery system */
1652 if (c->delivery_system == SYS_UNDEFINED) 1687 if (c->delivery_system == SYS_UNDEFINED)
1653 c->delivery_system = fe->ops.delsys[0]; 1688 c->delivery_system = fe->ops.delsys[0];
1654 1689
1655 /* 1690 /*
1656 * A DVBv3 call doesn't know what's the desired system.
1657 * Also, DVBv3 applications don't know that ops.info->type
1658 * could be changed, and they simply don't tune when it doesn't
1659 * match.
1660 * So, don't change the current delivery system, as it
1661 * may be trying to do the wrong thing, like setting an
1662 * ISDB-T frontend as DVB-T. Instead, find the closest
1663 * DVBv3 system that matches the delivery system.
1664 */
1665
1666 /*
1667 * Trivial case: just use the current one, if it already a DVBv3 1691 * Trivial case: just use the current one, if it already a DVBv3
1668 * delivery system 1692 * delivery system
1669 */ 1693 */
@@ -1674,50 +1698,25 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
1674 return 0; 1698 return 0;
1675 } 1699 }
1676 1700
1677 /* Convert from DVBv3 into DVBv5 namespace */
1678 type = dvbv3_type(c->delivery_system);
1679 switch (type) {
1680 case DVBV3_QPSK:
1681 desired_system = SYS_DVBS;
1682 break;
1683 case DVBV3_QAM:
1684 desired_system = SYS_DVBC_ANNEX_A;
1685 break;
1686 case DVBV3_ATSC:
1687 desired_system = SYS_ATSC;
1688 break;
1689 case DVBV3_OFDM:
1690 desired_system = SYS_DVBT;
1691 break;
1692 default:
1693 dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n",
1694 __func__);
1695 return -EINVAL;
1696 }
1697
1698 /* 1701 /*
1699 * Get a delivery system that is compatible with DVBv3 1702 * Seek for the first delivery system that it is compatible with a
1700 * NOTE: in order for this to work with softwares like Kaffeine that 1703 * DVBv3 standard
1701 * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
1702 * DVB-S, drivers that support both should put the SYS_DVBS entry
1703 * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
1704 * The real fix is that userspace applications should not use DVBv3
1705 * and not trust on calling FE_SET_FRONTEND to switch the delivery
1706 * system.
1707 */ 1704 */
1708 ncaps = 0; 1705 ncaps = 0;
1709 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { 1706 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1710 if (fe->ops.delsys[ncaps] == desired_system) { 1707 if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
1711 delsys = desired_system; 1708 delsys = fe->ops.delsys[ncaps];
1712 break; 1709 break;
1713 } 1710 }
1714 ncaps++; 1711 ncaps++;
1715 } 1712 }
1716 if (delsys == SYS_UNDEFINED) { 1713 if (delsys == SYS_UNDEFINED) {
1717 dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n", 1714 dev_dbg(fe->dvb->device,
1718 __func__, desired_system); 1715 "%s: Couldn't find a delivery system that works with FE_SET_FRONTEND\n",
1716 __func__);
1717 return -EINVAL;
1719 } 1718 }
1720 return emulate_delivery_system(fe, type, delsys, desired_system); 1719 return emulate_delivery_system(fe, delsys);
1721} 1720}
1722 1721
1723static int dtv_property_process_set(struct dvb_frontend *fe, 1722static int dtv_property_process_set(struct dvb_frontend *fe,