diff options
Diffstat (limited to 'drivers/char/cyclades.c')
-rw-r--r-- | drivers/char/cyclades.c | 617 |
1 files changed, 292 insertions, 325 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 817fef3071a..39bfe043fba 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -980,378 +980,342 @@ static unsigned detect_isa_irq(void __iomem * address) | |||
980 | } | 980 | } |
981 | #endif /* CONFIG_ISA */ | 981 | #endif /* CONFIG_ISA */ |
982 | 982 | ||
983 | static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, | 983 | static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, |
984 | void __iomem * base_addr, int status, int index) | 984 | void __iomem *base_addr) |
985 | { | 985 | { |
986 | struct cyclades_port *info; | 986 | struct cyclades_port *info; |
987 | struct tty_struct *tty; | 987 | struct tty_struct *tty; |
988 | int char_count; | 988 | int char_count; |
989 | int j, len, mdm_change, mdm_status, outch; | 989 | int j, len, index = cinfo->bus_index; |
990 | int save_xir, channel, save_car; | 990 | int save_xir, channel, save_car; |
991 | char data; | 991 | char data; |
992 | 992 | ||
993 | if (status & CySRReceive) { /* reception interrupt */ | ||
994 | #ifdef CY_DEBUG_INTERRUPTS | 993 | #ifdef CY_DEBUG_INTERRUPTS |
995 | printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); | 994 | printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); |
996 | #endif | 995 | #endif |
997 | /* determine the channel & change to that context */ | 996 | /* determine the channel & change to that context */ |
998 | spin_lock(&cinfo->card_lock); | 997 | spin_lock(&cinfo->card_lock); |
999 | save_xir = (u_char) readb(base_addr + (CyRIR << index)); | 998 | save_xir = (u_char) readb(base_addr + (CyRIR << index)); |
1000 | channel = (u_short) (save_xir & CyIRChannel); | 999 | channel = (u_short) (save_xir & CyIRChannel); |
1001 | info = &cinfo->ports[channel + chip * 4]; | 1000 | info = &cinfo->ports[channel + chip * 4]; |
1002 | save_car = readb(base_addr + (CyCAR << index)); | 1001 | save_car = readb(base_addr + (CyCAR << index)); |
1003 | cy_writeb(base_addr + (CyCAR << index), save_xir); | 1002 | cy_writeb(base_addr + (CyCAR << index), save_xir); |
1004 | 1003 | ||
1005 | /* if there is nowhere to put the data, discard it */ | 1004 | /* if there is nowhere to put the data, discard it */ |
1006 | if (info->tty == NULL) { | 1005 | if (info->tty == NULL) { |
1007 | j = (readb(base_addr + (CyRIVR << index)) & | 1006 | j = (readb(base_addr + (CyRIVR << index)) & CyIVRMask); |
1008 | CyIVRMask); | 1007 | if (j == CyIVRRxEx) { /* exception */ |
1009 | if (j == CyIVRRxEx) { /* exception */ | 1008 | data = readb(base_addr + (CyRDSR << index)); |
1010 | data = readb(base_addr + (CyRDSR << index)); | 1009 | } else { /* normal character reception */ |
1011 | } else { /* normal character reception */ | 1010 | char_count = readb(base_addr + (CyRDCR << index)); |
1012 | char_count = readb(base_addr + | 1011 | while (char_count--) |
1013 | (CyRDCR << index)); | ||
1014 | while (char_count--) { | ||
1015 | data = readb(base_addr + | ||
1016 | (CyRDSR << index)); | ||
1017 | } | ||
1018 | } | ||
1019 | } else { /* there is an open port for this data */ | ||
1020 | tty = info->tty; | ||
1021 | j = (readb(base_addr + (CyRIVR << index)) & | ||
1022 | CyIVRMask); | ||
1023 | if (j == CyIVRRxEx) { /* exception */ | ||
1024 | data = readb(base_addr + (CyRDSR << index)); | 1012 | data = readb(base_addr + (CyRDSR << index)); |
1025 | 1013 | } | |
1026 | /* For statistics only */ | 1014 | goto end; |
1027 | if (data & CyBREAK) | 1015 | } |
1028 | info->icount.brk++; | 1016 | /* there is an open port for this data */ |
1029 | else if (data & CyFRAME) | 1017 | tty = info->tty; |
1030 | info->icount.frame++; | 1018 | j = readb(base_addr + (CyRIVR << index)) & CyIVRMask; |
1031 | else if (data & CyPARITY) | 1019 | if (j == CyIVRRxEx) { /* exception */ |
1032 | info->icount.parity++; | 1020 | data = readb(base_addr + (CyRDSR << index)); |
1033 | else if (data & CyOVERRUN) | 1021 | |
1034 | info->icount.overrun++; | 1022 | /* For statistics only */ |
1035 | 1023 | if (data & CyBREAK) | |
1036 | if (data & info->ignore_status_mask) { | 1024 | info->icount.brk++; |
1025 | else if (data & CyFRAME) | ||
1026 | info->icount.frame++; | ||
1027 | else if (data & CyPARITY) | ||
1028 | info->icount.parity++; | ||
1029 | else if (data & CyOVERRUN) | ||
1030 | info->icount.overrun++; | ||
1031 | |||
1032 | if (data & info->ignore_status_mask) { | ||
1033 | info->icount.rx++; | ||
1034 | spin_unlock(&cinfo->card_lock); | ||
1035 | return; | ||
1036 | } | ||
1037 | if (tty_buffer_request_room(tty, 1)) { | ||
1038 | if (data & info->read_status_mask) { | ||
1039 | if (data & CyBREAK) { | ||
1040 | tty_insert_flip_char(tty, | ||
1041 | readb(base_addr + (CyRDSR << | ||
1042 | index)), TTY_BREAK); | ||
1043 | info->icount.rx++; | ||
1044 | if (info->flags & ASYNC_SAK) | ||
1045 | do_SAK(tty); | ||
1046 | } else if (data & CyFRAME) { | ||
1047 | tty_insert_flip_char( tty, | ||
1048 | readb(base_addr + (CyRDSR << | ||
1049 | index)), TTY_FRAME); | ||
1050 | info->icount.rx++; | ||
1051 | info->idle_stats.frame_errs++; | ||
1052 | } else if (data & CyPARITY) { | ||
1053 | /* Pieces of seven... */ | ||
1054 | tty_insert_flip_char(tty, | ||
1055 | readb(base_addr + (CyRDSR << | ||
1056 | index)), TTY_PARITY); | ||
1057 | info->icount.rx++; | ||
1058 | info->idle_stats.parity_errs++; | ||
1059 | } else if (data & CyOVERRUN) { | ||
1060 | tty_insert_flip_char(tty, 0, | ||
1061 | TTY_OVERRUN); | ||
1062 | info->icount.rx++; | ||
1063 | /* If the flip buffer itself is | ||
1064 | overflowing, we still lose | ||
1065 | the next incoming character. | ||
1066 | */ | ||
1067 | tty_insert_flip_char(tty, | ||
1068 | readb(base_addr + (CyRDSR << | ||
1069 | index)), TTY_FRAME); | ||
1037 | info->icount.rx++; | 1070 | info->icount.rx++; |
1038 | spin_unlock(&cinfo->card_lock); | ||
1039 | return; | ||
1040 | } | ||
1041 | if (tty_buffer_request_room(tty, 1)) { | ||
1042 | if (data & info->read_status_mask) { | ||
1043 | if (data & CyBREAK) { | ||
1044 | tty_insert_flip_char( | ||
1045 | tty, | ||
1046 | readb( | ||
1047 | base_addr + | ||
1048 | (CyRDSR << | ||
1049 | index)), | ||
1050 | TTY_BREAK); | ||
1051 | info->icount.rx++; | ||
1052 | if (info->flags & | ||
1053 | ASYNC_SAK) { | ||
1054 | do_SAK(tty); | ||
1055 | } | ||
1056 | } else if (data & CyFRAME) { | ||
1057 | tty_insert_flip_char( | ||
1058 | tty, | ||
1059 | readb( | ||
1060 | base_addr + | ||
1061 | (CyRDSR << | ||
1062 | index)), | ||
1063 | TTY_FRAME); | ||
1064 | info->icount.rx++; | ||
1065 | info->idle_stats. | ||
1066 | frame_errs++; | ||
1067 | } else if (data & CyPARITY) { | ||
1068 | /* Pieces of seven... */ | ||
1069 | tty_insert_flip_char( | ||
1070 | tty, | ||
1071 | readb( | ||
1072 | base_addr + | ||
1073 | (CyRDSR << | ||
1074 | index)), | ||
1075 | TTY_PARITY); | ||
1076 | info->icount.rx++; | ||
1077 | info->idle_stats. | ||
1078 | parity_errs++; | ||
1079 | } else if (data & CyOVERRUN) { | ||
1080 | tty_insert_flip_char( | ||
1081 | tty, 0, | ||
1082 | TTY_OVERRUN); | ||
1083 | info->icount.rx++; | ||
1084 | /* If the flip buffer itself is | ||
1085 | overflowing, we still lose | ||
1086 | the next incoming character. | ||
1087 | */ | ||
1088 | tty_insert_flip_char( | ||
1089 | tty, | ||
1090 | readb( | ||
1091 | base_addr + | ||
1092 | (CyRDSR << | ||
1093 | index)), | ||
1094 | TTY_FRAME); | ||
1095 | info->icount.rx++; | ||
1096 | info->idle_stats. | ||
1097 | overruns++; | ||
1098 | /* These two conditions may imply */ | ||
1099 | /* a normal read should be done. */ | ||
1100 | /* }else if(data & CyTIMEOUT){ */ | ||
1101 | /* }else if(data & CySPECHAR){ */ | ||
1102 | } else { | ||
1103 | tty_insert_flip_char( | ||
1104 | tty, 0, | ||
1105 | TTY_NORMAL); | ||
1106 | info->icount.rx++; | ||
1107 | } | ||
1108 | } else { | ||
1109 | tty_insert_flip_char(tty, 0, | ||
1110 | TTY_NORMAL); | ||
1111 | info->icount.rx++; | ||
1112 | } | ||
1113 | } else { | ||
1114 | /* there was a software buffer | ||
1115 | overrun and nothing could be | ||
1116 | done about it!!! */ | ||
1117 | info->icount.buf_overrun++; | ||
1118 | info->idle_stats.overruns++; | 1071 | info->idle_stats.overruns++; |
1072 | /* These two conditions may imply */ | ||
1073 | /* a normal read should be done. */ | ||
1074 | /* } else if(data & CyTIMEOUT) { */ | ||
1075 | /* } else if(data & CySPECHAR) { */ | ||
1076 | } else { | ||
1077 | tty_insert_flip_char(tty, 0, | ||
1078 | TTY_NORMAL); | ||
1079 | info->icount.rx++; | ||
1119 | } | 1080 | } |
1120 | } else { /* normal character reception */ | 1081 | } else { |
1121 | /* load # chars available from the chip */ | 1082 | tty_insert_flip_char(tty, 0, TTY_NORMAL); |
1122 | char_count = readb(base_addr + | 1083 | info->icount.rx++; |
1123 | (CyRDCR << index)); | 1084 | } |
1085 | } else { | ||
1086 | /* there was a software buffer overrun and nothing | ||
1087 | * could be done about it!!! */ | ||
1088 | info->icount.buf_overrun++; | ||
1089 | info->idle_stats.overruns++; | ||
1090 | } | ||
1091 | } else { /* normal character reception */ | ||
1092 | /* load # chars available from the chip */ | ||
1093 | char_count = readb(base_addr + (CyRDCR << index)); | ||
1124 | 1094 | ||
1125 | #ifdef CY_ENABLE_MONITORING | 1095 | #ifdef CY_ENABLE_MONITORING |
1126 | ++info->mon.int_count; | 1096 | ++info->mon.int_count; |
1127 | info->mon.char_count += char_count; | 1097 | info->mon.char_count += char_count; |
1128 | if (char_count > info->mon.char_max) | 1098 | if (char_count > info->mon.char_max) |
1129 | info->mon.char_max = char_count; | 1099 | info->mon.char_max = char_count; |
1130 | info->mon.char_last = char_count; | 1100 | info->mon.char_last = char_count; |
1131 | #endif | 1101 | #endif |
1132 | len = tty_buffer_request_room(tty, char_count); | 1102 | len = tty_buffer_request_room(tty, char_count); |
1133 | while (len--) { | 1103 | while (len--) { |
1134 | data = readb(base_addr + | 1104 | data = readb(base_addr + (CyRDSR << index)); |
1135 | (CyRDSR << index)); | 1105 | tty_insert_flip_char(tty, data, TTY_NORMAL); |
1136 | tty_insert_flip_char(tty, data, | 1106 | info->idle_stats.recv_bytes++; |
1137 | TTY_NORMAL); | 1107 | info->icount.rx++; |
1138 | info->idle_stats.recv_bytes++; | ||
1139 | info->icount.rx++; | ||
1140 | #ifdef CY_16Y_HACK | 1108 | #ifdef CY_16Y_HACK |
1141 | udelay(10L); | 1109 | udelay(10L); |
1142 | #endif | 1110 | #endif |
1143 | } | ||
1144 | info->idle_stats.recv_idle = jiffies; | ||
1145 | } | ||
1146 | tty_schedule_flip(tty); | ||
1147 | } | 1111 | } |
1148 | /* end of service */ | 1112 | info->idle_stats.recv_idle = jiffies; |
1149 | cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f)); | ||
1150 | cy_writeb(base_addr + (CyCAR << index), (save_car)); | ||
1151 | spin_unlock(&cinfo->card_lock); | ||
1152 | } | 1113 | } |
1114 | tty_schedule_flip(tty); | ||
1115 | end: | ||
1116 | /* end of service */ | ||
1117 | cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f); | ||
1118 | cy_writeb(base_addr + (CyCAR << index), save_car); | ||
1119 | spin_unlock(&cinfo->card_lock); | ||
1120 | } | ||
1121 | |||
1122 | static void cyy_chip_tx(struct cyclades_card *cinfo, int chip, | ||
1123 | void __iomem *base_addr) | ||
1124 | { | ||
1125 | struct cyclades_port *info; | ||
1126 | int char_count; | ||
1127 | int outch; | ||
1128 | int save_xir, channel, save_car, index = cinfo->bus_index; | ||
1153 | 1129 | ||
1154 | if (status & CySRTransmit) { /* transmission interrupt */ | 1130 | /* Since we only get here when the transmit buffer |
1155 | /* Since we only get here when the transmit buffer | 1131 | is empty, we know we can always stuff a dozen |
1156 | is empty, we know we can always stuff a dozen | 1132 | characters. */ |
1157 | characters. */ | ||
1158 | #ifdef CY_DEBUG_INTERRUPTS | 1133 | #ifdef CY_DEBUG_INTERRUPTS |
1159 | printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); | 1134 | printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); |
1160 | #endif | 1135 | #endif |
1161 | 1136 | ||
1162 | /* determine the channel & change to that context */ | 1137 | /* determine the channel & change to that context */ |
1163 | spin_lock(&cinfo->card_lock); | 1138 | spin_lock(&cinfo->card_lock); |
1164 | save_xir = (u_char) readb(base_addr + (CyTIR << index)); | 1139 | save_xir = (u_char) readb(base_addr + (CyTIR << index)); |
1165 | channel = (u_short) (save_xir & CyIRChannel); | 1140 | channel = (u_short) (save_xir & CyIRChannel); |
1166 | save_car = readb(base_addr + (CyCAR << index)); | 1141 | save_car = readb(base_addr + (CyCAR << index)); |
1167 | cy_writeb(base_addr + (CyCAR << index), save_xir); | 1142 | cy_writeb(base_addr + (CyCAR << index), save_xir); |
1168 | 1143 | ||
1169 | /* validate the port# (as configured and open) */ | 1144 | /* validate the port# (as configured and open) */ |
1170 | if (channel + chip * 4 >= cinfo->nports) { | 1145 | if (channel + chip * 4 >= cinfo->nports) { |
1171 | cy_writeb(base_addr + (CySRER << index), | 1146 | cy_writeb(base_addr + (CySRER << index), |
1172 | readb(base_addr + (CySRER << index)) & | 1147 | readb(base_addr + (CySRER << index)) & ~CyTxRdy); |
1173 | ~CyTxRdy); | 1148 | goto end; |
1174 | goto txend; | 1149 | } |
1175 | } | 1150 | info = &cinfo->ports[channel + chip * 4]; |
1176 | info = &cinfo->ports[channel + chip * 4]; | 1151 | if (info->tty == NULL) { |
1177 | if (info->tty == NULL) { | 1152 | cy_writeb(base_addr + (CySRER << index), |
1178 | cy_writeb(base_addr + (CySRER << index), | 1153 | readb(base_addr + (CySRER << index)) & ~CyTxRdy); |
1179 | readb(base_addr + (CySRER << index)) & | 1154 | goto end; |
1180 | ~CyTxRdy); | 1155 | } |
1181 | goto txend; | ||
1182 | } | ||
1183 | 1156 | ||
1184 | /* load the on-chip space for outbound data */ | 1157 | /* load the on-chip space for outbound data */ |
1185 | char_count = info->xmit_fifo_size; | 1158 | char_count = info->xmit_fifo_size; |
1186 | 1159 | ||
1187 | if (info->x_char) { /* send special char */ | 1160 | if (info->x_char) { /* send special char */ |
1188 | outch = info->x_char; | 1161 | outch = info->x_char; |
1189 | cy_writeb(base_addr + (CyTDR << index), outch); | 1162 | cy_writeb(base_addr + (CyTDR << index), outch); |
1190 | char_count--; | 1163 | char_count--; |
1191 | info->icount.tx++; | 1164 | info->icount.tx++; |
1192 | info->x_char = 0; | 1165 | info->x_char = 0; |
1193 | } | 1166 | } |
1194 | 1167 | ||
1195 | if (info->breakon || info->breakoff) { | 1168 | if (info->breakon || info->breakoff) { |
1196 | if (info->breakon) { | 1169 | if (info->breakon) { |
1197 | cy_writeb(base_addr + (CyTDR << index), 0); | 1170 | cy_writeb(base_addr + (CyTDR << index), 0); |
1198 | cy_writeb(base_addr + (CyTDR << index), 0x81); | 1171 | cy_writeb(base_addr + (CyTDR << index), 0x81); |
1199 | info->breakon = 0; | 1172 | info->breakon = 0; |
1200 | char_count -= 2; | 1173 | char_count -= 2; |
1201 | } | 1174 | } |
1202 | if (info->breakoff) { | 1175 | if (info->breakoff) { |
1203 | cy_writeb(base_addr + (CyTDR << index), 0); | 1176 | cy_writeb(base_addr + (CyTDR << index), 0); |
1204 | cy_writeb(base_addr + (CyTDR << index), 0x83); | 1177 | cy_writeb(base_addr + (CyTDR << index), 0x83); |
1205 | info->breakoff = 0; | 1178 | info->breakoff = 0; |
1206 | char_count -= 2; | 1179 | char_count -= 2; |
1207 | } | ||
1208 | } | 1180 | } |
1181 | } | ||
1209 | 1182 | ||
1210 | while (char_count-- > 0) { | 1183 | while (char_count-- > 0) { |
1211 | if (!info->xmit_cnt) { | 1184 | if (!info->xmit_cnt) { |
1212 | if (readb(base_addr + (CySRER << index)) & | 1185 | if (readb(base_addr + (CySRER << index)) & CyTxMpty) { |
1213 | CyTxMpty) { | 1186 | cy_writeb(base_addr + (CySRER << index), |
1214 | cy_writeb(base_addr + (CySRER << index), | 1187 | readb(base_addr + (CySRER << index)) & |
1215 | readb(base_addr + | ||
1216 | (CySRER << index)) & | ||
1217 | ~CyTxMpty); | 1188 | ~CyTxMpty); |
1218 | } else { | 1189 | } else { |
1219 | cy_writeb(base_addr + (CySRER << index), | 1190 | cy_writeb(base_addr + (CySRER << index), |
1220 | (readb(base_addr + | 1191 | (readb(base_addr + (CySRER << index)) & |
1221 | (CySRER << index)) & | ||
1222 | ~CyTxRdy) | CyTxMpty); | 1192 | ~CyTxRdy) | CyTxMpty); |
1223 | } | ||
1224 | goto txdone; | ||
1225 | } | 1193 | } |
1226 | if (info->xmit_buf == NULL) { | 1194 | goto done; |
1227 | cy_writeb(base_addr + (CySRER << index), | 1195 | } |
1228 | readb(base_addr + (CySRER << index)) & | 1196 | if (info->xmit_buf == NULL) { |
1197 | cy_writeb(base_addr + (CySRER << index), | ||
1198 | readb(base_addr + (CySRER << index)) & | ||
1229 | ~CyTxRdy); | 1199 | ~CyTxRdy); |
1230 | goto txdone; | 1200 | goto done; |
1231 | } | 1201 | } |
1232 | if (info->tty->stopped || info->tty->hw_stopped) { | 1202 | if (info->tty->stopped || info->tty->hw_stopped) { |
1233 | cy_writeb(base_addr + (CySRER << index), | 1203 | cy_writeb(base_addr + (CySRER << index), |
1234 | readb(base_addr + (CySRER << index)) & | 1204 | readb(base_addr + (CySRER << index)) & |
1235 | ~CyTxRdy); | 1205 | ~CyTxRdy); |
1236 | goto txdone; | 1206 | goto done; |
1237 | } | 1207 | } |
1238 | /* Because the Embedded Transmit Commands have | 1208 | /* Because the Embedded Transmit Commands have been enabled, |
1239 | been enabled, we must check to see if the | 1209 | * we must check to see if the escape character, NULL, is being |
1240 | escape character, NULL, is being sent. If it | 1210 | * sent. If it is, we must ensure that there is room for it to |
1241 | is, we must ensure that there is room for it | 1211 | * be doubled in the output stream. Therefore we no longer |
1242 | to be doubled in the output stream. Therefore | 1212 | * advance the pointer when the character is fetched, but |
1243 | we no longer advance the pointer when the | 1213 | * rather wait until after the check for a NULL output |
1244 | character is fetched, but rather wait until | 1214 | * character. This is necessary because there may not be room |
1245 | after the check for a NULL output character. | 1215 | * for the two chars needed to send a NULL.) |
1246 | This is necessary because there may not be | 1216 | */ |
1247 | room for the two chars needed to send a NULL.) | 1217 | outch = info->xmit_buf[info->xmit_tail]; |
1248 | */ | 1218 | if (outch) { |
1249 | outch = info->xmit_buf[info->xmit_tail]; | 1219 | info->xmit_cnt--; |
1250 | if (outch) { | 1220 | info->xmit_tail = (info->xmit_tail + 1) & |
1221 | (SERIAL_XMIT_SIZE - 1); | ||
1222 | cy_writeb(base_addr + (CyTDR << index), outch); | ||
1223 | info->icount.tx++; | ||
1224 | } else { | ||
1225 | if (char_count > 1) { | ||
1251 | info->xmit_cnt--; | 1226 | info->xmit_cnt--; |
1252 | info->xmit_tail = (info->xmit_tail + 1) & | 1227 | info->xmit_tail = (info->xmit_tail + 1) & |
1253 | (SERIAL_XMIT_SIZE - 1); | 1228 | (SERIAL_XMIT_SIZE - 1); |
1254 | cy_writeb(base_addr + (CyTDR << index), outch); | 1229 | cy_writeb(base_addr + (CyTDR << index), outch); |
1230 | cy_writeb(base_addr + (CyTDR << index), 0); | ||
1255 | info->icount.tx++; | 1231 | info->icount.tx++; |
1256 | } else { | 1232 | char_count--; |
1257 | if (char_count > 1) { | ||
1258 | info->xmit_cnt--; | ||
1259 | info->xmit_tail = (info->xmit_tail + 1)& | ||
1260 | (SERIAL_XMIT_SIZE - 1); | ||
1261 | cy_writeb(base_addr + (CyTDR << index), | ||
1262 | outch); | ||
1263 | cy_writeb(base_addr + (CyTDR << index), | ||
1264 | 0); | ||
1265 | info->icount.tx++; | ||
1266 | char_count--; | ||
1267 | } | ||
1268 | } | 1233 | } |
1269 | } | 1234 | } |
1270 | |||
1271 | txdone: | ||
1272 | tty_wakeup(info->tty); | ||
1273 | txend: | ||
1274 | /* end of service */ | ||
1275 | cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f)); | ||
1276 | cy_writeb(base_addr + (CyCAR << index), (save_car)); | ||
1277 | spin_unlock(&cinfo->card_lock); | ||
1278 | } | 1235 | } |
1279 | 1236 | ||
1280 | if (status & CySRModem) { /* modem interrupt */ | 1237 | done: |
1238 | tty_wakeup(info->tty); | ||
1239 | end: | ||
1240 | /* end of service */ | ||
1241 | cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f); | ||
1242 | cy_writeb(base_addr + (CyCAR << index), save_car); | ||
1243 | spin_unlock(&cinfo->card_lock); | ||
1244 | } | ||
1245 | |||
1246 | static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | ||
1247 | void __iomem *base_addr) | ||
1248 | { | ||
1249 | struct cyclades_port *info; | ||
1250 | int mdm_change, mdm_status; | ||
1251 | int save_xir, channel, save_car, index = cinfo->bus_index; | ||
1281 | 1252 | ||
1282 | /* determine the channel & change to that context */ | 1253 | /* determine the channel & change to that context */ |
1283 | spin_lock(&cinfo->card_lock); | 1254 | spin_lock(&cinfo->card_lock); |
1284 | save_xir = (u_char) readb(base_addr + (CyMIR << index)); | 1255 | save_xir = (u_char) readb(base_addr + (CyMIR << index)); |
1285 | channel = (u_short) (save_xir & CyIRChannel); | 1256 | channel = (u_short) (save_xir & CyIRChannel); |
1286 | info = &cinfo->ports[channel + chip * 4]; | 1257 | info = &cinfo->ports[channel + chip * 4]; |
1287 | save_car = readb(base_addr + (CyCAR << index)); | 1258 | save_car = readb(base_addr + (CyCAR << index)); |
1288 | cy_writeb(base_addr + (CyCAR << index), save_xir); | 1259 | cy_writeb(base_addr + (CyCAR << index), save_xir); |
1289 | 1260 | ||
1290 | mdm_change = readb(base_addr + (CyMISR << index)); | 1261 | mdm_change = readb(base_addr + (CyMISR << index)); |
1291 | mdm_status = readb(base_addr + (CyMSVR1 << index)); | 1262 | mdm_status = readb(base_addr + (CyMSVR1 << index)); |
1292 | 1263 | ||
1293 | if (info->tty) { | 1264 | if (!info->tty) |
1294 | if (mdm_change & CyANY_DELTA) { | 1265 | goto end; |
1295 | /* For statistics only */ | ||
1296 | if (mdm_change & CyDCD) | ||
1297 | info->icount.dcd++; | ||
1298 | if (mdm_change & CyCTS) | ||
1299 | info->icount.cts++; | ||
1300 | if (mdm_change & CyDSR) | ||
1301 | info->icount.dsr++; | ||
1302 | if (mdm_change & CyRI) | ||
1303 | info->icount.rng++; | ||
1304 | |||
1305 | wake_up_interruptible(&info->delta_msr_wait); | ||
1306 | } | ||
1307 | 1266 | ||
1308 | if ((mdm_change & CyDCD) && | 1267 | if (mdm_change & CyANY_DELTA) { |
1309 | (info->flags & ASYNC_CHECK_CD)) { | 1268 | /* For statistics only */ |
1310 | if (!(mdm_status & CyDCD)) { | 1269 | if (mdm_change & CyDCD) |
1311 | tty_hangup(info->tty); | 1270 | info->icount.dcd++; |
1312 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | 1271 | if (mdm_change & CyCTS) |
1313 | } | 1272 | info->icount.cts++; |
1314 | wake_up_interruptible(&info->open_wait); | 1273 | if (mdm_change & CyDSR) |
1315 | } | 1274 | info->icount.dsr++; |
1316 | if ((mdm_change & CyCTS) && | 1275 | if (mdm_change & CyRI) |
1317 | (info->flags & ASYNC_CTS_FLOW)) { | 1276 | info->icount.rng++; |
1318 | if (info->tty->hw_stopped) { | 1277 | |
1319 | if (mdm_status & CyCTS) { | 1278 | wake_up_interruptible(&info->delta_msr_wait); |
1320 | /* cy_start isn't used | 1279 | } |
1321 | because... !!! */ | 1280 | |
1322 | info->tty->hw_stopped = 0; | 1281 | if ((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)) { |
1323 | cy_writeb(base_addr + | 1282 | if (!(mdm_status & CyDCD)) { |
1324 | (CySRER << index), | 1283 | tty_hangup(info->tty); |
1325 | readb(base_addr + | 1284 | info->flags &= ~ASYNC_NORMAL_ACTIVE; |
1326 | (CySRER << | 1285 | } |
1327 | index))| | 1286 | wake_up_interruptible(&info->open_wait); |
1328 | CyTxRdy); | 1287 | } |
1329 | tty_wakeup(info->tty); | 1288 | if ((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)) { |
1330 | } | 1289 | if (info->tty->hw_stopped) { |
1331 | } else { | 1290 | if (mdm_status & CyCTS) { |
1332 | if (!(mdm_status & CyCTS)) { | 1291 | /* cy_start isn't used |
1333 | /* cy_stop isn't used | 1292 | because... !!! */ |
1334 | because ... !!! */ | 1293 | info->tty->hw_stopped = 0; |
1335 | info->tty->hw_stopped = 1; | 1294 | cy_writeb(base_addr + (CySRER << index), |
1336 | cy_writeb(base_addr + | 1295 | readb(base_addr + (CySRER << index)) | |
1337 | (CySRER << index), | 1296 | CyTxRdy); |
1338 | readb(base_addr + | 1297 | tty_wakeup(info->tty); |
1339 | (CySRER << | ||
1340 | index)) & | ||
1341 | ~CyTxRdy); | ||
1342 | } | ||
1343 | } | ||
1344 | } | 1298 | } |
1345 | /* if (mdm_change & CyDSR) { | 1299 | } else { |
1300 | if (!(mdm_status & CyCTS)) { | ||
1301 | /* cy_stop isn't used | ||
1302 | because ... !!! */ | ||
1303 | info->tty->hw_stopped = 1; | ||
1304 | cy_writeb(base_addr + (CySRER << index), | ||
1305 | readb(base_addr + (CySRER << index)) & | ||
1306 | ~CyTxRdy); | ||
1346 | } | 1307 | } |
1347 | if (mdm_change & CyRI) { | ||
1348 | }*/ | ||
1349 | } | 1308 | } |
1350 | /* end of service */ | ||
1351 | cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f)); | ||
1352 | cy_writeb(base_addr + (CyCAR << index), save_car); | ||
1353 | spin_unlock(&cinfo->card_lock); | ||
1354 | } | 1309 | } |
1310 | /* if (mdm_change & CyDSR) { | ||
1311 | } | ||
1312 | if (mdm_change & CyRI) { | ||
1313 | }*/ | ||
1314 | end: | ||
1315 | /* end of service */ | ||
1316 | cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f); | ||
1317 | cy_writeb(base_addr + (CyCAR << index), save_car); | ||
1318 | spin_unlock(&cinfo->card_lock); | ||
1355 | } | 1319 | } |
1356 | 1320 | ||
1357 | /* The real interrupt service routine is called | 1321 | /* The real interrupt service routine is called |
@@ -1401,11 +1365,14 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) | |||
1401 | chips to be checked in a round-robin fashion (after | 1365 | chips to be checked in a round-robin fashion (after |
1402 | draining each of a bunch (1000) of characters). | 1366 | draining each of a bunch (1000) of characters). |
1403 | */ | 1367 | */ |
1404 | if (1000 < too_many++) { | 1368 | if (1000 < too_many++) |
1405 | break; | 1369 | break; |
1406 | } | 1370 | if (status & CySRReceive) /* rx intr */ |
1407 | cyy_intr_chip(cinfo, chip, base_addr, status, | 1371 | cyy_chip_rx(cinfo, chip, base_addr); |
1408 | index); | 1372 | if (status & CySRTransmit) /* tx intr */ |
1373 | cyy_chip_tx(cinfo, chip, base_addr); | ||
1374 | if (status & CySRModem) /* modem intr */ | ||
1375 | cyy_chip_modem(cinfo, chip, base_addr); | ||
1409 | } | 1376 | } |
1410 | } | 1377 | } |
1411 | } while (had_work); | 1378 | } while (had_work); |