| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 11 | 12 | * |
|---|
| 12 | 13 | * Copyright (C) 1999-2002 Ralph Metzler |
|---|
| 13 | 14 | * & Marcus Metzler for convergence integrated media GmbH |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is free software; you can redistribute it and/or |
|---|
| 16 | | - * modify it under the terms of the GNU General Public License |
|---|
| 17 | | - * as published by the Free Software Foundation; either version 2 |
|---|
| 18 | | - * of the License, or (at your option) any later version. |
|---|
| 19 | | - * |
|---|
| 20 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 21 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 22 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 23 | | - * GNU General Public License for more details. |
|---|
| 24 | | - * To obtain the license, point your browser to |
|---|
| 25 | | - * http://www.gnu.org/copyleft/gpl.html |
|---|
| 26 | 15 | */ |
|---|
| 27 | 16 | |
|---|
| 28 | 17 | #define pr_fmt(fmt) "dvb_ca_en50221: " fmt |
|---|
| .. | .. |
|---|
| 162 | 151 | |
|---|
| 163 | 152 | /* mutex serializing ioctls */ |
|---|
| 164 | 153 | struct mutex ioctl_mutex; |
|---|
| 154 | + |
|---|
| 155 | + /* A mutex used when a device is disconnected */ |
|---|
| 156 | + struct mutex remove_mutex; |
|---|
| 157 | + |
|---|
| 158 | + /* Whether the device is disconnected */ |
|---|
| 159 | + int exit; |
|---|
| 165 | 160 | }; |
|---|
| 166 | 161 | |
|---|
| 167 | 162 | static void dvb_ca_private_free(struct dvb_ca_private *ca) |
|---|
| 168 | 163 | { |
|---|
| 169 | 164 | unsigned int i; |
|---|
| 170 | 165 | |
|---|
| 171 | | - dvb_free_device(ca->dvbdev); |
|---|
| 166 | + dvb_device_put(ca->dvbdev); |
|---|
| 172 | 167 | for (i = 0; i < ca->slot_count; i++) |
|---|
| 173 | 168 | vfree(ca->slot_info[i].rx_buffer.data); |
|---|
| 174 | 169 | |
|---|
| .. | .. |
|---|
| 198 | 193 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, |
|---|
| 199 | 194 | u8 *ebuf, int ecount); |
|---|
| 200 | 195 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, |
|---|
| 201 | | - u8 *ebuf, int ecount); |
|---|
| 196 | + u8 *ebuf, int ecount, int size_write_flag); |
|---|
| 202 | 197 | |
|---|
| 203 | 198 | /** |
|---|
| 204 | 199 | * Safely find needle in haystack. |
|---|
| .. | .. |
|---|
| 381 | 376 | ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10); |
|---|
| 382 | 377 | if (ret) |
|---|
| 383 | 378 | return ret; |
|---|
| 384 | | - ret = dvb_ca_en50221_write_data(ca, slot, buf, 2); |
|---|
| 379 | + ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW); |
|---|
| 385 | 380 | if (ret != 2) |
|---|
| 386 | 381 | return -EIO; |
|---|
| 387 | 382 | ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); |
|---|
| .. | .. |
|---|
| 789 | 784 | * @buf: The data in this buffer is treated as a complete link-level packet to |
|---|
| 790 | 785 | * be written. |
|---|
| 791 | 786 | * @bytes_write: Size of ebuf. |
|---|
| 787 | + * @size_write_flag: A flag on Command Register which says whether the link size |
|---|
| 788 | + * information will be writen or not. |
|---|
| 792 | 789 | * |
|---|
| 793 | 790 | * return: Number of bytes written, or < 0 on error. |
|---|
| 794 | 791 | */ |
|---|
| 795 | 792 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, |
|---|
| 796 | | - u8 *buf, int bytes_write) |
|---|
| 793 | + u8 *buf, int bytes_write, int size_write_flag) |
|---|
| 797 | 794 | { |
|---|
| 798 | 795 | struct dvb_ca_slot *sl = &ca->slot_info[slot]; |
|---|
| 799 | 796 | int status; |
|---|
| .. | .. |
|---|
| 828 | 825 | |
|---|
| 829 | 826 | /* OK, set HC bit */ |
|---|
| 830 | 827 | status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, |
|---|
| 831 | | - IRQEN | CMDREG_HC); |
|---|
| 828 | + IRQEN | CMDREG_HC | size_write_flag); |
|---|
| 832 | 829 | if (status) |
|---|
| 833 | 830 | goto exit; |
|---|
| 834 | 831 | |
|---|
| .. | .. |
|---|
| 1516 | 1513 | |
|---|
| 1517 | 1514 | mutex_lock(&sl->slot_lock); |
|---|
| 1518 | 1515 | status = dvb_ca_en50221_write_data(ca, slot, fragbuf, |
|---|
| 1519 | | - fraglen + 2); |
|---|
| 1516 | + fraglen + 2, 0); |
|---|
| 1520 | 1517 | mutex_unlock(&sl->slot_lock); |
|---|
| 1521 | 1518 | if (status == (fraglen + 2)) { |
|---|
| 1522 | 1519 | written = 1; |
|---|
| .. | .. |
|---|
| 1717 | 1714 | |
|---|
| 1718 | 1715 | dprintk("%s\n", __func__); |
|---|
| 1719 | 1716 | |
|---|
| 1720 | | - if (!try_module_get(ca->pub->owner)) |
|---|
| 1717 | + mutex_lock(&ca->remove_mutex); |
|---|
| 1718 | + |
|---|
| 1719 | + if (ca->exit) { |
|---|
| 1720 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1721 | + return -ENODEV; |
|---|
| 1722 | + } |
|---|
| 1723 | + |
|---|
| 1724 | + if (!try_module_get(ca->pub->owner)) { |
|---|
| 1725 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1721 | 1726 | return -EIO; |
|---|
| 1727 | + } |
|---|
| 1722 | 1728 | |
|---|
| 1723 | 1729 | err = dvb_generic_open(inode, file); |
|---|
| 1724 | 1730 | if (err < 0) { |
|---|
| 1725 | 1731 | module_put(ca->pub->owner); |
|---|
| 1732 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1726 | 1733 | return err; |
|---|
| 1727 | 1734 | } |
|---|
| 1728 | 1735 | |
|---|
| .. | .. |
|---|
| 1747 | 1754 | |
|---|
| 1748 | 1755 | dvb_ca_private_get(ca); |
|---|
| 1749 | 1756 | |
|---|
| 1757 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1750 | 1758 | return 0; |
|---|
| 1751 | 1759 | } |
|---|
| 1752 | 1760 | |
|---|
| .. | .. |
|---|
| 1766 | 1774 | |
|---|
| 1767 | 1775 | dprintk("%s\n", __func__); |
|---|
| 1768 | 1776 | |
|---|
| 1777 | + mutex_lock(&ca->remove_mutex); |
|---|
| 1778 | + |
|---|
| 1769 | 1779 | /* mark the CA device as closed */ |
|---|
| 1770 | 1780 | ca->open = 0; |
|---|
| 1771 | 1781 | dvb_ca_en50221_thread_update_delay(ca); |
|---|
| .. | .. |
|---|
| 1775 | 1785 | module_put(ca->pub->owner); |
|---|
| 1776 | 1786 | |
|---|
| 1777 | 1787 | dvb_ca_private_put(ca); |
|---|
| 1788 | + |
|---|
| 1789 | + if (dvbdev->users == 1 && ca->exit == 1) { |
|---|
| 1790 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1791 | + wake_up(&dvbdev->wait_queue); |
|---|
| 1792 | + } else { |
|---|
| 1793 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1794 | + } |
|---|
| 1778 | 1795 | |
|---|
| 1779 | 1796 | return err; |
|---|
| 1780 | 1797 | } |
|---|
| .. | .. |
|---|
| 1797 | 1814 | |
|---|
| 1798 | 1815 | dprintk("%s\n", __func__); |
|---|
| 1799 | 1816 | |
|---|
| 1817 | + poll_wait(file, &ca->wait_queue, wait); |
|---|
| 1818 | + |
|---|
| 1800 | 1819 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) |
|---|
| 1801 | 1820 | mask |= EPOLLIN; |
|---|
| 1802 | 1821 | |
|---|
| 1803 | 1822 | /* if there is something, return now */ |
|---|
| 1804 | 1823 | if (mask) |
|---|
| 1805 | 1824 | return mask; |
|---|
| 1806 | | - |
|---|
| 1807 | | - /* wait for something to happen */ |
|---|
| 1808 | | - poll_wait(file, &ca->wait_queue, wait); |
|---|
| 1809 | 1825 | |
|---|
| 1810 | 1826 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) |
|---|
| 1811 | 1827 | mask |= EPOLLIN; |
|---|
| .. | .. |
|---|
| 1900 | 1916 | } |
|---|
| 1901 | 1917 | |
|---|
| 1902 | 1918 | mutex_init(&ca->ioctl_mutex); |
|---|
| 1919 | + mutex_init(&ca->remove_mutex); |
|---|
| 1903 | 1920 | |
|---|
| 1904 | 1921 | if (signal_pending(current)) { |
|---|
| 1905 | 1922 | ret = -EINTR; |
|---|
| .. | .. |
|---|
| 1942 | 1959 | |
|---|
| 1943 | 1960 | dprintk("%s\n", __func__); |
|---|
| 1944 | 1961 | |
|---|
| 1962 | + mutex_lock(&ca->remove_mutex); |
|---|
| 1963 | + ca->exit = 1; |
|---|
| 1964 | + mutex_unlock(&ca->remove_mutex); |
|---|
| 1965 | + |
|---|
| 1966 | + if (ca->dvbdev->users < 1) |
|---|
| 1967 | + wait_event(ca->dvbdev->wait_queue, |
|---|
| 1968 | + ca->dvbdev->users == 1); |
|---|
| 1969 | + |
|---|
| 1945 | 1970 | /* shutdown the thread if there was one */ |
|---|
| 1946 | 1971 | kthread_stop(ca->thread); |
|---|
| 1947 | 1972 | |
|---|