diff options
Diffstat (limited to 'drivers/serial/68328serial.c')
| -rw-r--r-- | drivers/serial/68328serial.c | 102 |
1 files changed, 44 insertions, 58 deletions
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index b88a7c1158af..bff94541991c 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c | |||
| @@ -131,17 +131,6 @@ static int m68328_console_baud = CONSOLE_BAUD_RATE; | |||
| 131 | static int m68328_console_cbaud = DEFAULT_CBAUD; | 131 | static int m68328_console_cbaud = DEFAULT_CBAUD; |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | /* | ||
| 135 | * tmp_buf is used as a temporary buffer by serial_write. We need to | ||
| 136 | * lock it in case the memcpy_fromfs blocks while swapping in a page, | ||
| 137 | * and some other program tries to do a serial write at the same time. | ||
| 138 | * Since the lock will only come under contention when the system is | ||
| 139 | * swapping and available memory is low, it makes sense to share one | ||
| 140 | * buffer across all the serial ports, since it significantly saves | ||
| 141 | * memory if large numbers of serial ports are open. | ||
| 142 | */ | ||
| 143 | static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */ | ||
| 144 | |||
| 145 | static inline int serial_paranoia_check(struct m68k_serial *info, | 134 | static inline int serial_paranoia_check(struct m68k_serial *info, |
| 146 | char *name, const char *routine) | 135 | char *name, const char *routine) |
| 147 | { | 136 | { |
| @@ -211,16 +200,16 @@ static void rs_stop(struct tty_struct *tty) | |||
| 211 | if (serial_paranoia_check(info, tty->name, "rs_stop")) | 200 | if (serial_paranoia_check(info, tty->name, "rs_stop")) |
| 212 | return; | 201 | return; |
| 213 | 202 | ||
| 214 | save_flags(flags); cli(); | 203 | local_irq_save(flags); |
| 215 | uart->ustcnt &= ~USTCNT_TXEN; | 204 | uart->ustcnt &= ~USTCNT_TXEN; |
| 216 | restore_flags(flags); | 205 | local_irq_restore(flags); |
| 217 | } | 206 | } |
| 218 | 207 | ||
| 219 | static void rs_put_char(char ch) | 208 | static void rs_put_char(char ch) |
| 220 | { | 209 | { |
| 221 | int flags, loops = 0; | 210 | int flags, loops = 0; |
| 222 | 211 | ||
| 223 | save_flags(flags); cli(); | 212 | local_irq_save(flags); |
| 224 | 213 | ||
| 225 | while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) { | 214 | while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) { |
| 226 | loops++; | 215 | loops++; |
| @@ -229,7 +218,7 @@ static void rs_put_char(char ch) | |||
| 229 | 218 | ||
| 230 | UTX_TXDATA = ch; | 219 | UTX_TXDATA = ch; |
| 231 | udelay(5); | 220 | udelay(5); |
| 232 | restore_flags(flags); | 221 | local_irq_restore(flags); |
| 233 | } | 222 | } |
| 234 | 223 | ||
| 235 | static void rs_start(struct tty_struct *tty) | 224 | static void rs_start(struct tty_struct *tty) |
| @@ -241,7 +230,7 @@ static void rs_start(struct tty_struct *tty) | |||
| 241 | if (serial_paranoia_check(info, tty->name, "rs_start")) | 230 | if (serial_paranoia_check(info, tty->name, "rs_start")) |
| 242 | return; | 231 | return; |
| 243 | 232 | ||
| 244 | save_flags(flags); cli(); | 233 | local_irq_save(flags); |
| 245 | if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { | 234 | if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) { |
| 246 | #ifdef USE_INTS | 235 | #ifdef USE_INTS |
| 247 | uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; | 236 | uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK; |
| @@ -249,7 +238,7 @@ static void rs_start(struct tty_struct *tty) | |||
| 249 | uart->ustcnt |= USTCNT_TXEN; | 238 | uart->ustcnt |= USTCNT_TXEN; |
| 250 | #endif | 239 | #endif |
| 251 | } | 240 | } |
| 252 | restore_flags(flags); | 241 | local_irq_restore(flags); |
| 253 | } | 242 | } |
| 254 | 243 | ||
| 255 | /* Drop into either the boot monitor or kadb upon receiving a break | 244 | /* Drop into either the boot monitor or kadb upon receiving a break |
| @@ -327,14 +316,6 @@ static void receive_chars(struct m68k_serial *info, struct pt_regs *regs, | |||
| 327 | if(!tty) | 316 | if(!tty) |
| 328 | goto clear_and_exit; | 317 | goto clear_and_exit; |
| 329 | 318 | ||
| 330 | /* | ||
| 331 | * Make sure that we do not overflow the buffer | ||
| 332 | */ | ||
| 333 | if (tty_request_buffer_room(tty, 1) == 0) { | ||
| 334 | tty_schedule_flip(tty); | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | |||
| 338 | flag = TTY_NORMAL; | 319 | flag = TTY_NORMAL; |
| 339 | 320 | ||
| 340 | if(rx & URX_PARITY_ERROR) { | 321 | if(rx & URX_PARITY_ERROR) { |
| @@ -473,7 +454,7 @@ static int startup(struct m68k_serial * info) | |||
| 473 | return -ENOMEM; | 454 | return -ENOMEM; |
| 474 | } | 455 | } |
| 475 | 456 | ||
| 476 | save_flags(flags); cli(); | 457 | local_irq_save(flags); |
| 477 | 458 | ||
| 478 | /* | 459 | /* |
| 479 | * Clear the FIFO buffers and disable them | 460 | * Clear the FIFO buffers and disable them |
| @@ -506,7 +487,7 @@ static int startup(struct m68k_serial * info) | |||
| 506 | change_speed(info); | 487 | change_speed(info); |
| 507 | 488 | ||
| 508 | info->flags |= S_INITIALIZED; | 489 | info->flags |= S_INITIALIZED; |
| 509 | restore_flags(flags); | 490 | local_irq_restore(flags); |
| 510 | return 0; | 491 | return 0; |
| 511 | } | 492 | } |
| 512 | 493 | ||
| @@ -523,7 +504,7 @@ static void shutdown(struct m68k_serial * info) | |||
| 523 | if (!(info->flags & S_INITIALIZED)) | 504 | if (!(info->flags & S_INITIALIZED)) |
| 524 | return; | 505 | return; |
| 525 | 506 | ||
| 526 | save_flags(flags); cli(); /* Disable interrupts */ | 507 | local_irq_save(flags); |
| 527 | 508 | ||
| 528 | if (info->xmit_buf) { | 509 | if (info->xmit_buf) { |
| 529 | free_page((unsigned long) info->xmit_buf); | 510 | free_page((unsigned long) info->xmit_buf); |
| @@ -534,7 +515,7 @@ static void shutdown(struct m68k_serial * info) | |||
| 534 | set_bit(TTY_IO_ERROR, &info->tty->flags); | 515 | set_bit(TTY_IO_ERROR, &info->tty->flags); |
| 535 | 516 | ||
| 536 | info->flags &= ~S_INITIALIZED; | 517 | info->flags &= ~S_INITIALIZED; |
| 537 | restore_flags(flags); | 518 | local_irq_restore(flags); |
| 538 | } | 519 | } |
| 539 | 520 | ||
| 540 | struct { | 521 | struct { |
| @@ -655,24 +636,24 @@ static void rs_fair_output(void) | |||
| 655 | if (info == 0) return; | 636 | if (info == 0) return; |
| 656 | if (info->xmit_buf == 0) return; | 637 | if (info->xmit_buf == 0) return; |
| 657 | 638 | ||
| 658 | save_flags(flags); cli(); | 639 | local_irq_save(flags); |
| 659 | left = info->xmit_cnt; | 640 | left = info->xmit_cnt; |
| 660 | while (left != 0) { | 641 | while (left != 0) { |
| 661 | c = info->xmit_buf[info->xmit_tail]; | 642 | c = info->xmit_buf[info->xmit_tail]; |
| 662 | info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); | 643 | info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); |
| 663 | info->xmit_cnt--; | 644 | info->xmit_cnt--; |
| 664 | restore_flags(flags); | 645 | local_irq_restore(flags); |
| 665 | 646 | ||
| 666 | rs_put_char(c); | 647 | rs_put_char(c); |
| 667 | 648 | ||
| 668 | save_flags(flags); cli(); | 649 | local_irq_save(flags); |
| 669 | left = min(info->xmit_cnt, left-1); | 650 | left = min(info->xmit_cnt, left-1); |
| 670 | } | 651 | } |
| 671 | 652 | ||
| 672 | /* Last character is being transmitted now (hopefully). */ | 653 | /* Last character is being transmitted now (hopefully). */ |
| 673 | udelay(5); | 654 | udelay(5); |
| 674 | 655 | ||
| 675 | restore_flags(flags); | 656 | local_irq_restore(flags); |
| 676 | return; | 657 | return; |
| 677 | } | 658 | } |
| 678 | 659 | ||
| @@ -720,11 +701,11 @@ static void rs_flush_chars(struct tty_struct *tty) | |||
| 720 | #endif | 701 | #endif |
| 721 | 702 | ||
| 722 | /* Enable transmitter */ | 703 | /* Enable transmitter */ |
| 723 | save_flags(flags); cli(); | 704 | local_irq_save(flags); |
| 724 | 705 | ||
| 725 | if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || | 706 | if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || |
| 726 | !info->xmit_buf) { | 707 | !info->xmit_buf) { |
| 727 | restore_flags(flags); | 708 | local_irq_restore(flags); |
| 728 | return; | 709 | return; |
| 729 | } | 710 | } |
| 730 | 711 | ||
| @@ -749,7 +730,7 @@ static void rs_flush_chars(struct tty_struct *tty) | |||
| 749 | while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); | 730 | while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5); |
| 750 | } | 731 | } |
| 751 | #endif | 732 | #endif |
| 752 | restore_flags(flags); | 733 | local_irq_restore(flags); |
| 753 | } | 734 | } |
| 754 | 735 | ||
| 755 | extern void console_printn(const char * b, int count); | 736 | extern void console_printn(const char * b, int count); |
| @@ -768,18 +749,22 @@ static int rs_write(struct tty_struct * tty, | |||
| 768 | if (!tty || !info->xmit_buf) | 749 | if (!tty || !info->xmit_buf) |
| 769 | return 0; | 750 | return 0; |
| 770 | 751 | ||
| 771 | save_flags(flags); | 752 | local_save_flags(flags); |
| 772 | while (1) { | 753 | while (1) { |
| 773 | cli(); | 754 | local_irq_disable(); |
| 774 | c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, | 755 | c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, |
| 775 | SERIAL_XMIT_SIZE - info->xmit_head)); | 756 | SERIAL_XMIT_SIZE - info->xmit_head)); |
| 757 | local_irq_restore(flags); | ||
| 758 | |||
| 776 | if (c <= 0) | 759 | if (c <= 0) |
| 777 | break; | 760 | break; |
| 778 | 761 | ||
| 779 | memcpy(info->xmit_buf + info->xmit_head, buf, c); | 762 | memcpy(info->xmit_buf + info->xmit_head, buf, c); |
| 763 | |||
| 764 | local_irq_disable(); | ||
| 780 | info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); | 765 | info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); |
| 781 | info->xmit_cnt += c; | 766 | info->xmit_cnt += c; |
| 782 | restore_flags(flags); | 767 | local_irq_restore(flags); |
| 783 | buf += c; | 768 | buf += c; |
| 784 | count -= c; | 769 | count -= c; |
| 785 | total += c; | 770 | total += c; |
| @@ -787,7 +772,7 @@ static int rs_write(struct tty_struct * tty, | |||
| 787 | 772 | ||
| 788 | if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { | 773 | if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { |
| 789 | /* Enable transmitter */ | 774 | /* Enable transmitter */ |
| 790 | cli(); | 775 | local_irq_disable(); |
| 791 | #ifndef USE_INTS | 776 | #ifndef USE_INTS |
| 792 | while(info->xmit_cnt) { | 777 | while(info->xmit_cnt) { |
| 793 | #endif | 778 | #endif |
| @@ -807,9 +792,9 @@ static int rs_write(struct tty_struct * tty, | |||
| 807 | #ifndef USE_INTS | 792 | #ifndef USE_INTS |
| 808 | } | 793 | } |
| 809 | #endif | 794 | #endif |
| 810 | restore_flags(flags); | 795 | local_irq_restore(flags); |
| 811 | } | 796 | } |
| 812 | restore_flags(flags); | 797 | |
| 813 | return total; | 798 | return total; |
| 814 | } | 799 | } |
| 815 | 800 | ||
| @@ -838,12 +823,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty) | |||
| 838 | static void rs_flush_buffer(struct tty_struct *tty) | 823 | static void rs_flush_buffer(struct tty_struct *tty) |
| 839 | { | 824 | { |
| 840 | struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; | 825 | struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; |
| 826 | unsigned long flags; | ||
| 841 | 827 | ||
| 842 | if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) | 828 | if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) |
| 843 | return; | 829 | return; |
| 844 | cli(); | 830 | local_irq_save(flags); |
| 845 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | 831 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
| 846 | sti(); | 832 | local_irq_restore(flags); |
| 847 | tty_wakeup(tty); | 833 | tty_wakeup(tty); |
| 848 | } | 834 | } |
| 849 | 835 | ||
| @@ -973,14 +959,15 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) | |||
| 973 | m68328_uart *uart = &uart_addr[info->line]; | 959 | m68328_uart *uart = &uart_addr[info->line]; |
| 974 | #endif | 960 | #endif |
| 975 | unsigned char status; | 961 | unsigned char status; |
| 962 | unsigned long flags; | ||
| 976 | 963 | ||
| 977 | cli(); | 964 | local_irq_save(flags); |
| 978 | #ifdef CONFIG_SERIAL_68328_RTS_CTS | 965 | #ifdef CONFIG_SERIAL_68328_RTS_CTS |
| 979 | status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; | 966 | status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0; |
| 980 | #else | 967 | #else |
| 981 | status = 0; | 968 | status = 0; |
| 982 | #endif | 969 | #endif |
| 983 | sti(); | 970 | local_irq_restore(flags); |
| 984 | put_user(status,value); | 971 | put_user(status,value); |
| 985 | return 0; | 972 | return 0; |
| 986 | } | 973 | } |
| @@ -994,14 +981,13 @@ static void send_break(struct m68k_serial * info, unsigned int duration) | |||
| 994 | unsigned long flags; | 981 | unsigned long flags; |
| 995 | if (!info->port) | 982 | if (!info->port) |
| 996 | return; | 983 | return; |
| 997 | save_flags(flags); | 984 | local_irq_save(flags); |
| 998 | cli(); | ||
| 999 | #ifdef USE_INTS | 985 | #ifdef USE_INTS |
| 1000 | uart->utx.w |= UTX_SEND_BREAK; | 986 | uart->utx.w |= UTX_SEND_BREAK; |
| 1001 | msleep_interruptible(duration); | 987 | msleep_interruptible(duration); |
| 1002 | uart->utx.w &= ~UTX_SEND_BREAK; | 988 | uart->utx.w &= ~UTX_SEND_BREAK; |
| 1003 | #endif | 989 | #endif |
| 1004 | restore_flags(flags); | 990 | local_irq_restore(flags); |
| 1005 | } | 991 | } |
| 1006 | 992 | ||
| 1007 | static int rs_ioctl(struct tty_struct *tty, struct file * file, | 993 | static int rs_ioctl(struct tty_struct *tty, struct file * file, |
| @@ -1060,7 +1046,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, | |||
| 1060 | (struct serial_struct *) arg); | 1046 | (struct serial_struct *) arg); |
| 1061 | case TIOCSERGETLSR: /* Get line status register */ | 1047 | case TIOCSERGETLSR: /* Get line status register */ |
| 1062 | if (access_ok(VERIFY_WRITE, (void *) arg, | 1048 | if (access_ok(VERIFY_WRITE, (void *) arg, |
| 1063 | sizeof(unsigned int)); | 1049 | sizeof(unsigned int))) |
| 1064 | return get_lsr_info(info, (unsigned int *) arg); | 1050 | return get_lsr_info(info, (unsigned int *) arg); |
| 1065 | return -EFAULT; | 1051 | return -EFAULT; |
| 1066 | case TIOCSERGSTRUCT: | 1052 | case TIOCSERGSTRUCT: |
| @@ -1113,10 +1099,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp) | |||
| 1113 | if (!info || serial_paranoia_check(info, tty->name, "rs_close")) | 1099 | if (!info || serial_paranoia_check(info, tty->name, "rs_close")) |
| 1114 | return; | 1100 | return; |
| 1115 | 1101 | ||
| 1116 | save_flags(flags); cli(); | 1102 | local_irq_save(flags); |
| 1117 | 1103 | ||
| 1118 | if (tty_hung_up_p(filp)) { | 1104 | if (tty_hung_up_p(filp)) { |
| 1119 | restore_flags(flags); | 1105 | local_irq_restore(flags); |
| 1120 | return; | 1106 | return; |
| 1121 | } | 1107 | } |
| 1122 | 1108 | ||
| @@ -1138,7 +1124,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) | |||
| 1138 | info->count = 0; | 1124 | info->count = 0; |
| 1139 | } | 1125 | } |
| 1140 | if (info->count) { | 1126 | if (info->count) { |
| 1141 | restore_flags(flags); | 1127 | local_irq_restore(flags); |
| 1142 | return; | 1128 | return; |
| 1143 | } | 1129 | } |
| 1144 | info->flags |= S_CLOSING; | 1130 | info->flags |= S_CLOSING; |
| @@ -1186,7 +1172,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) | |||
| 1186 | } | 1172 | } |
| 1187 | info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); | 1173 | info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); |
| 1188 | wake_up_interruptible(&info->close_wait); | 1174 | wake_up_interruptible(&info->close_wait); |
| 1189 | restore_flags(flags); | 1175 | local_irq_restore(flags); |
| 1190 | } | 1176 | } |
| 1191 | 1177 | ||
| 1192 | /* | 1178 | /* |
| @@ -1262,9 +1248,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, | |||
| 1262 | info->count--; | 1248 | info->count--; |
| 1263 | info->blocked_open++; | 1249 | info->blocked_open++; |
| 1264 | while (1) { | 1250 | while (1) { |
| 1265 | cli(); | 1251 | local_irq_disable(); |
| 1266 | m68k_rtsdtr(info, 1); | 1252 | m68k_rtsdtr(info, 1); |
| 1267 | sti(); | 1253 | local_irq_enable(); |
| 1268 | current->state = TASK_INTERRUPTIBLE; | 1254 | current->state = TASK_INTERRUPTIBLE; |
| 1269 | if (tty_hung_up_p(filp) || | 1255 | if (tty_hung_up_p(filp) || |
| 1270 | !(info->flags & S_INITIALIZED)) { | 1256 | !(info->flags & S_INITIALIZED)) { |
| @@ -1444,7 +1430,7 @@ rs68328_init(void) | |||
| 1444 | return -ENOMEM; | 1430 | return -ENOMEM; |
| 1445 | } | 1431 | } |
| 1446 | 1432 | ||
| 1447 | save_flags(flags); cli(); | 1433 | local_irq_save(flags); |
| 1448 | 1434 | ||
| 1449 | for(i=0;i<NR_PORTS;i++) { | 1435 | for(i=0;i<NR_PORTS;i++) { |
| 1450 | 1436 | ||
| @@ -1489,7 +1475,7 @@ rs68328_init(void) | |||
| 1489 | serial_pm[i]->data = info; | 1475 | serial_pm[i]->data = info; |
| 1490 | #endif | 1476 | #endif |
| 1491 | } | 1477 | } |
| 1492 | restore_flags(flags); | 1478 | local_irq_restore(flags); |
| 1493 | return 0; | 1479 | return 0; |
| 1494 | } | 1480 | } |
| 1495 | 1481 | ||
