diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2009-09-19 16:13:12 -0400 |
---|---|---|
committer | Live-CD User <linux@linux.site> | 2009-09-19 16:13:12 -0400 |
commit | d13549f804d2965a9f279a8ff867f35d949572c8 (patch) | |
tree | f7e1a6781fe38ffe845e0cfe104e56a0efa309bb /drivers/char | |
parent | 1607acaec38319c5e0b48a3586c00e667e920a0d (diff) |
cyclades: add tty refcounting
While this is not problem for Y card handlers (they are protected
by card_lock), Z handlers and other functions may dereference NULL
at any point after hangup/close. Even if (tty == NULL) was already
performed in the handler.
Note that it's not an issue for Y cards just for now. After
switching to tty_port_close_* et al. this will be a problem. So
add refcounting to them all.
Also proc .show doesn't take a tty reference and it should (along
with a ldisc one).
While at it and changing prototypes (adding tty param), prepend
cy_ to functions which don't have it yet.
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/cyclades.c | 172 |
1 files changed, 93 insertions, 79 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 2dafc2da0648..e2f731b70763 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -850,7 +850,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); | |||
850 | #endif | 850 | #endif |
851 | 851 | ||
852 | static void cy_start(struct tty_struct *); | 852 | static void cy_start(struct tty_struct *); |
853 | static void set_line_char(struct cyclades_port *); | 853 | static void cy_set_line_char(struct cyclades_port *, struct tty_struct *); |
854 | static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); | 854 | static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); |
855 | #ifdef CONFIG_ISA | 855 | #ifdef CONFIG_ISA |
856 | static unsigned detect_isa_irq(void __iomem *); | 856 | static unsigned detect_isa_irq(void __iomem *); |
@@ -1011,8 +1011,9 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
1011 | save_car = readb(base_addr + (CyCAR << index)); | 1011 | save_car = readb(base_addr + (CyCAR << index)); |
1012 | cy_writeb(base_addr + (CyCAR << index), save_xir); | 1012 | cy_writeb(base_addr + (CyCAR << index), save_xir); |
1013 | 1013 | ||
1014 | tty = tty_port_tty_get(&info->port); | ||
1014 | /* if there is nowhere to put the data, discard it */ | 1015 | /* if there is nowhere to put the data, discard it */ |
1015 | if (info->port.tty == NULL) { | 1016 | if (tty == NULL) { |
1016 | if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == | 1017 | if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == |
1017 | CyIVRRxEx) { /* exception */ | 1018 | CyIVRRxEx) { /* exception */ |
1018 | data = readb(base_addr + (CyRDSR << index)); | 1019 | data = readb(base_addr + (CyRDSR << index)); |
@@ -1024,7 +1025,6 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
1024 | goto end; | 1025 | goto end; |
1025 | } | 1026 | } |
1026 | /* there is an open port for this data */ | 1027 | /* there is an open port for this data */ |
1027 | tty = info->port.tty; | ||
1028 | if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == | 1028 | if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) == |
1029 | CyIVRRxEx) { /* exception */ | 1029 | CyIVRRxEx) { /* exception */ |
1030 | data = readb(base_addr + (CyRDSR << index)); | 1030 | data = readb(base_addr + (CyRDSR << index)); |
@@ -1041,6 +1041,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
1041 | 1041 | ||
1042 | if (data & info->ignore_status_mask) { | 1042 | if (data & info->ignore_status_mask) { |
1043 | info->icount.rx++; | 1043 | info->icount.rx++; |
1044 | tty_kref_put(tty); | ||
1044 | return; | 1045 | return; |
1045 | } | 1046 | } |
1046 | if (tty_buffer_request_room(tty, 1)) { | 1047 | if (tty_buffer_request_room(tty, 1)) { |
@@ -1121,6 +1122,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
1121 | info->idle_stats.recv_idle = jiffies; | 1122 | info->idle_stats.recv_idle = jiffies; |
1122 | } | 1123 | } |
1123 | tty_schedule_flip(tty); | 1124 | tty_schedule_flip(tty); |
1125 | tty_kref_put(tty); | ||
1124 | end: | 1126 | end: |
1125 | /* end of service */ | 1127 | /* end of service */ |
1126 | cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f); | 1128 | cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f); |
@@ -1131,6 +1133,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, | |||
1131 | void __iomem *base_addr) | 1133 | void __iomem *base_addr) |
1132 | { | 1134 | { |
1133 | struct cyclades_port *info; | 1135 | struct cyclades_port *info; |
1136 | struct tty_struct *tty; | ||
1134 | int char_count, index = cinfo->bus_index; | 1137 | int char_count, index = cinfo->bus_index; |
1135 | u8 save_xir, channel, save_car, outch; | 1138 | u8 save_xir, channel, save_car, outch; |
1136 | 1139 | ||
@@ -1154,7 +1157,8 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, | |||
1154 | goto end; | 1157 | goto end; |
1155 | } | 1158 | } |
1156 | info = &cinfo->ports[channel + chip * 4]; | 1159 | info = &cinfo->ports[channel + chip * 4]; |
1157 | if (info->port.tty == NULL) { | 1160 | tty = tty_port_tty_get(&info->port); |
1161 | if (tty == NULL) { | ||
1158 | cy_writeb(base_addr + (CySRER << index), | 1162 | cy_writeb(base_addr + (CySRER << index), |
1159 | readb(base_addr + (CySRER << index)) & ~CyTxRdy); | 1163 | readb(base_addr + (CySRER << index)) & ~CyTxRdy); |
1160 | goto end; | 1164 | goto end; |
@@ -1205,7 +1209,7 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, | |||
1205 | ~CyTxRdy); | 1209 | ~CyTxRdy); |
1206 | goto done; | 1210 | goto done; |
1207 | } | 1211 | } |
1208 | if (info->port.tty->stopped || info->port.tty->hw_stopped) { | 1212 | if (tty->stopped || tty->hw_stopped) { |
1209 | cy_writeb(base_addr + (CySRER << index), | 1213 | cy_writeb(base_addr + (CySRER << index), |
1210 | readb(base_addr + (CySRER << index)) & | 1214 | readb(base_addr + (CySRER << index)) & |
1211 | ~CyTxRdy); | 1215 | ~CyTxRdy); |
@@ -1241,7 +1245,8 @@ static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, | |||
1241 | } | 1245 | } |
1242 | 1246 | ||
1243 | done: | 1247 | done: |
1244 | tty_wakeup(info->port.tty); | 1248 | tty_wakeup(tty); |
1249 | tty_kref_put(tty); | ||
1245 | end: | 1250 | end: |
1246 | /* end of service */ | 1251 | /* end of service */ |
1247 | cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f); | 1252 | cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f); |
@@ -1252,6 +1257,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | |||
1252 | void __iomem *base_addr) | 1257 | void __iomem *base_addr) |
1253 | { | 1258 | { |
1254 | struct cyclades_port *info; | 1259 | struct cyclades_port *info; |
1260 | struct tty_struct *tty; | ||
1255 | int index = cinfo->bus_index; | 1261 | int index = cinfo->bus_index; |
1256 | u8 save_xir, channel, save_car, mdm_change, mdm_status; | 1262 | u8 save_xir, channel, save_car, mdm_change, mdm_status; |
1257 | 1263 | ||
@@ -1265,7 +1271,8 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | |||
1265 | mdm_change = readb(base_addr + (CyMISR << index)); | 1271 | mdm_change = readb(base_addr + (CyMISR << index)); |
1266 | mdm_status = readb(base_addr + (CyMSVR1 << index)); | 1272 | mdm_status = readb(base_addr + (CyMSVR1 << index)); |
1267 | 1273 | ||
1268 | if (!info->port.tty) | 1274 | tty = tty_port_tty_get(&info->port); |
1275 | if (!tty) | ||
1269 | goto end; | 1276 | goto end; |
1270 | 1277 | ||
1271 | if (mdm_change & CyANY_DELTA) { | 1278 | if (mdm_change & CyANY_DELTA) { |
@@ -1284,27 +1291,27 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | |||
1284 | 1291 | ||
1285 | if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { | 1292 | if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { |
1286 | if (!(mdm_status & CyDCD)) { | 1293 | if (!(mdm_status & CyDCD)) { |
1287 | tty_hangup(info->port.tty); | 1294 | tty_hangup(tty); |
1288 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1295 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1289 | } | 1296 | } |
1290 | wake_up_interruptible(&info->port.open_wait); | 1297 | wake_up_interruptible(&info->port.open_wait); |
1291 | } | 1298 | } |
1292 | if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { | 1299 | if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { |
1293 | if (info->port.tty->hw_stopped) { | 1300 | if (tty->hw_stopped) { |
1294 | if (mdm_status & CyCTS) { | 1301 | if (mdm_status & CyCTS) { |
1295 | /* cy_start isn't used | 1302 | /* cy_start isn't used |
1296 | because... !!! */ | 1303 | because... !!! */ |
1297 | info->port.tty->hw_stopped = 0; | 1304 | tty->hw_stopped = 0; |
1298 | cy_writeb(base_addr + (CySRER << index), | 1305 | cy_writeb(base_addr + (CySRER << index), |
1299 | readb(base_addr + (CySRER << index)) | | 1306 | readb(base_addr + (CySRER << index)) | |
1300 | CyTxRdy); | 1307 | CyTxRdy); |
1301 | tty_wakeup(info->port.tty); | 1308 | tty_wakeup(tty); |
1302 | } | 1309 | } |
1303 | } else { | 1310 | } else { |
1304 | if (!(mdm_status & CyCTS)) { | 1311 | if (!(mdm_status & CyCTS)) { |
1305 | /* cy_stop isn't used | 1312 | /* cy_stop isn't used |
1306 | because ... !!! */ | 1313 | because ... !!! */ |
1307 | info->port.tty->hw_stopped = 1; | 1314 | tty->hw_stopped = 1; |
1308 | cy_writeb(base_addr + (CySRER << index), | 1315 | cy_writeb(base_addr + (CySRER << index), |
1309 | readb(base_addr + (CySRER << index)) & | 1316 | readb(base_addr + (CySRER << index)) & |
1310 | ~CyTxRdy); | 1317 | ~CyTxRdy); |
@@ -1315,6 +1322,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | |||
1315 | } | 1322 | } |
1316 | if (mdm_change & CyRI) { | 1323 | if (mdm_change & CyRI) { |
1317 | }*/ | 1324 | }*/ |
1325 | tty_kref_put(tty); | ||
1318 | end: | 1326 | end: |
1319 | /* end of service */ | 1327 | /* end of service */ |
1320 | cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f); | 1328 | cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f); |
@@ -1449,11 +1457,10 @@ cyz_issue_cmd(struct cyclades_card *cinfo, | |||
1449 | return 0; | 1457 | return 0; |
1450 | } /* cyz_issue_cmd */ | 1458 | } /* cyz_issue_cmd */ |
1451 | 1459 | ||
1452 | static void cyz_handle_rx(struct cyclades_port *info, | 1460 | static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty, |
1453 | struct BUF_CTRL __iomem *buf_ctrl) | 1461 | struct BUF_CTRL __iomem *buf_ctrl) |
1454 | { | 1462 | { |
1455 | struct cyclades_card *cinfo = info->card; | 1463 | struct cyclades_card *cinfo = info->card; |
1456 | struct tty_struct *tty = info->port.tty; | ||
1457 | unsigned int char_count; | 1464 | unsigned int char_count; |
1458 | int len; | 1465 | int len; |
1459 | #ifdef BLOCKMOVE | 1466 | #ifdef BLOCKMOVE |
@@ -1542,11 +1549,10 @@ static void cyz_handle_rx(struct cyclades_port *info, | |||
1542 | } | 1549 | } |
1543 | } | 1550 | } |
1544 | 1551 | ||
1545 | static void cyz_handle_tx(struct cyclades_port *info, | 1552 | static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty, |
1546 | struct BUF_CTRL __iomem *buf_ctrl) | 1553 | struct BUF_CTRL __iomem *buf_ctrl) |
1547 | { | 1554 | { |
1548 | struct cyclades_card *cinfo = info->card; | 1555 | struct cyclades_card *cinfo = info->card; |
1549 | struct tty_struct *tty = info->port.tty; | ||
1550 | u8 data; | 1556 | u8 data; |
1551 | unsigned int char_count; | 1557 | unsigned int char_count; |
1552 | #ifdef BLOCKMOVE | 1558 | #ifdef BLOCKMOVE |
@@ -1642,7 +1648,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1642 | special_count = 0; | 1648 | special_count = 0; |
1643 | delta_count = 0; | 1649 | delta_count = 0; |
1644 | info = &cinfo->ports[channel]; | 1650 | info = &cinfo->ports[channel]; |
1645 | tty = info->port.tty; | 1651 | tty = tty_port_tty_get(&info->port); |
1646 | if (tty == NULL) | 1652 | if (tty == NULL) |
1647 | continue; | 1653 | continue; |
1648 | 1654 | ||
@@ -1674,7 +1680,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1674 | C_RS_DCD) { | 1680 | C_RS_DCD) { |
1675 | wake_up_interruptible(&info->port.open_wait); | 1681 | wake_up_interruptible(&info->port.open_wait); |
1676 | } else { | 1682 | } else { |
1677 | tty_hangup(info->port.tty); | 1683 | tty_hangup(tty); |
1678 | wake_up_interruptible(&info->port.open_wait); | 1684 | wake_up_interruptible(&info->port.open_wait); |
1679 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1685 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
1680 | } | 1686 | } |
@@ -1706,7 +1712,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1706 | printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " | 1712 | printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " |
1707 | "port %ld\n", info->card, channel); | 1713 | "port %ld\n", info->card, channel); |
1708 | #endif | 1714 | #endif |
1709 | cyz_handle_rx(info, buf_ctrl); | 1715 | cyz_handle_rx(info, tty, buf_ctrl); |
1710 | break; | 1716 | break; |
1711 | case C_CM_TXBEMPTY: | 1717 | case C_CM_TXBEMPTY: |
1712 | case C_CM_TXLOWWM: | 1718 | case C_CM_TXLOWWM: |
@@ -1716,7 +1722,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1716 | printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " | 1722 | printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " |
1717 | "port %ld\n", info->card, channel); | 1723 | "port %ld\n", info->card, channel); |
1718 | #endif | 1724 | #endif |
1719 | cyz_handle_tx(info, buf_ctrl); | 1725 | cyz_handle_tx(info, tty, buf_ctrl); |
1720 | break; | 1726 | break; |
1721 | #endif /* CONFIG_CYZ_INTR */ | 1727 | #endif /* CONFIG_CYZ_INTR */ |
1722 | case C_CM_FATAL: | 1728 | case C_CM_FATAL: |
@@ -1729,6 +1735,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1729 | wake_up_interruptible(&info->delta_msr_wait); | 1735 | wake_up_interruptible(&info->delta_msr_wait); |
1730 | if (special_count) | 1736 | if (special_count) |
1731 | tty_schedule_flip(tty); | 1737 | tty_schedule_flip(tty); |
1738 | tty_kref_put(tty); | ||
1732 | } | 1739 | } |
1733 | } | 1740 | } |
1734 | 1741 | ||
@@ -1774,7 +1781,6 @@ static void cyz_poll(unsigned long arg) | |||
1774 | { | 1781 | { |
1775 | struct cyclades_card *cinfo; | 1782 | struct cyclades_card *cinfo; |
1776 | struct cyclades_port *info; | 1783 | struct cyclades_port *info; |
1777 | struct tty_struct *tty; | ||
1778 | struct FIRM_ID __iomem *firm_id; | 1784 | struct FIRM_ID __iomem *firm_id; |
1779 | struct ZFW_CTRL __iomem *zfw_ctrl; | 1785 | struct ZFW_CTRL __iomem *zfw_ctrl; |
1780 | struct BUF_CTRL __iomem *buf_ctrl; | 1786 | struct BUF_CTRL __iomem *buf_ctrl; |
@@ -1802,13 +1808,19 @@ static void cyz_poll(unsigned long arg) | |||
1802 | cyz_handle_cmd(cinfo); | 1808 | cyz_handle_cmd(cinfo); |
1803 | 1809 | ||
1804 | for (port = 0; port < cinfo->nports; port++) { | 1810 | for (port = 0; port < cinfo->nports; port++) { |
1811 | struct tty_struct *tty; | ||
1812 | |||
1805 | info = &cinfo->ports[port]; | 1813 | info = &cinfo->ports[port]; |
1806 | tty = info->port.tty; | ||
1807 | buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); | 1814 | buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); |
1808 | 1815 | ||
1816 | tty = tty_port_tty_get(&info->port); | ||
1817 | /* OK to pass NULL to the handle functions below. | ||
1818 | They need to drop the data in that case. */ | ||
1819 | |||
1809 | if (!info->throttle) | 1820 | if (!info->throttle) |
1810 | cyz_handle_rx(info, buf_ctrl); | 1821 | cyz_handle_rx(info, tty, buf_ctrl); |
1811 | cyz_handle_tx(info, buf_ctrl); | 1822 | cyz_handle_tx(info, tty, buf_ctrl); |
1823 | tty_kref_put(tty); | ||
1812 | } | 1824 | } |
1813 | /* poll every 'cyz_polling_cycle' period */ | 1825 | /* poll every 'cyz_polling_cycle' period */ |
1814 | expires = jiffies + cyz_polling_cycle; | 1826 | expires = jiffies + cyz_polling_cycle; |
@@ -1824,7 +1836,7 @@ static void cyz_poll(unsigned long arg) | |||
1824 | /* This is called whenever a port becomes active; | 1836 | /* This is called whenever a port becomes active; |
1825 | interrupts are enabled and DTR & RTS are turned on. | 1837 | interrupts are enabled and DTR & RTS are turned on. |
1826 | */ | 1838 | */ |
1827 | static int startup(struct cyclades_port *info) | 1839 | static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) |
1828 | { | 1840 | { |
1829 | struct cyclades_card *card; | 1841 | struct cyclades_card *card; |
1830 | unsigned long flags; | 1842 | unsigned long flags; |
@@ -1848,8 +1860,7 @@ static int startup(struct cyclades_port *info) | |||
1848 | } | 1860 | } |
1849 | 1861 | ||
1850 | if (!info->type) { | 1862 | if (!info->type) { |
1851 | if (info->port.tty) | 1863 | set_bit(TTY_IO_ERROR, &tty->flags); |
1852 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1853 | free_page(page); | 1864 | free_page(page); |
1854 | goto errout; | 1865 | goto errout; |
1855 | } | 1866 | } |
@@ -1861,7 +1872,7 @@ static int startup(struct cyclades_port *info) | |||
1861 | 1872 | ||
1862 | spin_unlock_irqrestore(&card->card_lock, flags); | 1873 | spin_unlock_irqrestore(&card->card_lock, flags); |
1863 | 1874 | ||
1864 | set_line_char(info); | 1875 | cy_set_line_char(info, tty); |
1865 | 1876 | ||
1866 | if (!cy_is_Z(card)) { | 1877 | if (!cy_is_Z(card)) { |
1867 | chip = channel >> 2; | 1878 | chip = channel >> 2; |
@@ -1900,8 +1911,7 @@ static int startup(struct cyclades_port *info) | |||
1900 | readb(base_addr + (CySRER << index)) | CyRxData); | 1911 | readb(base_addr + (CySRER << index)) | CyRxData); |
1901 | info->port.flags |= ASYNC_INITIALIZED; | 1912 | info->port.flags |= ASYNC_INITIALIZED; |
1902 | 1913 | ||
1903 | if (info->port.tty) | 1914 | clear_bit(TTY_IO_ERROR, &tty->flags); |
1904 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1905 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | 1915 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
1906 | info->breakon = info->breakoff = 0; | 1916 | info->breakon = info->breakoff = 0; |
1907 | memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); | 1917 | memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); |
@@ -1984,8 +1994,7 @@ static int startup(struct cyclades_port *info) | |||
1984 | /* enable send, recv, modem !!! */ | 1994 | /* enable send, recv, modem !!! */ |
1985 | 1995 | ||
1986 | info->port.flags |= ASYNC_INITIALIZED; | 1996 | info->port.flags |= ASYNC_INITIALIZED; |
1987 | if (info->port.tty) | 1997 | clear_bit(TTY_IO_ERROR, &tty->flags); |
1988 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1989 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | 1998 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
1990 | info->breakon = info->breakoff = 0; | 1999 | info->breakon = info->breakoff = 0; |
1991 | memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); | 2000 | memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); |
@@ -2047,7 +2056,7 @@ static void start_xmit(struct cyclades_port *info) | |||
2047 | * This routine shuts down a serial port; interrupts are disabled, | 2056 | * This routine shuts down a serial port; interrupts are disabled, |
2048 | * and DTR is dropped if the hangup on close termio flag is on. | 2057 | * and DTR is dropped if the hangup on close termio flag is on. |
2049 | */ | 2058 | */ |
2050 | static void shutdown(struct cyclades_port *info) | 2059 | static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) |
2051 | { | 2060 | { |
2052 | struct cyclades_card *card; | 2061 | struct cyclades_card *card; |
2053 | unsigned long flags; | 2062 | unsigned long flags; |
@@ -2083,7 +2092,7 @@ static void shutdown(struct cyclades_port *info) | |||
2083 | free_page((unsigned long)temp); | 2092 | free_page((unsigned long)temp); |
2084 | } | 2093 | } |
2085 | cy_writeb(base_addr + (CyCAR << index), (u_char) channel); | 2094 | cy_writeb(base_addr + (CyCAR << index), (u_char) channel); |
2086 | if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { | 2095 | if (tty->termios->c_cflag & HUPCL) { |
2087 | cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); | 2096 | cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS); |
2088 | cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); | 2097 | cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR); |
2089 | #ifdef CY_DEBUG_DTR | 2098 | #ifdef CY_DEBUG_DTR |
@@ -2097,8 +2106,7 @@ static void shutdown(struct cyclades_port *info) | |||
2097 | /* it may be appropriate to clear _XMIT at | 2106 | /* it may be appropriate to clear _XMIT at |
2098 | some later date (after testing)!!! */ | 2107 | some later date (after testing)!!! */ |
2099 | 2108 | ||
2100 | if (info->port.tty) | 2109 | set_bit(TTY_IO_ERROR, &tty->flags); |
2101 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2102 | info->port.flags &= ~ASYNC_INITIALIZED; | 2110 | info->port.flags &= ~ASYNC_INITIALIZED; |
2103 | spin_unlock_irqrestore(&card->card_lock, flags); | 2111 | spin_unlock_irqrestore(&card->card_lock, flags); |
2104 | } else { | 2112 | } else { |
@@ -2132,7 +2140,7 @@ static void shutdown(struct cyclades_port *info) | |||
2132 | free_page((unsigned long)temp); | 2140 | free_page((unsigned long)temp); |
2133 | } | 2141 | } |
2134 | 2142 | ||
2135 | if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { | 2143 | if (tty->termios->c_cflag & HUPCL) { |
2136 | cy_writel(&ch_ctrl[channel].rs_control, | 2144 | cy_writel(&ch_ctrl[channel].rs_control, |
2137 | (__u32)(readl(&ch_ctrl[channel].rs_control) & | 2145 | (__u32)(readl(&ch_ctrl[channel].rs_control) & |
2138 | ~(C_RS_RTS | C_RS_DTR))); | 2146 | ~(C_RS_RTS | C_RS_DTR))); |
@@ -2147,8 +2155,7 @@ static void shutdown(struct cyclades_port *info) | |||
2147 | #endif | 2155 | #endif |
2148 | } | 2156 | } |
2149 | 2157 | ||
2150 | if (info->port.tty) | 2158 | set_bit(TTY_IO_ERROR, &tty->flags); |
2151 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2152 | info->port.flags &= ~ASYNC_INITIALIZED; | 2159 | info->port.flags &= ~ASYNC_INITIALIZED; |
2153 | 2160 | ||
2154 | spin_unlock_irqrestore(&card->card_lock, flags); | 2161 | spin_unlock_irqrestore(&card->card_lock, flags); |
@@ -2436,7 +2443,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp) | |||
2436 | printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); | 2443 | printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); |
2437 | #endif | 2444 | #endif |
2438 | tty->driver_data = info; | 2445 | tty->driver_data = info; |
2439 | info->port.tty = tty; | ||
2440 | if (serial_paranoia_check(info, tty->name, "cy_open")) | 2446 | if (serial_paranoia_check(info, tty->name, "cy_open")) |
2441 | return -ENODEV; | 2447 | return -ENODEV; |
2442 | 2448 | ||
@@ -2462,7 +2468,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) | |||
2462 | /* | 2468 | /* |
2463 | * Start up serial port | 2469 | * Start up serial port |
2464 | */ | 2470 | */ |
2465 | retval = startup(info); | 2471 | retval = cy_startup(info, tty); |
2466 | if (retval) | 2472 | if (retval) |
2467 | return retval; | 2473 | return retval; |
2468 | 2474 | ||
@@ -2476,6 +2482,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) | |||
2476 | } | 2482 | } |
2477 | 2483 | ||
2478 | info->throttle = 0; | 2484 | info->throttle = 0; |
2485 | tty_port_tty_set(&info->port, tty); | ||
2479 | 2486 | ||
2480 | #ifdef CY_DEBUG_OPEN | 2487 | #ifdef CY_DEBUG_OPEN |
2481 | printk(KERN_DEBUG "cyc:cy_open done\n"); | 2488 | printk(KERN_DEBUG "cyc:cy_open done\n"); |
@@ -2705,13 +2712,13 @@ static void cy_close(struct tty_struct *tty, struct file *filp) | |||
2705 | } | 2712 | } |
2706 | 2713 | ||
2707 | spin_unlock_irqrestore(&card->card_lock, flags); | 2714 | spin_unlock_irqrestore(&card->card_lock, flags); |
2708 | shutdown(info); | 2715 | cy_shutdown(info, tty); |
2709 | cy_flush_buffer(tty); | 2716 | cy_flush_buffer(tty); |
2710 | tty_ldisc_flush(tty); | 2717 | tty_ldisc_flush(tty); |
2711 | spin_lock_irqsave(&card->card_lock, flags); | 2718 | spin_lock_irqsave(&card->card_lock, flags); |
2712 | 2719 | ||
2713 | tty->closing = 0; | 2720 | tty->closing = 0; |
2714 | info->port.tty = NULL; | 2721 | tty_port_tty_set(&info->port, NULL); |
2715 | if (info->port.blocked_open) { | 2722 | if (info->port.blocked_open) { |
2716 | spin_unlock_irqrestore(&card->card_lock, flags); | 2723 | spin_unlock_irqrestore(&card->card_lock, flags); |
2717 | if (info->port.close_delay) { | 2724 | if (info->port.close_delay) { |
@@ -2957,7 +2964,7 @@ static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) | |||
2957 | * This routine finds or computes the various line characteristics. | 2964 | * This routine finds or computes the various line characteristics. |
2958 | * It used to be called config_setup | 2965 | * It used to be called config_setup |
2959 | */ | 2966 | */ |
2960 | static void set_line_char(struct cyclades_port *info) | 2967 | static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) |
2961 | { | 2968 | { |
2962 | struct cyclades_card *card; | 2969 | struct cyclades_card *card; |
2963 | unsigned long flags; | 2970 | unsigned long flags; |
@@ -2967,28 +2974,26 @@ static void set_line_char(struct cyclades_port *info) | |||
2967 | int baud, baud_rate = 0; | 2974 | int baud, baud_rate = 0; |
2968 | int i; | 2975 | int i; |
2969 | 2976 | ||
2970 | if (!info->port.tty || !info->port.tty->termios) | 2977 | if (!tty->termios) /* XXX can this happen at all? */ |
2971 | return; | 2978 | return; |
2972 | 2979 | ||
2973 | if (info->line == -1) | 2980 | if (info->line == -1) |
2974 | return; | 2981 | return; |
2975 | 2982 | ||
2976 | cflag = info->port.tty->termios->c_cflag; | 2983 | cflag = tty->termios->c_cflag; |
2977 | iflag = info->port.tty->termios->c_iflag; | 2984 | iflag = tty->termios->c_iflag; |
2978 | 2985 | ||
2979 | /* | 2986 | /* |
2980 | * Set up the tty->alt_speed kludge | 2987 | * Set up the tty->alt_speed kludge |
2981 | */ | 2988 | */ |
2982 | if (info->port.tty) { | 2989 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) |
2983 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | 2990 | tty->alt_speed = 57600; |
2984 | info->port.tty->alt_speed = 57600; | 2991 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) |
2985 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | 2992 | tty->alt_speed = 115200; |
2986 | info->port.tty->alt_speed = 115200; | 2993 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) |
2987 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | 2994 | tty->alt_speed = 230400; |
2988 | info->port.tty->alt_speed = 230400; | 2995 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) |
2989 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | 2996 | tty->alt_speed = 460800; |
2990 | info->port.tty->alt_speed = 460800; | ||
2991 | } | ||
2992 | 2997 | ||
2993 | card = info->card; | 2998 | card = info->card; |
2994 | channel = info->line - card->first_line; | 2999 | channel = info->line - card->first_line; |
@@ -2998,7 +3003,7 @@ static void set_line_char(struct cyclades_port *info) | |||
2998 | index = card->bus_index; | 3003 | index = card->bus_index; |
2999 | 3004 | ||
3000 | /* baud rate */ | 3005 | /* baud rate */ |
3001 | baud = tty_get_baud_rate(info->port.tty); | 3006 | baud = tty_get_baud_rate(tty); |
3002 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | 3007 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == |
3003 | ASYNC_SPD_CUST) { | 3008 | ASYNC_SPD_CUST) { |
3004 | if (info->custom_divisor) | 3009 | if (info->custom_divisor) |
@@ -3123,9 +3128,8 @@ static void set_line_char(struct cyclades_port *info) | |||
3123 | 3128 | ||
3124 | /* set line characteristics according configuration */ | 3129 | /* set line characteristics according configuration */ |
3125 | 3130 | ||
3126 | cy_writeb(base_addr + (CySCHR1 << index), | 3131 | cy_writeb(base_addr + (CySCHR1 << index), START_CHAR(tty)); |
3127 | START_CHAR(info->port.tty)); | 3132 | cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(tty)); |
3128 | cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->port.tty)); | ||
3129 | cy_writeb(base_addr + (CyCOR1 << index), info->cor1); | 3133 | cy_writeb(base_addr + (CyCOR1 << index), info->cor1); |
3130 | cy_writeb(base_addr + (CyCOR2 << index), info->cor2); | 3134 | cy_writeb(base_addr + (CyCOR2 << index), info->cor2); |
3131 | cy_writeb(base_addr + (CyCOR3 << index), info->cor3); | 3135 | cy_writeb(base_addr + (CyCOR3 << index), info->cor3); |
@@ -3141,7 +3145,7 @@ static void set_line_char(struct cyclades_port *info) | |||
3141 | (info->default_timeout ? info->default_timeout : 0x02)); | 3145 | (info->default_timeout ? info->default_timeout : 0x02)); |
3142 | /* 10ms rx timeout */ | 3146 | /* 10ms rx timeout */ |
3143 | 3147 | ||
3144 | if (C_CLOCAL(info->port.tty)) { | 3148 | if (C_CLOCAL(tty)) { |
3145 | /* without modem intr */ | 3149 | /* without modem intr */ |
3146 | cy_writeb(base_addr + (CySRER << index), | 3150 | cy_writeb(base_addr + (CySRER << index), |
3147 | readb(base_addr + (CySRER << index)) | CyMdmCh); | 3151 | readb(base_addr + (CySRER << index)) | CyMdmCh); |
@@ -3204,8 +3208,7 @@ static void set_line_char(struct cyclades_port *info) | |||
3204 | #endif | 3208 | #endif |
3205 | } | 3209 | } |
3206 | 3210 | ||
3207 | if (info->port.tty) | 3211 | clear_bit(TTY_IO_ERROR, &tty->flags); |
3208 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
3209 | spin_unlock_irqrestore(&card->card_lock, flags); | 3212 | spin_unlock_irqrestore(&card->card_lock, flags); |
3210 | 3213 | ||
3211 | } else { | 3214 | } else { |
@@ -3224,7 +3227,7 @@ static void set_line_char(struct cyclades_port *info) | |||
3224 | ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); | 3227 | ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); |
3225 | 3228 | ||
3226 | /* baud rate */ | 3229 | /* baud rate */ |
3227 | baud = tty_get_baud_rate(info->port.tty); | 3230 | baud = tty_get_baud_rate(tty); |
3228 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | 3231 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == |
3229 | ASYNC_SPD_CUST) { | 3232 | ASYNC_SPD_CUST) { |
3230 | if (info->custom_divisor) | 3233 | if (info->custom_divisor) |
@@ -3335,8 +3338,7 @@ static void set_line_char(struct cyclades_port *info) | |||
3335 | "was %x\n", info->line, retval); | 3338 | "was %x\n", info->line, retval); |
3336 | } | 3339 | } |
3337 | 3340 | ||
3338 | if (info->port.tty) | 3341 | clear_bit(TTY_IO_ERROR, &tty->flags); |
3339 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
3340 | } | 3342 | } |
3341 | } /* set_line_char */ | 3343 | } /* set_line_char */ |
3342 | 3344 | ||
@@ -3365,7 +3367,7 @@ get_serial_info(struct cyclades_port *info, | |||
3365 | } /* get_serial_info */ | 3367 | } /* get_serial_info */ |
3366 | 3368 | ||
3367 | static int | 3369 | static int |
3368 | set_serial_info(struct cyclades_port *info, | 3370 | cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, |
3369 | struct serial_struct __user *new_info) | 3371 | struct serial_struct __user *new_info) |
3370 | { | 3372 | { |
3371 | struct serial_struct new_serial; | 3373 | struct serial_struct new_serial; |
@@ -3403,10 +3405,10 @@ set_serial_info(struct cyclades_port *info, | |||
3403 | 3405 | ||
3404 | check_and_exit: | 3406 | check_and_exit: |
3405 | if (info->port.flags & ASYNC_INITIALIZED) { | 3407 | if (info->port.flags & ASYNC_INITIALIZED) { |
3406 | set_line_char(info); | 3408 | cy_set_line_char(info, tty); |
3407 | return 0; | 3409 | return 0; |
3408 | } else { | 3410 | } else { |
3409 | return startup(info); | 3411 | return cy_startup(info, tty); |
3410 | } | 3412 | } |
3411 | } /* set_serial_info */ | 3413 | } /* set_serial_info */ |
3412 | 3414 | ||
@@ -3955,7 +3957,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, | |||
3955 | ret_val = get_serial_info(info, argp); | 3957 | ret_val = get_serial_info(info, argp); |
3956 | break; | 3958 | break; |
3957 | case TIOCSSERIAL: | 3959 | case TIOCSSERIAL: |
3958 | ret_val = set_serial_info(info, argp); | 3960 | ret_val = cy_set_serial_info(info, tty, argp); |
3959 | break; | 3961 | break; |
3960 | case TIOCSERGETLSR: /* Get line status register */ | 3962 | case TIOCSERGETLSR: /* Get line status register */ |
3961 | ret_val = get_lsr_info(info, argp); | 3963 | ret_val = get_lsr_info(info, argp); |
@@ -4055,7 +4057,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | |||
4055 | printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); | 4057 | printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); |
4056 | #endif | 4058 | #endif |
4057 | 4059 | ||
4058 | set_line_char(info); | 4060 | cy_set_line_char(info, tty); |
4059 | 4061 | ||
4060 | if ((old_termios->c_cflag & CRTSCTS) && | 4062 | if ((old_termios->c_cflag & CRTSCTS) && |
4061 | !(tty->termios->c_cflag & CRTSCTS)) { | 4063 | !(tty->termios->c_cflag & CRTSCTS)) { |
@@ -4299,13 +4301,13 @@ static void cy_hangup(struct tty_struct *tty) | |||
4299 | return; | 4301 | return; |
4300 | 4302 | ||
4301 | cy_flush_buffer(tty); | 4303 | cy_flush_buffer(tty); |
4302 | shutdown(info); | 4304 | cy_shutdown(info, tty); |
4303 | info->port.count = 0; | 4305 | info->port.count = 0; |
4304 | #ifdef CY_DEBUG_COUNT | 4306 | #ifdef CY_DEBUG_COUNT |
4305 | printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", | 4307 | printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n", |
4306 | current->pid); | 4308 | current->pid); |
4307 | #endif | 4309 | #endif |
4308 | info->port.tty = NULL; | 4310 | tty_port_tty_set(&info->port, NULL); |
4309 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 4311 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; |
4310 | wake_up_interruptible(&info->port.open_wait); | 4312 | wake_up_interruptible(&info->port.open_wait); |
4311 | } /* cy_hangup */ | 4313 | } /* cy_hangup */ |
@@ -5191,18 +5193,30 @@ static int cyclades_proc_show(struct seq_file *m, void *v) | |||
5191 | for (j = 0; j < cy_card[i].nports; j++) { | 5193 | for (j = 0; j < cy_card[i].nports; j++) { |
5192 | info = &cy_card[i].ports[j]; | 5194 | info = &cy_card[i].ports[j]; |
5193 | 5195 | ||
5194 | if (info->port.count) | 5196 | if (info->port.count) { |
5197 | /* XXX is the ldisc num worth this? */ | ||
5198 | struct tty_struct *tty; | ||
5199 | struct tty_ldisc *ld; | ||
5200 | int num = 0; | ||
5201 | tty = tty_port_tty_get(&info->port); | ||
5202 | if (tty) { | ||
5203 | ld = tty_ldisc_ref(tty); | ||
5204 | if (ld) { | ||
5205 | num = ld->ops->num; | ||
5206 | tty_ldisc_deref(ld); | ||
5207 | } | ||
5208 | tty_kref_put(tty); | ||
5209 | } | ||
5195 | seq_printf(m, "%3d %8lu %10lu %8lu " | 5210 | seq_printf(m, "%3d %8lu %10lu %8lu " |
5196 | "%10lu %8lu %9lu %6ld\n", info->line, | 5211 | "%10lu %8lu %9lu %6d\n", info->line, |
5197 | (cur_jifs - info->idle_stats.in_use) / | 5212 | (cur_jifs - info->idle_stats.in_use) / |
5198 | HZ, info->idle_stats.xmit_bytes, | 5213 | HZ, info->idle_stats.xmit_bytes, |
5199 | (cur_jifs - info->idle_stats.xmit_idle)/ | 5214 | (cur_jifs - info->idle_stats.xmit_idle)/ |
5200 | HZ, info->idle_stats.recv_bytes, | 5215 | HZ, info->idle_stats.recv_bytes, |
5201 | (cur_jifs - info->idle_stats.recv_idle)/ | 5216 | (cur_jifs - info->idle_stats.recv_idle)/ |
5202 | HZ, info->idle_stats.overruns, | 5217 | HZ, info->idle_stats.overruns, |
5203 | /* FIXME: double check locking */ | 5218 | num); |
5204 | (long)info->port.tty->ldisc->ops->num); | 5219 | } else |
5205 | else | ||
5206 | seq_printf(m, "%3d %8lu %10lu %8lu " | 5220 | seq_printf(m, "%3d %8lu %10lu %8lu " |
5207 | "%10lu %8lu %9lu %6ld\n", | 5221 | "%10lu %8lu %9lu %6ld\n", |
5208 | info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); | 5222 | info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); |