diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-18 14:25:36 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-18 19:30:36 -0400 |
commit | be431b16c6bd22020abc5f5f30a89f1e2934de8e (patch) | |
tree | 0d4be77da0f07001a29640c17a06839eeee48224 | |
parent | 7f6301d1257505d35e87ef1cb8eeee268e63a123 (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.c | 294 |
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 | ||
1512 | static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) | 1512 | static 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 | ||
1567 | static 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 | |||
1643 | static 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 | |||
1687 | static int dtv_property_process_set(struct dvb_frontend *fe, | 1723 | static 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); |