diff options
-rw-r--r-- | drivers/char/mxser_new.c | 111 | ||||
-rw-r--r-- | drivers/char/mxser_new.h | 14 |
2 files changed, 105 insertions, 20 deletions
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 0b66056cd400..4c805496fb36 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c | |||
@@ -49,7 +49,7 @@ | |||
49 | 49 | ||
50 | #include "mxser_new.h" | 50 | #include "mxser_new.h" |
51 | 51 | ||
52 | #define MXSER_VERSION "2.0" | 52 | #define MXSER_VERSION "2.0.1" /* 1.9.15 */ |
53 | #define MXSERMAJOR 174 | 53 | #define MXSERMAJOR 174 |
54 | #define MXSERCUMAJOR 175 | 54 | #define MXSERCUMAJOR 175 |
55 | 55 | ||
@@ -179,6 +179,18 @@ static struct pci_device_id mxser_pcibrds[] = { | |||
179 | }; | 179 | }; |
180 | MODULE_DEVICE_TABLE(pci, mxser_pcibrds); | 180 | MODULE_DEVICE_TABLE(pci, mxser_pcibrds); |
181 | 181 | ||
182 | static int mxvar_baud_table[] = { | ||
183 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, | ||
184 | 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 | ||
185 | }; | ||
186 | static unsigned int mxvar_baud_table1[] = { | ||
187 | 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, | ||
188 | B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600 | ||
189 | }; | ||
190 | #define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table) | ||
191 | |||
192 | #define B_SPEC B2000000 | ||
193 | |||
182 | static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; | 194 | static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; |
183 | static int ttymajor = MXSERMAJOR; | 195 | static int ttymajor = MXSERMAJOR; |
184 | static int calloutmajor = MXSERCUMAJOR; | 196 | static int calloutmajor = MXSERCUMAJOR; |
@@ -240,6 +252,7 @@ struct mxser_port { | |||
240 | long realbaud; | 252 | long realbaud; |
241 | int type; /* UART type */ | 253 | int type; /* UART type */ |
242 | int flags; /* defined in tty.h */ | 254 | int flags; /* defined in tty.h */ |
255 | int speed; | ||
243 | 256 | ||
244 | int x_char; /* xon/xoff character */ | 257 | int x_char; /* xon/xoff character */ |
245 | int IER; /* Interrupt Enable Register */ | 258 | int IER; /* Interrupt Enable Register */ |
@@ -444,10 +457,10 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, | |||
444 | 457 | ||
445 | static int mxser_set_baud(struct mxser_port *info, long newspd) | 458 | static int mxser_set_baud(struct mxser_port *info, long newspd) |
446 | { | 459 | { |
460 | unsigned int i; | ||
447 | int quot = 0; | 461 | int quot = 0; |
448 | unsigned char cval; | 462 | unsigned char cval; |
449 | int ret = 0; | 463 | int ret = 0; |
450 | unsigned long flags; | ||
451 | 464 | ||
452 | if (!info->tty || !info->tty->termios) | 465 | if (!info->tty || !info->tty->termios) |
453 | return ret; | 466 | return ret; |
@@ -459,29 +472,34 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
459 | return 0; | 472 | return 0; |
460 | 473 | ||
461 | info->realbaud = newspd; | 474 | info->realbaud = newspd; |
462 | if (newspd == 134) { | 475 | for (i = 0; i < BAUD_TABLE_NO; i++) |
463 | quot = (2 * info->baud_base / 269); | 476 | if (newspd == mxvar_baud_table[i]) |
464 | } else if (newspd) { | 477 | break; |
465 | quot = info->baud_base / newspd; | 478 | if (i == BAUD_TABLE_NO) { |
466 | if (quot == 0) | 479 | quot = info->baud_base / info->speed; |
467 | quot = 1; | 480 | if (info->speed <= 0 || info->speed > info->max_baud) |
481 | quot = 0; | ||
468 | } else { | 482 | } else { |
469 | quot = 0; | 483 | if (newspd == 134) { |
484 | quot = (2 * info->baud_base / 269); | ||
485 | } else if (newspd) { | ||
486 | quot = info->baud_base / newspd; | ||
487 | if (quot == 0) | ||
488 | quot = 1; | ||
489 | } else { | ||
490 | quot = 0; | ||
491 | } | ||
470 | } | 492 | } |
471 | 493 | ||
472 | info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); | 494 | info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); |
473 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ | 495 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ |
474 | 496 | ||
475 | if (quot) { | 497 | if (quot) { |
476 | spin_lock_irqsave(&info->slock, flags); | ||
477 | info->MCR |= UART_MCR_DTR; | 498 | info->MCR |= UART_MCR_DTR; |
478 | outb(info->MCR, info->ioaddr + UART_MCR); | 499 | outb(info->MCR, info->ioaddr + UART_MCR); |
479 | spin_unlock_irqrestore(&info->slock, flags); | ||
480 | } else { | 500 | } else { |
481 | spin_lock_irqsave(&info->slock, flags); | ||
482 | info->MCR &= ~UART_MCR_DTR; | 501 | info->MCR &= ~UART_MCR_DTR; |
483 | outb(info->MCR, info->ioaddr + UART_MCR); | 502 | outb(info->MCR, info->ioaddr + UART_MCR); |
484 | spin_unlock_irqrestore(&info->slock, flags); | ||
485 | return ret; | 503 | return ret; |
486 | } | 504 | } |
487 | 505 | ||
@@ -493,6 +511,18 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
493 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ | 511 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ |
494 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | 512 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ |
495 | 513 | ||
514 | if (i == BAUD_TABLE_NO) { | ||
515 | quot = info->baud_base % info->speed; | ||
516 | quot *= 8; | ||
517 | if ((quot % info->speed) > (info->speed / 2)) { | ||
518 | quot /= info->speed; | ||
519 | quot++; | ||
520 | } else { | ||
521 | quot /= info->speed; | ||
522 | } | ||
523 | SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot); | ||
524 | } else | ||
525 | SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0); | ||
496 | 526 | ||
497 | return ret; | 527 | return ret; |
498 | } | 528 | } |
@@ -508,7 +538,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
508 | int ret = 0; | 538 | int ret = 0; |
509 | unsigned char status; | 539 | unsigned char status; |
510 | long baud; | 540 | long baud; |
511 | unsigned long flags; | ||
512 | 541 | ||
513 | if (!info->tty || !info->tty->termios) | 542 | if (!info->tty || !info->tty->termios) |
514 | return ret; | 543 | return ret; |
@@ -517,7 +546,10 @@ static int mxser_change_speed(struct mxser_port *info, | |||
517 | return ret; | 546 | return ret; |
518 | 547 | ||
519 | if (mxser_set_baud_method[info->tty->index] == 0) { | 548 | if (mxser_set_baud_method[info->tty->index] == 0) { |
520 | baud = tty_get_baud_rate(info->tty); | 549 | if ((cflag & CBAUD) == B_SPEC) |
550 | baud = info->speed; | ||
551 | else | ||
552 | baud = tty_get_baud_rate(info->tty); | ||
521 | mxser_set_baud(info, baud); | 553 | mxser_set_baud(info, baud); |
522 | } | 554 | } |
523 | 555 | ||
@@ -656,7 +688,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
656 | } | 688 | } |
657 | } | 689 | } |
658 | if (info->board->chip_flag) { | 690 | if (info->board->chip_flag) { |
659 | spin_lock_irqsave(&info->slock, flags); | ||
660 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); | 691 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); |
661 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); | 692 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); |
662 | if (I_IXON(info->tty)) { | 693 | if (I_IXON(info->tty)) { |
@@ -669,7 +700,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
669 | } else { | 700 | } else { |
670 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | 701 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); |
671 | } | 702 | } |
672 | spin_unlock_irqrestore(&info->slock, flags); | ||
673 | } | 703 | } |
674 | 704 | ||
675 | 705 | ||
@@ -822,8 +852,8 @@ static int mxser_startup(struct mxser_port *info) | |||
822 | /* | 852 | /* |
823 | * and set the speed of the serial port | 853 | * and set the speed of the serial port |
824 | */ | 854 | */ |
825 | spin_unlock_irqrestore(&info->slock, flags); | ||
826 | mxser_change_speed(info, NULL); | 855 | mxser_change_speed(info, NULL); |
856 | spin_unlock_irqrestore(&info->slock, flags); | ||
827 | 857 | ||
828 | info->flags |= ASYNC_INITIALIZED; | 858 | info->flags |= ASYNC_INITIALIZED; |
829 | return 0; | 859 | return 0; |
@@ -1195,6 +1225,7 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1195 | struct serial_struct __user *new_info) | 1225 | struct serial_struct __user *new_info) |
1196 | { | 1226 | { |
1197 | struct serial_struct new_serial; | 1227 | struct serial_struct new_serial; |
1228 | unsigned long sl_flags; | ||
1198 | unsigned int flags; | 1229 | unsigned int flags; |
1199 | int retval = 0; | 1230 | int retval = 0; |
1200 | 1231 | ||
@@ -1237,8 +1268,11 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1237 | process_txrx_fifo(info); | 1268 | process_txrx_fifo(info); |
1238 | 1269 | ||
1239 | if (info->flags & ASYNC_INITIALIZED) { | 1270 | if (info->flags & ASYNC_INITIALIZED) { |
1240 | if (flags != (info->flags & ASYNC_SPD_MASK)) | 1271 | if (flags != (info->flags & ASYNC_SPD_MASK)) { |
1272 | spin_lock_irqsave(&info->slock, sl_flags); | ||
1241 | mxser_change_speed(info, NULL); | 1273 | mxser_change_speed(info, NULL); |
1274 | spin_unlock_irqrestore(&info->slock, sl_flags); | ||
1275 | } | ||
1242 | } else | 1276 | } else |
1243 | retval = mxser_startup(info); | 1277 | retval = mxser_startup(info); |
1244 | 1278 | ||
@@ -1615,6 +1649,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1615 | struct serial_icounter_struct __user *p_cuser; | 1649 | struct serial_icounter_struct __user *p_cuser; |
1616 | unsigned long templ; | 1650 | unsigned long templ; |
1617 | unsigned long flags; | 1651 | unsigned long flags; |
1652 | unsigned int i; | ||
1618 | void __user *argp = (void __user *)arg; | 1653 | void __user *argp = (void __user *)arg; |
1619 | int retval; | 1654 | int retval; |
1620 | 1655 | ||
@@ -1653,6 +1688,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1653 | return 0; | 1688 | return 0; |
1654 | } | 1689 | } |
1655 | 1690 | ||
1691 | if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) { | ||
1692 | int speed; | ||
1693 | |||
1694 | if (get_user(speed, (int __user *)argp)) | ||
1695 | return -EFAULT; | ||
1696 | if (speed <= 0 || speed > info->max_baud) | ||
1697 | return -EFAULT; | ||
1698 | if (!info->tty || !info->tty->termios || !info->ioaddr) | ||
1699 | return 0; | ||
1700 | info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX); | ||
1701 | for (i = 0; i < BAUD_TABLE_NO; i++) | ||
1702 | if (speed == mxvar_baud_table[i]) | ||
1703 | break; | ||
1704 | if (i == BAUD_TABLE_NO) { | ||
1705 | info->tty->termios->c_cflag |= B_SPEC; | ||
1706 | } else if (speed != 0) | ||
1707 | info->tty->termios->c_cflag |= mxvar_baud_table1[i]; | ||
1708 | |||
1709 | info->speed = speed; | ||
1710 | spin_lock_irqsave(&info->slock, flags); | ||
1711 | mxser_change_speed(info, 0); | ||
1712 | spin_unlock_irqrestore(&info->slock, flags); | ||
1713 | |||
1714 | return 0; | ||
1715 | } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) { | ||
1716 | if (copy_to_user(argp, &info->speed, sizeof(int))) | ||
1717 | return -EFAULT; | ||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1656 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && | 1721 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && |
1657 | test_bit(TTY_IO_ERROR, &tty->flags)) | 1722 | test_bit(TTY_IO_ERROR, &tty->flags)) |
1658 | return -EIO; | 1723 | return -EIO; |
@@ -1770,7 +1835,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1770 | long baud; | 1835 | long baud; |
1771 | if (get_user(baud, (long __user *)argp)) | 1836 | if (get_user(baud, (long __user *)argp)) |
1772 | return -EFAULT; | 1837 | return -EFAULT; |
1838 | spin_lock_irqsave(&info->slock, flags); | ||
1773 | mxser_set_baud(info, baud); | 1839 | mxser_set_baud(info, baud); |
1840 | spin_unlock_irqrestore(&info->slock, flags); | ||
1774 | return 0; | 1841 | return 0; |
1775 | } | 1842 | } |
1776 | case MOXA_ASPP_GETBAUD: | 1843 | case MOXA_ASPP_GETBAUD: |
@@ -1947,7 +2014,9 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi | |||
1947 | if ((tty->termios->c_cflag != old_termios->c_cflag) || | 2014 | if ((tty->termios->c_cflag != old_termios->c_cflag) || |
1948 | (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { | 2015 | (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { |
1949 | 2016 | ||
2017 | spin_lock_irqsave(&info->slock, flags); | ||
1950 | mxser_change_speed(info, old_termios); | 2018 | mxser_change_speed(info, old_termios); |
2019 | spin_unlock_irqrestore(&info->slock, flags); | ||
1951 | 2020 | ||
1952 | if ((old_termios->c_cflag & CRTSCTS) && | 2021 | if ((old_termios->c_cflag & CRTSCTS) && |
1953 | !(tty->termios->c_cflag & CRTSCTS)) { | 2022 | !(tty->termios->c_cflag & CRTSCTS)) { |
@@ -2137,7 +2206,8 @@ intr_old: | |||
2137 | } else if (*status & UART_LSR_OE) { | 2206 | } else if (*status & UART_LSR_OE) { |
2138 | flag = TTY_OVERRUN; | 2207 | flag = TTY_OVERRUN; |
2139 | port->icount.overrun++; | 2208 | port->icount.overrun++; |
2140 | } | 2209 | } else |
2210 | flag = TTY_BREAK; | ||
2141 | } | 2211 | } |
2142 | tty_insert_flip_char(tty, ch, flag); | 2212 | tty_insert_flip_char(tty, ch, flag); |
2143 | cnt++; | 2213 | cnt++; |
@@ -2385,6 +2455,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, | |||
2385 | info->normal_termios = mxvar_sdriver->init_termios; | 2455 | info->normal_termios = mxvar_sdriver->init_termios; |
2386 | init_waitqueue_head(&info->open_wait); | 2456 | init_waitqueue_head(&info->open_wait); |
2387 | init_waitqueue_head(&info->delta_msr_wait); | 2457 | init_waitqueue_head(&info->delta_msr_wait); |
2458 | info->speed = 9600; | ||
2388 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); | 2459 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); |
2389 | info->err_shadow = 0; | 2460 | info->err_shadow = 0; |
2390 | spin_lock_init(&info->slock); | 2461 | spin_lock_init(&info->slock); |
diff --git a/drivers/char/mxser_new.h b/drivers/char/mxser_new.h index 04fa5fc9226d..d42f7766c652 100644 --- a/drivers/char/mxser_new.h +++ b/drivers/char/mxser_new.h | |||
@@ -35,6 +35,8 @@ | |||
35 | #define MOXA_ASPP_LSTATUS (MOXA + 74) | 35 | #define MOXA_ASPP_LSTATUS (MOXA + 74) |
36 | #define MOXA_ASPP_MON_EXT (MOXA + 75) | 36 | #define MOXA_ASPP_MON_EXT (MOXA + 75) |
37 | #define MOXA_SET_BAUD_METHOD (MOXA + 76) | 37 | #define MOXA_SET_BAUD_METHOD (MOXA + 76) |
38 | #define MOXA_SET_SPECIAL_BAUD_RATE (MOXA + 77) | ||
39 | #define MOXA_GET_SPECIAL_BAUD_RATE (MOXA + 78) | ||
38 | 40 | ||
39 | /* --------------------------------------------------- */ | 41 | /* --------------------------------------------------- */ |
40 | 42 | ||
@@ -212,6 +214,18 @@ | |||
212 | outb(__oldlcr, (info)->ioaddr+UART_LCR); \ | 214 | outb(__oldlcr, (info)->ioaddr+UART_LCR); \ |
213 | } while (0) | 215 | } while (0) |
214 | 216 | ||
217 | #define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \ | ||
218 | u8 __oldlcr, __efr; \ | ||
219 | __oldlcr = inb((baseio)+UART_LCR); \ | ||
220 | outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ | ||
221 | __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ | ||
222 | __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ | ||
223 | __efr |= MOXA_MUST_EFR_BANK2; \ | ||
224 | outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ | ||
225 | outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \ | ||
226 | outb(__oldlcr, (baseio)+UART_LCR); \ | ||
227 | } while (0) | ||
228 | |||
215 | #define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \ | 229 | #define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \ |
216 | u8 __oldlcr, __efr; \ | 230 | u8 __oldlcr, __efr; \ |
217 | __oldlcr = inb((baseio)+UART_LCR); \ | 231 | __oldlcr = inb((baseio)+UART_LCR); \ |