diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-18 14:25:37 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-18 19:33:03 -0400 |
commit | 52dee392f491e166cef21c787d1736f052a902cd (patch) | |
tree | 652a6489f4c05970cfe2c329e4c1de5ae8c0ced1 /drivers/media/dvb-core | |
parent | be431b16c6bd22020abc5f5f30a89f1e2934de8e (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.c | 219 |
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 | ||
1512 | static 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 | */ | ||
1522 | static 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 | */ | ||
1567 | static int dvbv5_set_delivery_system(struct dvb_frontend *fe, | 1576 | static 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 | */ | ||
1643 | static int dvbv3_set_delivery_system(struct dvb_frontend *fe) | 1680 | static 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 | ||
1723 | static int dtv_property_process_set(struct dvb_frontend *fe, | 1722 | static int dtv_property_process_set(struct dvb_frontend *fe, |