aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-03-18 14:25:36 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-18 19:30:36 -0400
commitbe431b16c6bd22020abc5f5f30a89f1e2934de8e (patch)
tree0d4be77da0f07001a29640c17a06839eeee48224
parent7f6301d1257505d35e87ef1cb8eeee268e63a123 (diff)
[media] dvb-frontend: split set_delivery_system()
This function is complex, and has different workflows, one for DVBv3 calls, and another one for DVBv5 calls. Break it into 3 functions, in order to make easier to understand what each block does. No functional changes so far. A few comments got improved. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c294
1 files changed, 165 insertions, 129 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 6e50a7581568..d0d193d1404a 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1509,132 +1509,12 @@ static bool is_dvbv3_delsys(u32 delsys)
1509 return status; 1509 return status;
1510} 1510}
1511 1511
1512static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) 1512static int emulate_delivery_system(struct dvb_frontend *fe,
1513 enum dvbv3_emulation_type type,
1514 u32 delsys, u32 desired_system)
1513{ 1515{
1514 int ncaps, i; 1516 int i;
1515 u32 delsys = SYS_UNDEFINED;
1516 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 1517 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1517 enum dvbv3_emulation_type type;
1518
1519 /*
1520 * It was reported that some old DVBv5 applications were
1521 * filling delivery_system with SYS_UNDEFINED. If this happens,
1522 * assume that the application wants to use the first supported
1523 * delivery system.
1524 */
1525 if (c->delivery_system == SYS_UNDEFINED)
1526 c->delivery_system = fe->ops.delsys[0];
1527
1528 if (desired_system == SYS_UNDEFINED) {
1529 /*
1530 * A DVBv3 call doesn't know what's the desired system.
1531 * Also, DVBv3 applications don't know that ops.info->type
1532 * could be changed, and they simply dies when it doesn't
1533 * match.
1534 * So, don't change the current delivery system, as it
1535 * may be trying to do the wrong thing, like setting an
1536 * ISDB-T frontend as DVB-T. Instead, find the closest
1537 * DVBv3 system that matches the delivery system.
1538 */
1539 if (is_dvbv3_delsys(c->delivery_system)) {
1540 dev_dbg(fe->dvb->device,
1541 "%s: Using delivery system to %d\n",
1542 __func__, c->delivery_system);
1543 return 0;
1544 }
1545 type = dvbv3_type(c->delivery_system);
1546 switch (type) {
1547 case DVBV3_QPSK:
1548 desired_system = SYS_DVBS;
1549 break;
1550 case DVBV3_QAM:
1551 desired_system = SYS_DVBC_ANNEX_A;
1552 break;
1553 case DVBV3_ATSC:
1554 desired_system = SYS_ATSC;
1555 break;
1556 case DVBV3_OFDM:
1557 desired_system = SYS_DVBT;
1558 break;
1559 default:
1560 dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n",
1561 __func__);
1562 return -EINVAL;
1563 }
1564 /*
1565 * Get a delivery system that is compatible with DVBv3
1566 * NOTE: in order for this to work with softwares like Kaffeine that
1567 * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
1568 * DVB-S, drivers that support both should put the SYS_DVBS entry
1569 * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
1570 * The real fix is that userspace applications should not use DVBv3
1571 * and not trust on calling FE_SET_FRONTEND to switch the delivery
1572 * system.
1573 */
1574 ncaps = 0;
1575 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1576 if (fe->ops.delsys[ncaps] == desired_system) {
1577 delsys = desired_system;
1578 break;
1579 }
1580 ncaps++;
1581 }
1582 if (delsys == SYS_UNDEFINED) {
1583 dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n",
1584 __func__, desired_system);
1585 }
1586 } else {
1587 /*
1588 * This is a DVBv5 call. So, it likely knows the supported
1589 * delivery systems.
1590 */
1591
1592 /* Check if the desired delivery system is supported */
1593 ncaps = 0;
1594 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1595 if (fe->ops.delsys[ncaps] == desired_system) {
1596 c->delivery_system = desired_system;
1597 dev_dbg(fe->dvb->device,
1598 "%s: Changing delivery system to %d\n",
1599 __func__, desired_system);
1600 return 0;
1601 }
1602 ncaps++;
1603 }
1604 type = dvbv3_type(desired_system);
1605
1606 /*
1607 * The delivery system is not supported. See if it can be
1608 * emulated.
1609 * The emulation only works if the desired system is one of the
1610 * DVBv3 delivery systems
1611 */
1612 if (!is_dvbv3_delsys(desired_system)) {
1613 dev_dbg(fe->dvb->device,
1614 "%s: can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
1615 __func__);
1616 return -EINVAL;
1617 }
1618
1619 /*
1620 * Get the last non-DVBv3 delivery system that has the same type
1621 * of the desired system
1622 */
1623 ncaps = 0;
1624 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1625 if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
1626 !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
1627 delsys = fe->ops.delsys[ncaps];
1628 ncaps++;
1629 }
1630 /* There's nothing compatible with the desired delivery system */
1631 if (delsys == SYS_UNDEFINED) {
1632 dev_dbg(fe->dvb->device,
1633 "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
1634 __func__);
1635 return -EINVAL;
1636 }
1637 }
1638 1518
1639 c->delivery_system = delsys; 1519 c->delivery_system = delsys;
1640 1520
@@ -1648,8 +1528,8 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
1648 * delivery system is the last one at the ops.delsys[] array 1528 * delivery system is the last one at the ops.delsys[] array
1649 */ 1529 */
1650 dev_dbg(fe->dvb->device, 1530 dev_dbg(fe->dvb->device,
1651 "%s: Using delivery system %d emulated as if it were a %d\n", 1531 "%s: Using delivery system %d emulated as if it were a %d\n",
1652 __func__, delsys, desired_system); 1532 __func__, delsys, desired_system);
1653 1533
1654 /* 1534 /*
1655 * For now, handles ISDB-T calls. More code may be needed here for the 1535 * For now, handles ISDB-T calls. More code may be needed here for the
@@ -1684,6 +1564,162 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
1684 return 0; 1564 return 0;
1685} 1565}
1686 1566
1567static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
1568 u32 desired_system)
1569{
1570 int ncaps;
1571 u32 delsys = SYS_UNDEFINED;
1572 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1573 enum dvbv3_emulation_type type;
1574
1575 /*
1576 * It was reported that some old DVBv5 applications were
1577 * filling delivery_system with SYS_UNDEFINED. If this happens,
1578 * assume that the application wants to use the first supported
1579 * delivery system.
1580 */
1581 if (c->delivery_system == SYS_UNDEFINED)
1582 c->delivery_system = fe->ops.delsys[0];
1583
1584 /*
1585 * This is a DVBv5 call. So, it likely knows the supported
1586 * delivery systems.
1587 */
1588
1589 /* Check if the desired delivery system is supported */
1590 ncaps = 0;
1591 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1592 if (fe->ops.delsys[ncaps] == desired_system) {
1593 c->delivery_system = desired_system;
1594 dev_dbg(fe->dvb->device,
1595 "%s: Changing delivery system to %d\n",
1596 __func__, desired_system);
1597 return 0;
1598 }
1599 ncaps++;
1600 }
1601
1602 /*
1603 * Need to emulate a delivery system
1604 */
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)) {
1615 dev_dbg(fe->dvb->device,
1616 "%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n",
1617 __func__);
1618 return -EINVAL;
1619 }
1620
1621 /*
1622 * Get the last non-DVBv3 delivery system that has the same type
1623 * of the desired system
1624 */
1625 ncaps = 0;
1626 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1627 if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
1628 !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
1629 delsys = fe->ops.delsys[ncaps];
1630 ncaps++;
1631 }
1632 /* There's nothing compatible with the desired delivery system */
1633 if (delsys == SYS_UNDEFINED) {
1634 dev_dbg(fe->dvb->device,
1635 "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
1636 __func__);
1637 return -EINVAL;
1638 }
1639
1640 return emulate_delivery_system(fe, type, delsys, desired_system);
1641}
1642
1643static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
1644{
1645 int ncaps;
1646 u32 desired_system;
1647 u32 delsys = SYS_UNDEFINED;
1648 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1649 enum dvbv3_emulation_type type;
1650
1651 /* If not set yet, defaults to the first supported delivery system */
1652 if (c->delivery_system == SYS_UNDEFINED)
1653 c->delivery_system = fe->ops.delsys[0];
1654
1655 /*
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
1668 * delivery system
1669 */
1670 if (is_dvbv3_delsys(c->delivery_system)) {
1671 dev_dbg(fe->dvb->device,
1672 "%s: Using delivery system to %d\n",
1673 __func__, c->delivery_system);
1674 return 0;
1675 }
1676
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 /*
1699 * Get a delivery system that is compatible with DVBv3
1700 * NOTE: in order for this to work with softwares like Kaffeine that
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 */
1708 ncaps = 0;
1709 while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
1710 if (fe->ops.delsys[ncaps] == desired_system) {
1711 delsys = desired_system;
1712 break;
1713 }
1714 ncaps++;
1715 }
1716 if (delsys == SYS_UNDEFINED) {
1717 dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n",
1718 __func__, desired_system);
1719 }
1720 return emulate_delivery_system(fe, type, delsys, desired_system);
1721}
1722
1687static int dtv_property_process_set(struct dvb_frontend *fe, 1723static int dtv_property_process_set(struct dvb_frontend *fe,
1688 struct dtv_property *tvp, 1724 struct dtv_property *tvp,
1689 struct file *file) 1725 struct file *file)
@@ -1742,7 +1778,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
1742 c->rolloff = tvp->u.data; 1778 c->rolloff = tvp->u.data;
1743 break; 1779 break;
1744 case DTV_DELIVERY_SYSTEM: 1780 case DTV_DELIVERY_SYSTEM:
1745 r = set_delivery_system(fe, tvp->u.data); 1781 r = dvbv5_set_delivery_system(fe, tvp->u.data);
1746 break; 1782 break;
1747 case DTV_VOLTAGE: 1783 case DTV_VOLTAGE:
1748 c->voltage = tvp->u.data; 1784 c->voltage = tvp->u.data;
@@ -2335,7 +2371,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
2335 break; 2371 break;
2336 2372
2337 case FE_SET_FRONTEND: 2373 case FE_SET_FRONTEND:
2338 err = set_delivery_system(fe, SYS_UNDEFINED); 2374 err = dvbv3_set_delivery_system(fe);
2339 if (err) 2375 if (err)
2340 break; 2376 break;
2341 2377
@@ -2594,7 +2630,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
2594 * first supported delivery system (ops->delsys[0]) 2630 * first supported delivery system (ops->delsys[0])
2595 */ 2631 */
2596 2632
2597 fe->dtv_property_cache.delivery_system = fe->ops.delsys[0]; 2633 fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
2598 dvb_frontend_clear_cache(fe); 2634 dvb_frontend_clear_cache(fe);
2599 2635
2600 mutex_unlock(&frontend_mutex); 2636 mutex_unlock(&frontend_mutex);