diff options
Diffstat (limited to 'drivers/tty/cyclades.c')
-rw-r--r-- | drivers/tty/cyclades.c | 297 |
1 files changed, 142 insertions, 155 deletions
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index b09c8d1f9a66..345bd0e0884e 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c | |||
@@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
441 | void __iomem *base_addr) | 441 | void __iomem *base_addr) |
442 | { | 442 | { |
443 | struct cyclades_port *info; | 443 | struct cyclades_port *info; |
444 | struct tty_struct *tty; | 444 | struct tty_port *port; |
445 | int len, index = cinfo->bus_index; | 445 | int len, index = cinfo->bus_index; |
446 | u8 ivr, save_xir, channel, save_car, data, char_count; | 446 | u8 ivr, save_xir, channel, save_car, data, char_count; |
447 | 447 | ||
@@ -452,22 +452,11 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
452 | save_xir = readb(base_addr + (CyRIR << index)); | 452 | save_xir = readb(base_addr + (CyRIR << index)); |
453 | channel = save_xir & CyIRChannel; | 453 | channel = save_xir & CyIRChannel; |
454 | info = &cinfo->ports[channel + chip * 4]; | 454 | info = &cinfo->ports[channel + chip * 4]; |
455 | port = &info->port; | ||
455 | save_car = cyy_readb(info, CyCAR); | 456 | save_car = cyy_readb(info, CyCAR); |
456 | cyy_writeb(info, CyCAR, save_xir); | 457 | cyy_writeb(info, CyCAR, save_xir); |
457 | ivr = cyy_readb(info, CyRIVR) & CyIVRMask; | 458 | ivr = cyy_readb(info, CyRIVR) & CyIVRMask; |
458 | 459 | ||
459 | tty = tty_port_tty_get(&info->port); | ||
460 | /* if there is nowhere to put the data, discard it */ | ||
461 | if (tty == NULL) { | ||
462 | if (ivr == CyIVRRxEx) { /* exception */ | ||
463 | data = cyy_readb(info, CyRDSR); | ||
464 | } else { /* normal character reception */ | ||
465 | char_count = cyy_readb(info, CyRDCR); | ||
466 | while (char_count--) | ||
467 | data = cyy_readb(info, CyRDSR); | ||
468 | } | ||
469 | goto end; | ||
470 | } | ||
471 | /* there is an open port for this data */ | 460 | /* there is an open port for this data */ |
472 | if (ivr == CyIVRRxEx) { /* exception */ | 461 | if (ivr == CyIVRRxEx) { /* exception */ |
473 | data = cyy_readb(info, CyRDSR); | 462 | data = cyy_readb(info, CyRDSR); |
@@ -484,40 +473,45 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
484 | 473 | ||
485 | if (data & info->ignore_status_mask) { | 474 | if (data & info->ignore_status_mask) { |
486 | info->icount.rx++; | 475 | info->icount.rx++; |
487 | tty_kref_put(tty); | ||
488 | return; | 476 | return; |
489 | } | 477 | } |
490 | if (tty_buffer_request_room(tty, 1)) { | 478 | if (tty_buffer_request_room(port, 1)) { |
491 | if (data & info->read_status_mask) { | 479 | if (data & info->read_status_mask) { |
492 | if (data & CyBREAK) { | 480 | if (data & CyBREAK) { |
493 | tty_insert_flip_char(tty, | 481 | tty_insert_flip_char(port, |
494 | cyy_readb(info, CyRDSR), | 482 | cyy_readb(info, CyRDSR), |
495 | TTY_BREAK); | 483 | TTY_BREAK); |
496 | info->icount.rx++; | 484 | info->icount.rx++; |
497 | if (info->port.flags & ASYNC_SAK) | 485 | if (port->flags & ASYNC_SAK) { |
498 | do_SAK(tty); | 486 | struct tty_struct *tty = |
487 | tty_port_tty_get(port); | ||
488 | if (tty) { | ||
489 | do_SAK(tty); | ||
490 | tty_kref_put(tty); | ||
491 | } | ||
492 | } | ||
499 | } else if (data & CyFRAME) { | 493 | } else if (data & CyFRAME) { |
500 | tty_insert_flip_char(tty, | 494 | tty_insert_flip_char(port, |
501 | cyy_readb(info, CyRDSR), | 495 | cyy_readb(info, CyRDSR), |
502 | TTY_FRAME); | 496 | TTY_FRAME); |
503 | info->icount.rx++; | 497 | info->icount.rx++; |
504 | info->idle_stats.frame_errs++; | 498 | info->idle_stats.frame_errs++; |
505 | } else if (data & CyPARITY) { | 499 | } else if (data & CyPARITY) { |
506 | /* Pieces of seven... */ | 500 | /* Pieces of seven... */ |
507 | tty_insert_flip_char(tty, | 501 | tty_insert_flip_char(port, |
508 | cyy_readb(info, CyRDSR), | 502 | cyy_readb(info, CyRDSR), |
509 | TTY_PARITY); | 503 | TTY_PARITY); |
510 | info->icount.rx++; | 504 | info->icount.rx++; |
511 | info->idle_stats.parity_errs++; | 505 | info->idle_stats.parity_errs++; |
512 | } else if (data & CyOVERRUN) { | 506 | } else if (data & CyOVERRUN) { |
513 | tty_insert_flip_char(tty, 0, | 507 | tty_insert_flip_char(port, 0, |
514 | TTY_OVERRUN); | 508 | TTY_OVERRUN); |
515 | info->icount.rx++; | 509 | info->icount.rx++; |
516 | /* If the flip buffer itself is | 510 | /* If the flip buffer itself is |
517 | overflowing, we still lose | 511 | overflowing, we still lose |
518 | the next incoming character. | 512 | the next incoming character. |
519 | */ | 513 | */ |
520 | tty_insert_flip_char(tty, | 514 | tty_insert_flip_char(port, |
521 | cyy_readb(info, CyRDSR), | 515 | cyy_readb(info, CyRDSR), |
522 | TTY_FRAME); | 516 | TTY_FRAME); |
523 | info->icount.rx++; | 517 | info->icount.rx++; |
@@ -527,12 +521,12 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
527 | /* } else if(data & CyTIMEOUT) { */ | 521 | /* } else if(data & CyTIMEOUT) { */ |
528 | /* } else if(data & CySPECHAR) { */ | 522 | /* } else if(data & CySPECHAR) { */ |
529 | } else { | 523 | } else { |
530 | tty_insert_flip_char(tty, 0, | 524 | tty_insert_flip_char(port, 0, |
531 | TTY_NORMAL); | 525 | TTY_NORMAL); |
532 | info->icount.rx++; | 526 | info->icount.rx++; |
533 | } | 527 | } |
534 | } else { | 528 | } else { |
535 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | 529 | tty_insert_flip_char(port, 0, TTY_NORMAL); |
536 | info->icount.rx++; | 530 | info->icount.rx++; |
537 | } | 531 | } |
538 | } else { | 532 | } else { |
@@ -552,10 +546,10 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
552 | info->mon.char_max = char_count; | 546 | info->mon.char_max = char_count; |
553 | info->mon.char_last = char_count; | 547 | info->mon.char_last = char_count; |
554 | #endif | 548 | #endif |
555 | len = tty_buffer_request_room(tty, char_count); | 549 | len = tty_buffer_request_room(port, char_count); |
556 | while (len--) { | 550 | while (len--) { |
557 | data = cyy_readb(info, CyRDSR); | 551 | data = cyy_readb(info, CyRDSR); |
558 | tty_insert_flip_char(tty, data, TTY_NORMAL); | 552 | tty_insert_flip_char(port, data, TTY_NORMAL); |
559 | info->idle_stats.recv_bytes++; | 553 | info->idle_stats.recv_bytes++; |
560 | info->icount.rx++; | 554 | info->icount.rx++; |
561 | #ifdef CY_16Y_HACK | 555 | #ifdef CY_16Y_HACK |
@@ -564,9 +558,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | |||
564 | } | 558 | } |
565 | info->idle_stats.recv_idle = jiffies; | 559 | info->idle_stats.recv_idle = jiffies; |
566 | } | 560 | } |
567 | tty_schedule_flip(tty); | 561 | tty_schedule_flip(port); |
568 | tty_kref_put(tty); | 562 | |
569 | end: | ||
570 | /* end of service */ | 563 | /* end of service */ |
571 | cyy_writeb(info, CyRIR, save_xir & 0x3f); | 564 | cyy_writeb(info, CyRIR, save_xir & 0x3f); |
572 | cyy_writeb(info, CyCAR, save_car); | 565 | cyy_writeb(info, CyCAR, save_car); |
@@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo, | |||
924 | return 0; | 917 | return 0; |
925 | } /* cyz_issue_cmd */ | 918 | } /* cyz_issue_cmd */ |
926 | 919 | ||
927 | static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) | 920 | static void cyz_handle_rx(struct cyclades_port *info) |
928 | { | 921 | { |
929 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; | 922 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; |
930 | struct cyclades_card *cinfo = info->card; | 923 | struct cyclades_card *cinfo = info->card; |
924 | struct tty_port *port = &info->port; | ||
931 | unsigned int char_count; | 925 | unsigned int char_count; |
932 | int len; | 926 | int len; |
933 | #ifdef BLOCKMOVE | 927 | #ifdef BLOCKMOVE |
@@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) | |||
946 | else | 940 | else |
947 | char_count = rx_put - rx_get + rx_bufsize; | 941 | char_count = rx_put - rx_get + rx_bufsize; |
948 | 942 | ||
949 | if (char_count) { | 943 | if (!char_count) |
944 | return; | ||
945 | |||
950 | #ifdef CY_ENABLE_MONITORING | 946 | #ifdef CY_ENABLE_MONITORING |
951 | info->mon.int_count++; | 947 | info->mon.int_count++; |
952 | info->mon.char_count += char_count; | 948 | info->mon.char_count += char_count; |
953 | if (char_count > info->mon.char_max) | 949 | if (char_count > info->mon.char_max) |
954 | info->mon.char_max = char_count; | 950 | info->mon.char_max = char_count; |
955 | info->mon.char_last = char_count; | 951 | info->mon.char_last = char_count; |
956 | #endif | 952 | #endif |
957 | if (tty == NULL) { | 953 | |
958 | /* flush received characters */ | ||
959 | new_rx_get = (new_rx_get + char_count) & | ||
960 | (rx_bufsize - 1); | ||
961 | info->rflush_count++; | ||
962 | } else { | ||
963 | #ifdef BLOCKMOVE | 954 | #ifdef BLOCKMOVE |
964 | /* we'd like to use memcpy(t, f, n) and memset(s, c, count) | 955 | /* we'd like to use memcpy(t, f, n) and memset(s, c, count) |
965 | for performance, but because of buffer boundaries, there | 956 | for performance, but because of buffer boundaries, there |
966 | may be several steps to the operation */ | 957 | may be several steps to the operation */ |
967 | while (1) { | 958 | while (1) { |
968 | len = tty_prepare_flip_string(tty, &buf, | 959 | len = tty_prepare_flip_string(port, &buf, |
969 | char_count); | 960 | char_count); |
970 | if (!len) | 961 | if (!len) |
971 | break; | 962 | break; |
972 | 963 | ||
973 | len = min_t(unsigned int, min(len, char_count), | 964 | len = min_t(unsigned int, min(len, char_count), |
974 | rx_bufsize - new_rx_get); | 965 | rx_bufsize - new_rx_get); |
975 | 966 | ||
976 | memcpy_fromio(buf, cinfo->base_addr + | 967 | memcpy_fromio(buf, cinfo->base_addr + |
977 | rx_bufaddr + new_rx_get, len); | 968 | rx_bufaddr + new_rx_get, len); |
978 | 969 | ||
979 | new_rx_get = (new_rx_get + len) & | 970 | new_rx_get = (new_rx_get + len) & |
980 | (rx_bufsize - 1); | 971 | (rx_bufsize - 1); |
981 | char_count -= len; | 972 | char_count -= len; |
982 | info->icount.rx += len; | 973 | info->icount.rx += len; |
983 | info->idle_stats.recv_bytes += len; | 974 | info->idle_stats.recv_bytes += len; |
984 | } | 975 | } |
985 | #else | 976 | #else |
986 | len = tty_buffer_request_room(tty, char_count); | 977 | len = tty_buffer_request_room(port, char_count); |
987 | while (len--) { | 978 | while (len--) { |
988 | data = readb(cinfo->base_addr + rx_bufaddr + | 979 | data = readb(cinfo->base_addr + rx_bufaddr + |
989 | new_rx_get); | 980 | new_rx_get); |
990 | new_rx_get = (new_rx_get + 1) & | 981 | new_rx_get = (new_rx_get + 1) & |
991 | (rx_bufsize - 1); | 982 | (rx_bufsize - 1); |
992 | tty_insert_flip_char(tty, data, TTY_NORMAL); | 983 | tty_insert_flip_char(port, data, TTY_NORMAL); |
993 | info->idle_stats.recv_bytes++; | 984 | info->idle_stats.recv_bytes++; |
994 | info->icount.rx++; | 985 | info->icount.rx++; |
995 | } | 986 | } |
996 | #endif | 987 | #endif |
997 | #ifdef CONFIG_CYZ_INTR | 988 | #ifdef CONFIG_CYZ_INTR |
998 | /* Recalculate the number of chars in the RX buffer and issue | 989 | /* Recalculate the number of chars in the RX buffer and issue |
999 | a cmd in case it's higher than the RX high water mark */ | 990 | a cmd in case it's higher than the RX high water mark */ |
1000 | rx_put = readl(&buf_ctrl->rx_put); | 991 | rx_put = readl(&buf_ctrl->rx_put); |
1001 | if (rx_put >= rx_get) | 992 | if (rx_put >= rx_get) |
1002 | char_count = rx_put - rx_get; | 993 | char_count = rx_put - rx_get; |
1003 | else | 994 | else |
1004 | char_count = rx_put - rx_get + rx_bufsize; | 995 | char_count = rx_put - rx_get + rx_bufsize; |
1005 | if (char_count >= readl(&buf_ctrl->rx_threshold) && | 996 | if (char_count >= readl(&buf_ctrl->rx_threshold) && |
1006 | !timer_pending(&cyz_rx_full_timer[ | 997 | !timer_pending(&cyz_rx_full_timer[ |
1007 | info->line])) | 998 | info->line])) |
1008 | mod_timer(&cyz_rx_full_timer[info->line], | 999 | mod_timer(&cyz_rx_full_timer[info->line], |
1009 | jiffies + 1); | 1000 | jiffies + 1); |
1010 | #endif | 1001 | #endif |
1011 | info->idle_stats.recv_idle = jiffies; | 1002 | info->idle_stats.recv_idle = jiffies; |
1012 | tty_schedule_flip(tty); | 1003 | tty_schedule_flip(&info->port); |
1013 | } | 1004 | |
1014 | /* Update rx_get */ | 1005 | /* Update rx_get */ |
1015 | cy_writel(&buf_ctrl->rx_get, new_rx_get); | 1006 | cy_writel(&buf_ctrl->rx_get, new_rx_get); |
1016 | } | ||
1017 | } | 1007 | } |
1018 | 1008 | ||
1019 | static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) | 1009 | static void cyz_handle_tx(struct cyclades_port *info) |
1020 | { | 1010 | { |
1021 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; | 1011 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; |
1022 | struct cyclades_card *cinfo = info->card; | 1012 | struct cyclades_card *cinfo = info->card; |
1013 | struct tty_struct *tty; | ||
1023 | u8 data; | 1014 | u8 data; |
1024 | unsigned int char_count; | 1015 | unsigned int char_count; |
1025 | #ifdef BLOCKMOVE | 1016 | #ifdef BLOCKMOVE |
@@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) | |||
1039 | else | 1030 | else |
1040 | char_count = tx_get - tx_put - 1; | 1031 | char_count = tx_get - tx_put - 1; |
1041 | 1032 | ||
1042 | if (char_count) { | 1033 | if (!char_count) |
1043 | 1034 | return; | |
1044 | if (tty == NULL) | 1035 | |
1045 | goto ztxdone; | 1036 | tty = tty_port_tty_get(&info->port); |
1037 | if (tty == NULL) | ||
1038 | goto ztxdone; | ||
1046 | 1039 | ||
1047 | if (info->x_char) { /* send special char */ | 1040 | if (info->x_char) { /* send special char */ |
1048 | data = info->x_char; | 1041 | data = info->x_char; |
1049 | 1042 | ||
1050 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); | 1043 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); |
1051 | tx_put = (tx_put + 1) & (tx_bufsize - 1); | 1044 | tx_put = (tx_put + 1) & (tx_bufsize - 1); |
1052 | info->x_char = 0; | 1045 | info->x_char = 0; |
1053 | char_count--; | 1046 | char_count--; |
1054 | info->icount.tx++; | 1047 | info->icount.tx++; |
1055 | } | 1048 | } |
1056 | #ifdef BLOCKMOVE | 1049 | #ifdef BLOCKMOVE |
1057 | while (0 < (small_count = min_t(unsigned int, | 1050 | while (0 < (small_count = min_t(unsigned int, |
1058 | tx_bufsize - tx_put, min_t(unsigned int, | 1051 | tx_bufsize - tx_put, min_t(unsigned int, |
1059 | (SERIAL_XMIT_SIZE - info->xmit_tail), | 1052 | (SERIAL_XMIT_SIZE - info->xmit_tail), |
1060 | min_t(unsigned int, info->xmit_cnt, | 1053 | min_t(unsigned int, info->xmit_cnt, |
1061 | char_count))))) { | 1054 | char_count))))) { |
1062 | 1055 | ||
1063 | memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + | 1056 | memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), |
1064 | tx_put), | 1057 | &info->port.xmit_buf[info->xmit_tail], |
1065 | &info->port.xmit_buf[info->xmit_tail], | 1058 | small_count); |
1066 | small_count); | 1059 | |
1067 | 1060 | tx_put = (tx_put + small_count) & (tx_bufsize - 1); | |
1068 | tx_put = (tx_put + small_count) & (tx_bufsize - 1); | 1061 | char_count -= small_count; |
1069 | char_count -= small_count; | 1062 | info->icount.tx += small_count; |
1070 | info->icount.tx += small_count; | 1063 | info->xmit_cnt -= small_count; |
1071 | info->xmit_cnt -= small_count; | 1064 | info->xmit_tail = (info->xmit_tail + small_count) & |
1072 | info->xmit_tail = (info->xmit_tail + small_count) & | 1065 | (SERIAL_XMIT_SIZE - 1); |
1073 | (SERIAL_XMIT_SIZE - 1); | 1066 | } |
1074 | } | ||
1075 | #else | 1067 | #else |
1076 | while (info->xmit_cnt && char_count) { | 1068 | while (info->xmit_cnt && char_count) { |
1077 | data = info->port.xmit_buf[info->xmit_tail]; | 1069 | data = info->port.xmit_buf[info->xmit_tail]; |
1078 | info->xmit_cnt--; | 1070 | info->xmit_cnt--; |
1079 | info->xmit_tail = (info->xmit_tail + 1) & | 1071 | info->xmit_tail = (info->xmit_tail + 1) & |
1080 | (SERIAL_XMIT_SIZE - 1); | 1072 | (SERIAL_XMIT_SIZE - 1); |
1081 | 1073 | ||
1082 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); | 1074 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); |
1083 | tx_put = (tx_put + 1) & (tx_bufsize - 1); | 1075 | tx_put = (tx_put + 1) & (tx_bufsize - 1); |
1084 | char_count--; | 1076 | char_count--; |
1085 | info->icount.tx++; | 1077 | info->icount.tx++; |
1086 | } | 1078 | } |
1087 | #endif | 1079 | #endif |
1088 | tty_wakeup(tty); | 1080 | tty_wakeup(tty); |
1081 | tty_kref_put(tty); | ||
1089 | ztxdone: | 1082 | ztxdone: |
1090 | /* Update tx_put */ | 1083 | /* Update tx_put */ |
1091 | cy_writel(&buf_ctrl->tx_put, tx_put); | 1084 | cy_writel(&buf_ctrl->tx_put, tx_put); |
1092 | } | ||
1093 | } | 1085 | } |
1094 | 1086 | ||
1095 | static void cyz_handle_cmd(struct cyclades_card *cinfo) | 1087 | static void cyz_handle_cmd(struct cyclades_card *cinfo) |
1096 | { | 1088 | { |
1097 | struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; | 1089 | struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; |
1098 | struct tty_struct *tty; | ||
1099 | struct cyclades_port *info; | 1090 | struct cyclades_port *info; |
1100 | __u32 channel, param, fw_ver; | 1091 | __u32 channel, param, fw_ver; |
1101 | __u8 cmd; | 1092 | __u8 cmd; |
@@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1108 | special_count = 0; | 1099 | special_count = 0; |
1109 | delta_count = 0; | 1100 | delta_count = 0; |
1110 | info = &cinfo->ports[channel]; | 1101 | info = &cinfo->ports[channel]; |
1111 | tty = tty_port_tty_get(&info->port); | ||
1112 | if (tty == NULL) | ||
1113 | continue; | ||
1114 | 1102 | ||
1115 | switch (cmd) { | 1103 | switch (cmd) { |
1116 | case C_CM_PR_ERROR: | 1104 | case C_CM_PR_ERROR: |
1117 | tty_insert_flip_char(tty, 0, TTY_PARITY); | 1105 | tty_insert_flip_char(&info->port, 0, TTY_PARITY); |
1118 | info->icount.rx++; | 1106 | info->icount.rx++; |
1119 | special_count++; | 1107 | special_count++; |
1120 | break; | 1108 | break; |
1121 | case C_CM_FR_ERROR: | 1109 | case C_CM_FR_ERROR: |
1122 | tty_insert_flip_char(tty, 0, TTY_FRAME); | 1110 | tty_insert_flip_char(&info->port, 0, TTY_FRAME); |
1123 | info->icount.rx++; | 1111 | info->icount.rx++; |
1124 | special_count++; | 1112 | special_count++; |
1125 | break; | 1113 | break; |
1126 | case C_CM_RXBRK: | 1114 | case C_CM_RXBRK: |
1127 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 1115 | tty_insert_flip_char(&info->port, 0, TTY_BREAK); |
1128 | info->icount.rx++; | 1116 | info->icount.rx++; |
1129 | special_count++; | 1117 | special_count++; |
1130 | break; | 1118 | break; |
@@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1136 | readl(&info->u.cyz.ch_ctrl->rs_status); | 1124 | readl(&info->u.cyz.ch_ctrl->rs_status); |
1137 | if (dcd & C_RS_DCD) | 1125 | if (dcd & C_RS_DCD) |
1138 | wake_up_interruptible(&info->port.open_wait); | 1126 | wake_up_interruptible(&info->port.open_wait); |
1139 | else | 1127 | else { |
1140 | tty_hangup(tty); | 1128 | struct tty_struct *tty; |
1129 | tty = tty_port_tty_get(&info->port); | ||
1130 | if (tty) { | ||
1131 | tty_hangup(tty); | ||
1132 | tty_kref_put(tty); | ||
1133 | } | ||
1134 | } | ||
1141 | } | 1135 | } |
1142 | break; | 1136 | break; |
1143 | case C_CM_MCTS: | 1137 | case C_CM_MCTS: |
@@ -1166,7 +1160,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1166 | printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " | 1160 | printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " |
1167 | "port %ld\n", info->card, channel); | 1161 | "port %ld\n", info->card, channel); |
1168 | #endif | 1162 | #endif |
1169 | cyz_handle_rx(info, tty); | 1163 | cyz_handle_rx(info); |
1170 | break; | 1164 | break; |
1171 | case C_CM_TXBEMPTY: | 1165 | case C_CM_TXBEMPTY: |
1172 | case C_CM_TXLOWWM: | 1166 | case C_CM_TXLOWWM: |
@@ -1176,7 +1170,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1176 | printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " | 1170 | printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " |
1177 | "port %ld\n", info->card, channel); | 1171 | "port %ld\n", info->card, channel); |
1178 | #endif | 1172 | #endif |
1179 | cyz_handle_tx(info, tty); | 1173 | cyz_handle_tx(info); |
1180 | break; | 1174 | break; |
1181 | #endif /* CONFIG_CYZ_INTR */ | 1175 | #endif /* CONFIG_CYZ_INTR */ |
1182 | case C_CM_FATAL: | 1176 | case C_CM_FATAL: |
@@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) | |||
1188 | if (delta_count) | 1182 | if (delta_count) |
1189 | wake_up_interruptible(&info->port.delta_msr_wait); | 1183 | wake_up_interruptible(&info->port.delta_msr_wait); |
1190 | if (special_count) | 1184 | if (special_count) |
1191 | tty_schedule_flip(tty); | 1185 | tty_schedule_flip(&info->port); |
1192 | tty_kref_put(tty); | ||
1193 | } | 1186 | } |
1194 | } | 1187 | } |
1195 | 1188 | ||
@@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg) | |||
1255 | cyz_handle_cmd(cinfo); | 1248 | cyz_handle_cmd(cinfo); |
1256 | 1249 | ||
1257 | for (port = 0; port < cinfo->nports; port++) { | 1250 | for (port = 0; port < cinfo->nports; port++) { |
1258 | struct tty_struct *tty; | ||
1259 | |||
1260 | info = &cinfo->ports[port]; | 1251 | info = &cinfo->ports[port]; |
1261 | tty = tty_port_tty_get(&info->port); | ||
1262 | /* OK to pass NULL to the handle functions below. | ||
1263 | They need to drop the data in that case. */ | ||
1264 | 1252 | ||
1265 | if (!info->throttle) | 1253 | if (!info->throttle) |
1266 | cyz_handle_rx(info, tty); | 1254 | cyz_handle_rx(info); |
1267 | cyz_handle_tx(info, tty); | 1255 | cyz_handle_tx(info); |
1268 | tty_kref_put(tty); | ||
1269 | } | 1256 | } |
1270 | /* poll every 'cyz_polling_cycle' period */ | 1257 | /* poll every 'cyz_polling_cycle' period */ |
1271 | expires = jiffies + cyz_polling_cycle; | 1258 | expires = jiffies + cyz_polling_cycle; |