diff options
-rw-r--r-- | drivers/char/cyclades.c | 675 |
1 files changed, 340 insertions, 335 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 3bb4e534c14e..dd8223dc9086 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -1053,6 +1053,341 @@ detect_isa_irq(void __iomem *address) | |||
1053 | } | 1053 | } |
1054 | #endif /* CONFIG_ISA */ | 1054 | #endif /* CONFIG_ISA */ |
1055 | 1055 | ||
1056 | static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, | ||
1057 | void __iomem *base_addr, int status, int index) | ||
1058 | { | ||
1059 | struct cyclades_port *info; | ||
1060 | struct tty_struct *tty; | ||
1061 | volatile int char_count; | ||
1062 | int i, j, len, mdm_change, mdm_status, outch; | ||
1063 | int save_xir, channel, save_car; | ||
1064 | char data; | ||
1065 | |||
1066 | if (status & CySRReceive) { /* reception interrupt */ | ||
1067 | #ifdef CY_DEBUG_INTERRUPTS | ||
1068 | printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); | ||
1069 | #endif | ||
1070 | /* determine the channel & change to that context */ | ||
1071 | spin_lock(&cinfo->card_lock); | ||
1072 | save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index)); | ||
1073 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1074 | i = channel + chip * 4 + cinfo->first_line; | ||
1075 | info = &cy_port[i]; | ||
1076 | info->last_active = jiffies; | ||
1077 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1078 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1079 | |||
1080 | /* if there is nowhere to put the data, discard it */ | ||
1081 | if(info->tty == 0){ | ||
1082 | j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); | ||
1083 | if ( j == CyIVRRxEx ) { /* exception */ | ||
1084 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1085 | } else { /* normal character reception */ | ||
1086 | char_count = cy_readb(base_addr+(CyRDCR<<index)); | ||
1087 | while(char_count--){ | ||
1088 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1089 | } | ||
1090 | } | ||
1091 | }else{ /* there is an open port for this data */ | ||
1092 | tty = info->tty; | ||
1093 | j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); | ||
1094 | if ( j == CyIVRRxEx ) { /* exception */ | ||
1095 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1096 | |||
1097 | /* For statistics only */ | ||
1098 | if (data & CyBREAK) | ||
1099 | info->icount.brk++; | ||
1100 | else if(data & CyFRAME) | ||
1101 | info->icount.frame++; | ||
1102 | else if(data & CyPARITY) | ||
1103 | info->icount.parity++; | ||
1104 | else if(data & CyOVERRUN) | ||
1105 | info->icount.overrun++; | ||
1106 | |||
1107 | if(data & info->ignore_status_mask){ | ||
1108 | info->icount.rx++; | ||
1109 | return; | ||
1110 | } | ||
1111 | if (tty_buffer_request_room(tty, 1)) { | ||
1112 | if (data & info->read_status_mask){ | ||
1113 | if(data & CyBREAK){ | ||
1114 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK); | ||
1115 | info->icount.rx++; | ||
1116 | if (info->flags & ASYNC_SAK){ | ||
1117 | do_SAK(tty); | ||
1118 | } | ||
1119 | }else if(data & CyFRAME){ | ||
1120 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); | ||
1121 | info->icount.rx++; | ||
1122 | info->idle_stats.frame_errs++; | ||
1123 | }else if(data & CyPARITY){ | ||
1124 | /* Pieces of seven... */ | ||
1125 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY); | ||
1126 | info->icount.rx++; | ||
1127 | info->idle_stats.parity_errs++; | ||
1128 | }else if(data & CyOVERRUN){ | ||
1129 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
1130 | info->icount.rx++; | ||
1131 | /* If the flip buffer itself is | ||
1132 | overflowing, we still lose | ||
1133 | the next incoming character. | ||
1134 | */ | ||
1135 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); | ||
1136 | info->icount.rx++; | ||
1137 | info->idle_stats.overruns++; | ||
1138 | /* These two conditions may imply */ | ||
1139 | /* a normal read should be done. */ | ||
1140 | /* }else if(data & CyTIMEOUT){ */ | ||
1141 | /* }else if(data & CySPECHAR){ */ | ||
1142 | }else { | ||
1143 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | ||
1144 | info->icount.rx++; | ||
1145 | } | ||
1146 | }else{ | ||
1147 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | ||
1148 | info->icount.rx++; | ||
1149 | } | ||
1150 | }else{ | ||
1151 | /* there was a software buffer | ||
1152 | overrun and nothing could be | ||
1153 | done about it!!! */ | ||
1154 | info->icount.buf_overrun++; | ||
1155 | info->idle_stats.overruns++; | ||
1156 | } | ||
1157 | } else { /* normal character reception */ | ||
1158 | /* load # chars available from the chip */ | ||
1159 | char_count = cy_readb(base_addr+(CyRDCR<<index)); | ||
1160 | |||
1161 | #ifdef CY_ENABLE_MONITORING | ||
1162 | ++info->mon.int_count; | ||
1163 | info->mon.char_count += char_count; | ||
1164 | if (char_count > info->mon.char_max) | ||
1165 | info->mon.char_max = char_count; | ||
1166 | info->mon.char_last = char_count; | ||
1167 | #endif | ||
1168 | len = tty_buffer_request_room(tty, char_count); | ||
1169 | while(len--){ | ||
1170 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1171 | tty_insert_flip_char(tty, data, TTY_NORMAL); | ||
1172 | info->idle_stats.recv_bytes++; | ||
1173 | info->icount.rx++; | ||
1174 | #ifdef CY_16Y_HACK | ||
1175 | udelay(10L); | ||
1176 | #endif | ||
1177 | } | ||
1178 | info->idle_stats.recv_idle = jiffies; | ||
1179 | } | ||
1180 | tty_schedule_flip(tty); | ||
1181 | } | ||
1182 | /* end of service */ | ||
1183 | cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); | ||
1184 | cy_writeb(base_addr+(CyCAR<<index), (save_car)); | ||
1185 | spin_unlock(&cinfo->card_lock); | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | if (status & CySRTransmit) { /* transmission interrupt */ | ||
1190 | /* Since we only get here when the transmit buffer | ||
1191 | is empty, we know we can always stuff a dozen | ||
1192 | characters. */ | ||
1193 | #ifdef CY_DEBUG_INTERRUPTS | ||
1194 | printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); | ||
1195 | #endif | ||
1196 | |||
1197 | /* determine the channel & change to that context */ | ||
1198 | spin_lock(&cinfo->card_lock); | ||
1199 | save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index)); | ||
1200 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1201 | i = channel + chip * 4 + cinfo->first_line; | ||
1202 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1203 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1204 | |||
1205 | /* validate the port# (as configured and open) */ | ||
1206 | if( (i < 0) || (NR_PORTS <= i) ){ | ||
1207 | cy_writeb(base_addr+(CySRER<<index), | ||
1208 | cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); | ||
1209 | goto txend; | ||
1210 | } | ||
1211 | info = &cy_port[i]; | ||
1212 | info->last_active = jiffies; | ||
1213 | if(info->tty == 0){ | ||
1214 | cy_writeb(base_addr+(CySRER<<index), | ||
1215 | cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); | ||
1216 | goto txdone; | ||
1217 | } | ||
1218 | |||
1219 | /* load the on-chip space for outbound data */ | ||
1220 | char_count = info->xmit_fifo_size; | ||
1221 | |||
1222 | if(info->x_char) { /* send special char */ | ||
1223 | outch = info->x_char; | ||
1224 | cy_writeb(base_addr+(CyTDR<<index), outch); | ||
1225 | char_count--; | ||
1226 | info->icount.tx++; | ||
1227 | info->x_char = 0; | ||
1228 | } | ||
1229 | |||
1230 | if (info->breakon || info->breakoff) { | ||
1231 | if (info->breakon) { | ||
1232 | cy_writeb(base_addr + (CyTDR<<index), 0); | ||
1233 | cy_writeb(base_addr + (CyTDR<<index), 0x81); | ||
1234 | info->breakon = 0; | ||
1235 | char_count -= 2; | ||
1236 | } | ||
1237 | if (info->breakoff) { | ||
1238 | cy_writeb(base_addr + (CyTDR<<index), 0); | ||
1239 | cy_writeb(base_addr + (CyTDR<<index), 0x83); | ||
1240 | info->breakoff = 0; | ||
1241 | char_count -= 2; | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | while (char_count-- > 0){ | ||
1246 | if (!info->xmit_cnt){ | ||
1247 | if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) { | ||
1248 | cy_writeb(base_addr+(CySRER<<index), | ||
1249 | cy_readb(base_addr+(CySRER<<index)) & | ||
1250 | ~CyTxMpty); | ||
1251 | } else { | ||
1252 | cy_writeb(base_addr+(CySRER<<index), | ||
1253 | ((cy_readb(base_addr+(CySRER<<index)) | ||
1254 | & ~CyTxRdy) | ||
1255 | | CyTxMpty)); | ||
1256 | } | ||
1257 | goto txdone; | ||
1258 | } | ||
1259 | if (info->xmit_buf == 0){ | ||
1260 | cy_writeb(base_addr+(CySRER<<index), | ||
1261 | cy_readb(base_addr+(CySRER<<index)) & | ||
1262 | ~CyTxRdy); | ||
1263 | goto txdone; | ||
1264 | } | ||
1265 | if (info->tty->stopped || info->tty->hw_stopped){ | ||
1266 | cy_writeb(base_addr+(CySRER<<index), | ||
1267 | cy_readb(base_addr+(CySRER<<index)) & | ||
1268 | ~CyTxRdy); | ||
1269 | goto txdone; | ||
1270 | } | ||
1271 | /* Because the Embedded Transmit Commands have | ||
1272 | been enabled, we must check to see if the | ||
1273 | escape character, NULL, is being sent. If it | ||
1274 | is, we must ensure that there is room for it | ||
1275 | to be doubled in the output stream. Therefore | ||
1276 | we no longer advance the pointer when the | ||
1277 | character is fetched, but rather wait until | ||
1278 | after the check for a NULL output character. | ||
1279 | This is necessary because there may not be | ||
1280 | room for the two chars needed to send a NULL.) | ||
1281 | */ | ||
1282 | outch = info->xmit_buf[info->xmit_tail]; | ||
1283 | if( outch ){ | ||
1284 | info->xmit_cnt--; | ||
1285 | info->xmit_tail = (info->xmit_tail + 1) | ||
1286 | & (SERIAL_XMIT_SIZE - 1); | ||
1287 | cy_writeb(base_addr+(CyTDR<<index), outch); | ||
1288 | info->icount.tx++; | ||
1289 | }else{ | ||
1290 | if(char_count > 1){ | ||
1291 | info->xmit_cnt--; | ||
1292 | info->xmit_tail = (info->xmit_tail + 1) | ||
1293 | & (SERIAL_XMIT_SIZE - 1); | ||
1294 | cy_writeb(base_addr+(CyTDR<<index), | ||
1295 | outch); | ||
1296 | cy_writeb(base_addr+(CyTDR<<index), 0); | ||
1297 | info->icount.tx++; | ||
1298 | char_count--; | ||
1299 | }else{ | ||
1300 | } | ||
1301 | } | ||
1302 | } | ||
1303 | |||
1304 | txdone: | ||
1305 | if (info->xmit_cnt < WAKEUP_CHARS) { | ||
1306 | cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); | ||
1307 | } | ||
1308 | txend: | ||
1309 | /* end of service */ | ||
1310 | cy_writeb(base_addr+(CyTIR<<index), | ||
1311 | (save_xir & 0x3f)); | ||
1312 | cy_writeb(base_addr+(CyCAR<<index), (save_car)); | ||
1313 | spin_unlock(&cinfo->card_lock); | ||
1314 | } | ||
1315 | |||
1316 | if (status & CySRModem) { /* modem interrupt */ | ||
1317 | |||
1318 | /* determine the channel & change to that context */ | ||
1319 | spin_lock(&cinfo->card_lock); | ||
1320 | save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index)); | ||
1321 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1322 | info = &cy_port[channel + chip * 4 | ||
1323 | + cinfo->first_line]; | ||
1324 | info->last_active = jiffies; | ||
1325 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1326 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1327 | |||
1328 | mdm_change = cy_readb(base_addr+(CyMISR<<index)); | ||
1329 | mdm_status = cy_readb(base_addr+(CyMSVR1<<index)); | ||
1330 | |||
1331 | if(info->tty == 0){/* no place for data, ignore it*/ | ||
1332 | ; | ||
1333 | }else{ | ||
1334 | if (mdm_change & CyANY_DELTA) { | ||
1335 | /* For statistics only */ | ||
1336 | if (mdm_change & CyDCD) info->icount.dcd++; | ||
1337 | if (mdm_change & CyCTS) info->icount.cts++; | ||
1338 | if (mdm_change & CyDSR) info->icount.dsr++; | ||
1339 | if (mdm_change & CyRI) info->icount.rng++; | ||
1340 | |||
1341 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); | ||
1342 | } | ||
1343 | |||
1344 | if((mdm_change & CyDCD) | ||
1345 | && (info->flags & ASYNC_CHECK_CD)){ | ||
1346 | if(mdm_status & CyDCD){ | ||
1347 | cy_sched_event(info, | ||
1348 | Cy_EVENT_OPEN_WAKEUP); | ||
1349 | }else{ | ||
1350 | cy_sched_event(info, | ||
1351 | Cy_EVENT_HANGUP); | ||
1352 | } | ||
1353 | } | ||
1354 | if((mdm_change & CyCTS) | ||
1355 | && (info->flags & ASYNC_CTS_FLOW)){ | ||
1356 | if(info->tty->hw_stopped){ | ||
1357 | if(mdm_status & CyCTS){ | ||
1358 | /* cy_start isn't used | ||
1359 | because... !!! */ | ||
1360 | info->tty->hw_stopped = 0; | ||
1361 | cy_writeb(base_addr+(CySRER<<index), | ||
1362 | cy_readb(base_addr+(CySRER<<index)) | | ||
1363 | CyTxRdy); | ||
1364 | cy_sched_event(info, | ||
1365 | Cy_EVENT_WRITE_WAKEUP); | ||
1366 | } | ||
1367 | }else{ | ||
1368 | if(!(mdm_status & CyCTS)){ | ||
1369 | /* cy_stop isn't used | ||
1370 | because ... !!! */ | ||
1371 | info->tty->hw_stopped = 1; | ||
1372 | cy_writeb(base_addr+(CySRER<<index), | ||
1373 | cy_readb(base_addr+(CySRER<<index)) & | ||
1374 | ~CyTxRdy); | ||
1375 | } | ||
1376 | } | ||
1377 | } | ||
1378 | if(mdm_change & CyDSR){ | ||
1379 | } | ||
1380 | if(mdm_change & CyRI){ | ||
1381 | } | ||
1382 | } | ||
1383 | /* end of service */ | ||
1384 | cy_writeb(base_addr+(CyMIR<<index), | ||
1385 | (save_xir & 0x3f)); | ||
1386 | cy_writeb(base_addr+(CyCAR<<index), save_car); | ||
1387 | spin_unlock(&cinfo->card_lock); | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1056 | /* The real interrupt service routine is called | 1391 | /* The real interrupt service routine is called |
1057 | whenever the card wants its hand held--chars | 1392 | whenever the card wants its hand held--chars |
1058 | received, out buffer empty, modem change, etc. | 1393 | received, out buffer empty, modem change, etc. |
@@ -1060,22 +1395,14 @@ detect_isa_irq(void __iomem *address) | |||
1060 | static irqreturn_t | 1395 | static irqreturn_t |
1061 | cyy_interrupt(int irq, void *dev_id) | 1396 | cyy_interrupt(int irq, void *dev_id) |
1062 | { | 1397 | { |
1063 | struct tty_struct *tty; | ||
1064 | int status; | 1398 | int status; |
1065 | struct cyclades_card *cinfo; | 1399 | struct cyclades_card *cinfo; |
1066 | struct cyclades_port *info; | ||
1067 | void __iomem *base_addr, *card_base_addr; | 1400 | void __iomem *base_addr, *card_base_addr; |
1068 | int chip; | 1401 | int chip; |
1069 | int save_xir, channel, save_car; | 1402 | int index; |
1070 | char data; | ||
1071 | volatile int char_count; | ||
1072 | int outch; | ||
1073 | int i,j,index; | ||
1074 | int too_many; | 1403 | int too_many; |
1075 | int had_work; | 1404 | int had_work; |
1076 | int mdm_change; | 1405 | |
1077 | int mdm_status; | ||
1078 | int len; | ||
1079 | if((cinfo = (struct cyclades_card *)dev_id) == 0){ | 1406 | if((cinfo = (struct cyclades_card *)dev_id) == 0){ |
1080 | #ifdef CY_DEBUG_INTERRUPTS | 1407 | #ifdef CY_DEBUG_INTERRUPTS |
1081 | printk("cyy_interrupt: spurious interrupt %d\n\r", irq); | 1408 | printk("cyy_interrupt: spurious interrupt %d\n\r", irq); |
@@ -1107,331 +1434,9 @@ cyy_interrupt(int irq, void *dev_id) | |||
1107 | if(1000<too_many++){ | 1434 | if(1000<too_many++){ |
1108 | break; | 1435 | break; |
1109 | } | 1436 | } |
1110 | if (status & CySRReceive) { /* reception interrupt */ | 1437 | cyy_intr_chip(cinfo, chip, base_addr, status, index); |
1111 | #ifdef CY_DEBUG_INTERRUPTS | 1438 | } |
1112 | printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); | 1439 | } |
1113 | #endif | ||
1114 | /* determine the channel & change to that context */ | ||
1115 | spin_lock(&cinfo->card_lock); | ||
1116 | save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index)); | ||
1117 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1118 | i = channel + chip * 4 + cinfo->first_line; | ||
1119 | info = &cy_port[i]; | ||
1120 | info->last_active = jiffies; | ||
1121 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1122 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1123 | |||
1124 | /* if there is nowhere to put the data, discard it */ | ||
1125 | if(info->tty == 0){ | ||
1126 | j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); | ||
1127 | if ( j == CyIVRRxEx ) { /* exception */ | ||
1128 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1129 | } else { /* normal character reception */ | ||
1130 | char_count = cy_readb(base_addr+(CyRDCR<<index)); | ||
1131 | while(char_count--){ | ||
1132 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1133 | } | ||
1134 | } | ||
1135 | }else{ /* there is an open port for this data */ | ||
1136 | tty = info->tty; | ||
1137 | j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); | ||
1138 | if ( j == CyIVRRxEx ) { /* exception */ | ||
1139 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1140 | |||
1141 | /* For statistics only */ | ||
1142 | if (data & CyBREAK) | ||
1143 | info->icount.brk++; | ||
1144 | else if(data & CyFRAME) | ||
1145 | info->icount.frame++; | ||
1146 | else if(data & CyPARITY) | ||
1147 | info->icount.parity++; | ||
1148 | else if(data & CyOVERRUN) | ||
1149 | info->icount.overrun++; | ||
1150 | |||
1151 | if(data & info->ignore_status_mask){ | ||
1152 | info->icount.rx++; | ||
1153 | continue; | ||
1154 | } | ||
1155 | if (tty_buffer_request_room(tty, 1)) { | ||
1156 | if (data & info->read_status_mask){ | ||
1157 | if(data & CyBREAK){ | ||
1158 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK); | ||
1159 | info->icount.rx++; | ||
1160 | if (info->flags & ASYNC_SAK){ | ||
1161 | do_SAK(tty); | ||
1162 | } | ||
1163 | }else if(data & CyFRAME){ | ||
1164 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); | ||
1165 | info->icount.rx++; | ||
1166 | info->idle_stats.frame_errs++; | ||
1167 | }else if(data & CyPARITY){ | ||
1168 | /* Pieces of seven... */ | ||
1169 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY); | ||
1170 | info->icount.rx++; | ||
1171 | info->idle_stats.parity_errs++; | ||
1172 | }else if(data & CyOVERRUN){ | ||
1173 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
1174 | info->icount.rx++; | ||
1175 | /* If the flip buffer itself is | ||
1176 | overflowing, we still lose | ||
1177 | the next incoming character. | ||
1178 | */ | ||
1179 | tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); | ||
1180 | info->icount.rx++; | ||
1181 | info->idle_stats.overruns++; | ||
1182 | /* These two conditions may imply */ | ||
1183 | /* a normal read should be done. */ | ||
1184 | /* }else if(data & CyTIMEOUT){ */ | ||
1185 | /* }else if(data & CySPECHAR){ */ | ||
1186 | }else { | ||
1187 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | ||
1188 | info->icount.rx++; | ||
1189 | } | ||
1190 | }else{ | ||
1191 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | ||
1192 | info->icount.rx++; | ||
1193 | } | ||
1194 | }else{ | ||
1195 | /* there was a software buffer | ||
1196 | overrun and nothing could be | ||
1197 | done about it!!! */ | ||
1198 | info->icount.buf_overrun++; | ||
1199 | info->idle_stats.overruns++; | ||
1200 | } | ||
1201 | } else { /* normal character reception */ | ||
1202 | /* load # chars available from the chip */ | ||
1203 | char_count = cy_readb(base_addr+(CyRDCR<<index)); | ||
1204 | |||
1205 | #ifdef CY_ENABLE_MONITORING | ||
1206 | ++info->mon.int_count; | ||
1207 | info->mon.char_count += char_count; | ||
1208 | if (char_count > info->mon.char_max) | ||
1209 | info->mon.char_max = char_count; | ||
1210 | info->mon.char_last = char_count; | ||
1211 | #endif | ||
1212 | len = tty_buffer_request_room(tty, char_count); | ||
1213 | while(len--){ | ||
1214 | data = cy_readb(base_addr+(CyRDSR<<index)); | ||
1215 | tty_insert_flip_char(tty, data, TTY_NORMAL); | ||
1216 | info->idle_stats.recv_bytes++; | ||
1217 | info->icount.rx++; | ||
1218 | #ifdef CY_16Y_HACK | ||
1219 | udelay(10L); | ||
1220 | #endif | ||
1221 | } | ||
1222 | info->idle_stats.recv_idle = jiffies; | ||
1223 | } | ||
1224 | tty_schedule_flip(tty); | ||
1225 | } | ||
1226 | /* end of service */ | ||
1227 | cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); | ||
1228 | cy_writeb(base_addr+(CyCAR<<index), (save_car)); | ||
1229 | spin_unlock(&cinfo->card_lock); | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | if (status & CySRTransmit) { /* transmission interrupt */ | ||
1234 | /* Since we only get here when the transmit buffer | ||
1235 | is empty, we know we can always stuff a dozen | ||
1236 | characters. */ | ||
1237 | #ifdef CY_DEBUG_INTERRUPTS | ||
1238 | printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); | ||
1239 | #endif | ||
1240 | |||
1241 | /* determine the channel & change to that context */ | ||
1242 | spin_lock(&cinfo->card_lock); | ||
1243 | save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index)); | ||
1244 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1245 | i = channel + chip * 4 + cinfo->first_line; | ||
1246 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1247 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1248 | |||
1249 | /* validate the port# (as configured and open) */ | ||
1250 | if( (i < 0) || (NR_PORTS <= i) ){ | ||
1251 | cy_writeb(base_addr+(CySRER<<index), | ||
1252 | cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); | ||
1253 | goto txend; | ||
1254 | } | ||
1255 | info = &cy_port[i]; | ||
1256 | info->last_active = jiffies; | ||
1257 | if(info->tty == 0){ | ||
1258 | cy_writeb(base_addr+(CySRER<<index), | ||
1259 | cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); | ||
1260 | goto txdone; | ||
1261 | } | ||
1262 | |||
1263 | /* load the on-chip space for outbound data */ | ||
1264 | char_count = info->xmit_fifo_size; | ||
1265 | |||
1266 | if(info->x_char) { /* send special char */ | ||
1267 | outch = info->x_char; | ||
1268 | cy_writeb(base_addr+(CyTDR<<index), outch); | ||
1269 | char_count--; | ||
1270 | info->icount.tx++; | ||
1271 | info->x_char = 0; | ||
1272 | } | ||
1273 | |||
1274 | if (info->breakon || info->breakoff) { | ||
1275 | if (info->breakon) { | ||
1276 | cy_writeb(base_addr + (CyTDR<<index), 0); | ||
1277 | cy_writeb(base_addr + (CyTDR<<index), 0x81); | ||
1278 | info->breakon = 0; | ||
1279 | char_count -= 2; | ||
1280 | } | ||
1281 | if (info->breakoff) { | ||
1282 | cy_writeb(base_addr + (CyTDR<<index), 0); | ||
1283 | cy_writeb(base_addr + (CyTDR<<index), 0x83); | ||
1284 | info->breakoff = 0; | ||
1285 | char_count -= 2; | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | while (char_count-- > 0){ | ||
1290 | if (!info->xmit_cnt){ | ||
1291 | if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) { | ||
1292 | cy_writeb(base_addr+(CySRER<<index), | ||
1293 | cy_readb(base_addr+(CySRER<<index)) & | ||
1294 | ~CyTxMpty); | ||
1295 | } else { | ||
1296 | cy_writeb(base_addr+(CySRER<<index), | ||
1297 | ((cy_readb(base_addr+(CySRER<<index)) | ||
1298 | & ~CyTxRdy) | ||
1299 | | CyTxMpty)); | ||
1300 | } | ||
1301 | goto txdone; | ||
1302 | } | ||
1303 | if (info->xmit_buf == 0){ | ||
1304 | cy_writeb(base_addr+(CySRER<<index), | ||
1305 | cy_readb(base_addr+(CySRER<<index)) & | ||
1306 | ~CyTxRdy); | ||
1307 | goto txdone; | ||
1308 | } | ||
1309 | if (info->tty->stopped || info->tty->hw_stopped){ | ||
1310 | cy_writeb(base_addr+(CySRER<<index), | ||
1311 | cy_readb(base_addr+(CySRER<<index)) & | ||
1312 | ~CyTxRdy); | ||
1313 | goto txdone; | ||
1314 | } | ||
1315 | /* Because the Embedded Transmit Commands have | ||
1316 | been enabled, we must check to see if the | ||
1317 | escape character, NULL, is being sent. If it | ||
1318 | is, we must ensure that there is room for it | ||
1319 | to be doubled in the output stream. Therefore | ||
1320 | we no longer advance the pointer when the | ||
1321 | character is fetched, but rather wait until | ||
1322 | after the check for a NULL output character. | ||
1323 | This is necessary because there may not be | ||
1324 | room for the two chars needed to send a NULL.) | ||
1325 | */ | ||
1326 | outch = info->xmit_buf[info->xmit_tail]; | ||
1327 | if( outch ){ | ||
1328 | info->xmit_cnt--; | ||
1329 | info->xmit_tail = (info->xmit_tail + 1) | ||
1330 | & (SERIAL_XMIT_SIZE - 1); | ||
1331 | cy_writeb(base_addr+(CyTDR<<index), outch); | ||
1332 | info->icount.tx++; | ||
1333 | }else{ | ||
1334 | if(char_count > 1){ | ||
1335 | info->xmit_cnt--; | ||
1336 | info->xmit_tail = (info->xmit_tail + 1) | ||
1337 | & (SERIAL_XMIT_SIZE - 1); | ||
1338 | cy_writeb(base_addr+(CyTDR<<index), | ||
1339 | outch); | ||
1340 | cy_writeb(base_addr+(CyTDR<<index), 0); | ||
1341 | info->icount.tx++; | ||
1342 | char_count--; | ||
1343 | }else{ | ||
1344 | } | ||
1345 | } | ||
1346 | } | ||
1347 | |||
1348 | txdone: | ||
1349 | if (info->xmit_cnt < WAKEUP_CHARS) { | ||
1350 | cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); | ||
1351 | } | ||
1352 | txend: | ||
1353 | /* end of service */ | ||
1354 | cy_writeb(base_addr+(CyTIR<<index), | ||
1355 | (save_xir & 0x3f)); | ||
1356 | cy_writeb(base_addr+(CyCAR<<index), (save_car)); | ||
1357 | spin_unlock(&cinfo->card_lock); | ||
1358 | } | ||
1359 | |||
1360 | if (status & CySRModem) { /* modem interrupt */ | ||
1361 | |||
1362 | /* determine the channel & change to that context */ | ||
1363 | spin_lock(&cinfo->card_lock); | ||
1364 | save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index)); | ||
1365 | channel = (u_short ) (save_xir & CyIRChannel); | ||
1366 | info = &cy_port[channel + chip * 4 | ||
1367 | + cinfo->first_line]; | ||
1368 | info->last_active = jiffies; | ||
1369 | save_car = cy_readb(base_addr+(CyCAR<<index)); | ||
1370 | cy_writeb(base_addr+(CyCAR<<index), save_xir); | ||
1371 | |||
1372 | mdm_change = cy_readb(base_addr+(CyMISR<<index)); | ||
1373 | mdm_status = cy_readb(base_addr+(CyMSVR1<<index)); | ||
1374 | |||
1375 | if(info->tty == 0){/* no place for data, ignore it*/ | ||
1376 | ; | ||
1377 | }else{ | ||
1378 | if (mdm_change & CyANY_DELTA) { | ||
1379 | /* For statistics only */ | ||
1380 | if (mdm_change & CyDCD) info->icount.dcd++; | ||
1381 | if (mdm_change & CyCTS) info->icount.cts++; | ||
1382 | if (mdm_change & CyDSR) info->icount.dsr++; | ||
1383 | if (mdm_change & CyRI) info->icount.rng++; | ||
1384 | |||
1385 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); | ||
1386 | } | ||
1387 | |||
1388 | if((mdm_change & CyDCD) | ||
1389 | && (info->flags & ASYNC_CHECK_CD)){ | ||
1390 | if(mdm_status & CyDCD){ | ||
1391 | cy_sched_event(info, | ||
1392 | Cy_EVENT_OPEN_WAKEUP); | ||
1393 | }else{ | ||
1394 | cy_sched_event(info, | ||
1395 | Cy_EVENT_HANGUP); | ||
1396 | } | ||
1397 | } | ||
1398 | if((mdm_change & CyCTS) | ||
1399 | && (info->flags & ASYNC_CTS_FLOW)){ | ||
1400 | if(info->tty->hw_stopped){ | ||
1401 | if(mdm_status & CyCTS){ | ||
1402 | /* cy_start isn't used | ||
1403 | because... !!! */ | ||
1404 | info->tty->hw_stopped = 0; | ||
1405 | cy_writeb(base_addr+(CySRER<<index), | ||
1406 | cy_readb(base_addr+(CySRER<<index)) | | ||
1407 | CyTxRdy); | ||
1408 | cy_sched_event(info, | ||
1409 | Cy_EVENT_WRITE_WAKEUP); | ||
1410 | } | ||
1411 | }else{ | ||
1412 | if(!(mdm_status & CyCTS)){ | ||
1413 | /* cy_stop isn't used | ||
1414 | because ... !!! */ | ||
1415 | info->tty->hw_stopped = 1; | ||
1416 | cy_writeb(base_addr+(CySRER<<index), | ||
1417 | cy_readb(base_addr+(CySRER<<index)) & | ||
1418 | ~CyTxRdy); | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | if(mdm_change & CyDSR){ | ||
1423 | } | ||
1424 | if(mdm_change & CyRI){ | ||
1425 | } | ||
1426 | } | ||
1427 | /* end of service */ | ||
1428 | cy_writeb(base_addr+(CyMIR<<index), | ||
1429 | (save_xir & 0x3f)); | ||
1430 | cy_writeb(base_addr+(CyCAR<<index), save_car); | ||
1431 | spin_unlock(&cinfo->card_lock); | ||
1432 | } | ||
1433 | } /* end while status != 0 */ | ||
1434 | } /* end loop for chips... */ | ||
1435 | } while(had_work); | 1440 | } while(had_work); |
1436 | 1441 | ||
1437 | /* clear interrupts */ | 1442 | /* clear interrupts */ |