Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

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