diff options
Diffstat (limited to 'drivers/char/mxser_new.c')
-rw-r--r-- | drivers/char/mxser_new.c | 236 |
1 files changed, 131 insertions, 105 deletions
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 1bb030b3a51..9af07e4999d 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c | |||
@@ -49,22 +49,25 @@ | |||
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 | ||
56 | #define MXSER_EVENT_TXLOW 1 | ||
57 | |||
58 | #define MXSER_BOARDS 4 /* Max. boards */ | 56 | #define MXSER_BOARDS 4 /* Max. boards */ |
59 | #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ | 57 | #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ |
60 | #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) | 58 | #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) |
61 | #define MXSER_ISR_PASS_LIMIT 99999L | 59 | #define MXSER_ISR_PASS_LIMIT 100 |
62 | 60 | ||
63 | #define MXSER_ERR_IOADDR -1 | 61 | #define MXSER_ERR_IOADDR -1 |
64 | #define MXSER_ERR_IRQ -2 | 62 | #define MXSER_ERR_IRQ -2 |
65 | #define MXSER_ERR_IRQ_CONFLIT -3 | 63 | #define MXSER_ERR_IRQ_CONFLIT -3 |
66 | #define MXSER_ERR_VECTOR -4 | 64 | #define MXSER_ERR_VECTOR -4 |
67 | 65 | ||
66 | /*CheckIsMoxaMust return value*/ | ||
67 | #define MOXA_OTHER_UART 0x00 | ||
68 | #define MOXA_MUST_MU150_HWID 0x01 | ||
69 | #define MOXA_MUST_MU860_HWID 0x02 | ||
70 | |||
68 | #define WAKEUP_CHARS 256 | 71 | #define WAKEUP_CHARS 256 |
69 | 72 | ||
70 | #define UART_MCR_AFE 0x20 | 73 | #define UART_MCR_AFE 0x20 |
@@ -176,6 +179,18 @@ static struct pci_device_id mxser_pcibrds[] = { | |||
176 | }; | 179 | }; |
177 | MODULE_DEVICE_TABLE(pci, mxser_pcibrds); | 180 | MODULE_DEVICE_TABLE(pci, mxser_pcibrds); |
178 | 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 | |||
179 | static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; | 194 | static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 }; |
180 | static int ttymajor = MXSERMAJOR; | 195 | static int ttymajor = MXSERMAJOR; |
181 | static int calloutmajor = MXSERCUMAJOR; | 196 | static int calloutmajor = MXSERCUMAJOR; |
@@ -237,8 +252,7 @@ struct mxser_port { | |||
237 | long realbaud; | 252 | long realbaud; |
238 | int type; /* UART type */ | 253 | int type; /* UART type */ |
239 | int flags; /* defined in tty.h */ | 254 | int flags; /* defined in tty.h */ |
240 | long session; /* Session of opening process */ | 255 | int speed; |
241 | long pgrp; /* pgrp of opening process */ | ||
242 | 256 | ||
243 | int x_char; /* xon/xoff character */ | 257 | int x_char; /* xon/xoff character */ |
244 | int IER; /* Interrupt Enable Register */ | 258 | int IER; /* Interrupt Enable Register */ |
@@ -267,14 +281,11 @@ struct mxser_port { | |||
267 | int xmit_cnt; | 281 | int xmit_cnt; |
268 | 282 | ||
269 | struct ktermios normal_termios; | 283 | struct ktermios normal_termios; |
270 | struct ktermios callout_termios; | ||
271 | 284 | ||
272 | struct mxser_mon mon_data; | 285 | struct mxser_mon mon_data; |
273 | 286 | ||
274 | spinlock_t slock; | 287 | spinlock_t slock; |
275 | struct work_struct tqueue; | ||
276 | wait_queue_head_t open_wait; | 288 | wait_queue_head_t open_wait; |
277 | wait_queue_head_t close_wait; | ||
278 | wait_queue_head_t delta_msr_wait; | 289 | wait_queue_head_t delta_msr_wait; |
279 | }; | 290 | }; |
280 | 291 | ||
@@ -313,10 +324,9 @@ static int mxvar_diagflag; | |||
313 | static unsigned char mxser_msr[MXSER_PORTS + 1]; | 324 | static unsigned char mxser_msr[MXSER_PORTS + 1]; |
314 | static struct mxser_mon_ext mon_data_ext; | 325 | static struct mxser_mon_ext mon_data_ext; |
315 | static int mxser_set_baud_method[MXSER_PORTS + 1]; | 326 | static int mxser_set_baud_method[MXSER_PORTS + 1]; |
316 | static spinlock_t gm_lock; | ||
317 | 327 | ||
318 | #ifdef CONFIG_PCI | 328 | #ifdef CONFIG_PCI |
319 | static int CheckIsMoxaMust(int io) | 329 | static int __devinit CheckIsMoxaMust(int io) |
320 | { | 330 | { |
321 | u8 oldmcr, hwid; | 331 | u8 oldmcr, hwid; |
322 | int i; | 332 | int i; |
@@ -360,15 +370,6 @@ static void process_txrx_fifo(struct mxser_port *info) | |||
360 | } | 370 | } |
361 | } | 371 | } |
362 | 372 | ||
363 | static void mxser_do_softint(struct work_struct *work) | ||
364 | { | ||
365 | struct mxser_port *info = container_of(work, struct mxser_port, tqueue); | ||
366 | struct tty_struct *tty = info->tty; | ||
367 | |||
368 | if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) | ||
369 | tty_wakeup(tty); | ||
370 | } | ||
371 | |||
372 | static unsigned char mxser_get_msr(int baseaddr, int mode, int port) | 373 | static unsigned char mxser_get_msr(int baseaddr, int mode, int port) |
373 | { | 374 | { |
374 | unsigned char status = 0; | 375 | unsigned char status = 0; |
@@ -456,10 +457,10 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, | |||
456 | 457 | ||
457 | static int mxser_set_baud(struct mxser_port *info, long newspd) | 458 | static int mxser_set_baud(struct mxser_port *info, long newspd) |
458 | { | 459 | { |
460 | unsigned int i; | ||
459 | int quot = 0; | 461 | int quot = 0; |
460 | unsigned char cval; | 462 | unsigned char cval; |
461 | int ret = 0; | 463 | int ret = 0; |
462 | unsigned long flags; | ||
463 | 464 | ||
464 | if (!info->tty || !info->tty->termios) | 465 | if (!info->tty || !info->tty->termios) |
465 | return ret; | 466 | return ret; |
@@ -471,29 +472,34 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
471 | return 0; | 472 | return 0; |
472 | 473 | ||
473 | info->realbaud = newspd; | 474 | info->realbaud = newspd; |
474 | if (newspd == 134) { | 475 | for (i = 0; i < BAUD_TABLE_NO; i++) |
475 | quot = (2 * info->baud_base / 269); | 476 | if (newspd == mxvar_baud_table[i]) |
476 | } else if (newspd) { | 477 | break; |
477 | quot = info->baud_base / newspd; | 478 | if (i == BAUD_TABLE_NO) { |
478 | if (quot == 0) | 479 | quot = info->baud_base / info->speed; |
479 | quot = 1; | 480 | if (info->speed <= 0 || info->speed > info->max_baud) |
481 | quot = 0; | ||
480 | } else { | 482 | } else { |
481 | 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 | } | ||
482 | } | 492 | } |
483 | 493 | ||
484 | 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); |
485 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ | 495 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ |
486 | 496 | ||
487 | if (quot) { | 497 | if (quot) { |
488 | spin_lock_irqsave(&info->slock, flags); | ||
489 | info->MCR |= UART_MCR_DTR; | 498 | info->MCR |= UART_MCR_DTR; |
490 | outb(info->MCR, info->ioaddr + UART_MCR); | 499 | outb(info->MCR, info->ioaddr + UART_MCR); |
491 | spin_unlock_irqrestore(&info->slock, flags); | ||
492 | } else { | 500 | } else { |
493 | spin_lock_irqsave(&info->slock, flags); | ||
494 | info->MCR &= ~UART_MCR_DTR; | 501 | info->MCR &= ~UART_MCR_DTR; |
495 | outb(info->MCR, info->ioaddr + UART_MCR); | 502 | outb(info->MCR, info->ioaddr + UART_MCR); |
496 | spin_unlock_irqrestore(&info->slock, flags); | ||
497 | return ret; | 503 | return ret; |
498 | } | 504 | } |
499 | 505 | ||
@@ -505,6 +511,18 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) | |||
505 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ | 511 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ |
506 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | 512 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ |
507 | 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); | ||
508 | 526 | ||
509 | return ret; | 527 | return ret; |
510 | } | 528 | } |
@@ -520,7 +538,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
520 | int ret = 0; | 538 | int ret = 0; |
521 | unsigned char status; | 539 | unsigned char status; |
522 | long baud; | 540 | long baud; |
523 | unsigned long flags; | ||
524 | 541 | ||
525 | if (!info->tty || !info->tty->termios) | 542 | if (!info->tty || !info->tty->termios) |
526 | return ret; | 543 | return ret; |
@@ -529,7 +546,10 @@ static int mxser_change_speed(struct mxser_port *info, | |||
529 | return ret; | 546 | return ret; |
530 | 547 | ||
531 | if (mxser_set_baud_method[info->tty->index] == 0) { | 548 | if (mxser_set_baud_method[info->tty->index] == 0) { |
532 | 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); | ||
533 | mxser_set_baud(info, baud); | 553 | mxser_set_baud(info, baud); |
534 | } | 554 | } |
535 | 555 | ||
@@ -612,8 +632,8 @@ static int mxser_change_speed(struct mxser_port *info, | |||
612 | outb(info->IER, info->ioaddr + | 632 | outb(info->IER, info->ioaddr + |
613 | UART_IER); | 633 | UART_IER); |
614 | } | 634 | } |
615 | set_bit(MXSER_EVENT_TXLOW, &info->event); | 635 | tty_wakeup(info->tty); |
616 | schedule_work(&info->tqueue); } | 636 | } |
617 | } else { | 637 | } else { |
618 | if (!(status & UART_MSR_CTS)) { | 638 | if (!(status & UART_MSR_CTS)) { |
619 | info->tty->hw_stopped = 1; | 639 | info->tty->hw_stopped = 1; |
@@ -668,7 +688,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
668 | } | 688 | } |
669 | } | 689 | } |
670 | if (info->board->chip_flag) { | 690 | if (info->board->chip_flag) { |
671 | spin_lock_irqsave(&info->slock, flags); | ||
672 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); | 691 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); |
673 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); | 692 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); |
674 | if (I_IXON(info->tty)) { | 693 | if (I_IXON(info->tty)) { |
@@ -681,7 +700,6 @@ static int mxser_change_speed(struct mxser_port *info, | |||
681 | } else { | 700 | } else { |
682 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | 701 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); |
683 | } | 702 | } |
684 | spin_unlock_irqrestore(&info->slock, flags); | ||
685 | } | 703 | } |
686 | 704 | ||
687 | 705 | ||
@@ -708,7 +726,6 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) | |||
708 | if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { | 726 | if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { |
709 | if (status & UART_MSR_DCD) | 727 | if (status & UART_MSR_DCD) |
710 | wake_up_interruptible(&port->open_wait); | 728 | wake_up_interruptible(&port->open_wait); |
711 | schedule_work(&port->tqueue); | ||
712 | } | 729 | } |
713 | 730 | ||
714 | if (port->flags & ASYNC_CTS_FLOW) { | 731 | if (port->flags & ASYNC_CTS_FLOW) { |
@@ -724,8 +741,7 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) | |||
724 | outb(port->IER, port->ioaddr + | 741 | outb(port->IER, port->ioaddr + |
725 | UART_IER); | 742 | UART_IER); |
726 | } | 743 | } |
727 | set_bit(MXSER_EVENT_TXLOW, &port->event); | 744 | tty_wakeup(port->tty); |
728 | schedule_work(&port->tqueue); | ||
729 | } | 745 | } |
730 | } else { | 746 | } else { |
731 | if (!(status & UART_MSR_CTS)) { | 747 | if (!(status & UART_MSR_CTS)) { |
@@ -836,10 +852,10 @@ static int mxser_startup(struct mxser_port *info) | |||
836 | /* | 852 | /* |
837 | * and set the speed of the serial port | 853 | * and set the speed of the serial port |
838 | */ | 854 | */ |
839 | spin_unlock_irqrestore(&info->slock, flags); | ||
840 | mxser_change_speed(info, NULL); | 855 | mxser_change_speed(info, NULL); |
841 | |||
842 | info->flags |= ASYNC_INITIALIZED; | 856 | info->flags |= ASYNC_INITIALIZED; |
857 | spin_unlock_irqrestore(&info->slock, flags); | ||
858 | |||
843 | return 0; | 859 | return 0; |
844 | } | 860 | } |
845 | 861 | ||
@@ -909,11 +925,9 @@ static void mxser_shutdown(struct mxser_port *info) | |||
909 | static int mxser_open(struct tty_struct *tty, struct file *filp) | 925 | static int mxser_open(struct tty_struct *tty, struct file *filp) |
910 | { | 926 | { |
911 | struct mxser_port *info; | 927 | struct mxser_port *info; |
928 | unsigned long flags; | ||
912 | int retval, line; | 929 | int retval, line; |
913 | 930 | ||
914 | /* initialize driver_data in case something fails */ | ||
915 | tty->driver_data = NULL; | ||
916 | |||
917 | line = tty->index; | 931 | line = tty->index; |
918 | if (line == MXSER_PORTS) | 932 | if (line == MXSER_PORTS) |
919 | return 0; | 933 | return 0; |
@@ -928,7 +942,9 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) | |||
928 | /* | 942 | /* |
929 | * Start up serial port | 943 | * Start up serial port |
930 | */ | 944 | */ |
945 | spin_lock_irqsave(&info->slock, flags); | ||
931 | info->count++; | 946 | info->count++; |
947 | spin_unlock_irqrestore(&info->slock, flags); | ||
932 | retval = mxser_startup(info); | 948 | retval = mxser_startup(info); |
933 | if (retval) | 949 | if (retval) |
934 | return retval; | 950 | return retval; |
@@ -937,17 +953,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) | |||
937 | if (retval) | 953 | if (retval) |
938 | return retval; | 954 | return retval; |
939 | 955 | ||
940 | if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { | ||
941 | if (tty->driver->subtype == SERIAL_TYPE_NORMAL) | ||
942 | *tty->termios = info->normal_termios; | ||
943 | else | ||
944 | *tty->termios = info->callout_termios; | ||
945 | mxser_change_speed(info, NULL); | ||
946 | } | ||
947 | |||
948 | info->session = process_session(current); | ||
949 | info->pgrp = process_group(current); | ||
950 | |||
951 | /* unmark here for very high baud rate (ex. 921600 bps) used */ | 956 | /* unmark here for very high baud rate (ex. 921600 bps) used */ |
952 | tty->low_latency = 1; | 957 | tty->low_latency = 1; |
953 | return 0; | 958 | return 0; |
@@ -1054,8 +1059,6 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) | |||
1054 | } | 1059 | } |
1055 | 1060 | ||
1056 | info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); | 1061 | info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); |
1057 | wake_up_interruptible(&info->close_wait); | ||
1058 | |||
1059 | } | 1062 | } |
1060 | 1063 | ||
1061 | static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) | 1064 | static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) |
@@ -1222,6 +1225,7 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1222 | struct serial_struct __user *new_info) | 1225 | struct serial_struct __user *new_info) |
1223 | { | 1226 | { |
1224 | struct serial_struct new_serial; | 1227 | struct serial_struct new_serial; |
1228 | unsigned long sl_flags; | ||
1225 | unsigned int flags; | 1229 | unsigned int flags; |
1226 | int retval = 0; | 1230 | int retval = 0; |
1227 | 1231 | ||
@@ -1264,8 +1268,11 @@ static int mxser_set_serial_info(struct mxser_port *info, | |||
1264 | process_txrx_fifo(info); | 1268 | process_txrx_fifo(info); |
1265 | 1269 | ||
1266 | if (info->flags & ASYNC_INITIALIZED) { | 1270 | if (info->flags & ASYNC_INITIALIZED) { |
1267 | if (flags != (info->flags & ASYNC_SPD_MASK)) | 1271 | if (flags != (info->flags & ASYNC_SPD_MASK)) { |
1272 | spin_lock_irqsave(&info->slock, sl_flags); | ||
1268 | mxser_change_speed(info, NULL); | 1273 | mxser_change_speed(info, NULL); |
1274 | spin_unlock_irqrestore(&info->slock, sl_flags); | ||
1275 | } | ||
1269 | } else | 1276 | } else |
1270 | retval = mxser_startup(info); | 1277 | retval = mxser_startup(info); |
1271 | 1278 | ||
@@ -1373,11 +1380,10 @@ static int mxser_tiocmset(struct tty_struct *tty, struct file *file, | |||
1373 | return 0; | 1380 | return 0; |
1374 | } | 1381 | } |
1375 | 1382 | ||
1376 | static int mxser_program_mode(int port) | 1383 | static int __init mxser_program_mode(int port) |
1377 | { | 1384 | { |
1378 | int id, i, j, n; | 1385 | int id, i, j, n; |
1379 | 1386 | ||
1380 | spin_lock(&gm_lock); | ||
1381 | outb(0, port); | 1387 | outb(0, port); |
1382 | outb(0, port); | 1388 | outb(0, port); |
1383 | outb(0, port); | 1389 | outb(0, port); |
@@ -1385,7 +1391,6 @@ static int mxser_program_mode(int port) | |||
1385 | (void)inb(port); | 1391 | (void)inb(port); |
1386 | outb(0, port); | 1392 | outb(0, port); |
1387 | (void)inb(port); | 1393 | (void)inb(port); |
1388 | spin_unlock(&gm_lock); | ||
1389 | 1394 | ||
1390 | id = inb(port + 1) & 0x1F; | 1395 | id = inb(port + 1) & 0x1F; |
1391 | if ((id != C168_ASIC_ID) && | 1396 | if ((id != C168_ASIC_ID) && |
@@ -1410,7 +1415,7 @@ static int mxser_program_mode(int port) | |||
1410 | return id; | 1415 | return id; |
1411 | } | 1416 | } |
1412 | 1417 | ||
1413 | static void mxser_normal_mode(int port) | 1418 | static void __init mxser_normal_mode(int port) |
1414 | { | 1419 | { |
1415 | int i, n; | 1420 | int i, n; |
1416 | 1421 | ||
@@ -1443,7 +1448,7 @@ static void mxser_normal_mode(int port) | |||
1443 | #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ | 1448 | #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ |
1444 | #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ | 1449 | #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ |
1445 | #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ | 1450 | #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ |
1446 | static int mxser_read_register(int port, unsigned short *regs) | 1451 | static int __init mxser_read_register(int port, unsigned short *regs) |
1447 | { | 1452 | { |
1448 | int i, k, value, id; | 1453 | int i, k, value, id; |
1449 | unsigned int j; | 1454 | unsigned int j; |
@@ -1644,6 +1649,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1644 | struct serial_icounter_struct __user *p_cuser; | 1649 | struct serial_icounter_struct __user *p_cuser; |
1645 | unsigned long templ; | 1650 | unsigned long templ; |
1646 | unsigned long flags; | 1651 | unsigned long flags; |
1652 | unsigned int i; | ||
1647 | void __user *argp = (void __user *)arg; | 1653 | void __user *argp = (void __user *)arg; |
1648 | int retval; | 1654 | int retval; |
1649 | 1655 | ||
@@ -1682,6 +1688,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1682 | return 0; | 1688 | return 0; |
1683 | } | 1689 | } |
1684 | 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, NULL); | ||
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 | |||
1685 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && | 1721 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && |
1686 | test_bit(TTY_IO_ERROR, &tty->flags)) | 1722 | test_bit(TTY_IO_ERROR, &tty->flags)) |
1687 | return -EIO; | 1723 | return -EIO; |
@@ -1799,7 +1835,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1799 | long baud; | 1835 | long baud; |
1800 | if (get_user(baud, (long __user *)argp)) | 1836 | if (get_user(baud, (long __user *)argp)) |
1801 | return -EFAULT; | 1837 | return -EFAULT; |
1838 | spin_lock_irqsave(&info->slock, flags); | ||
1802 | mxser_set_baud(info, baud); | 1839 | mxser_set_baud(info, baud); |
1840 | spin_unlock_irqrestore(&info->slock, flags); | ||
1803 | return 0; | 1841 | return 0; |
1804 | } | 1842 | } |
1805 | case MOXA_ASPP_GETBAUD: | 1843 | case MOXA_ASPP_GETBAUD: |
@@ -1976,7 +2014,9 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi | |||
1976 | if ((tty->termios->c_cflag != old_termios->c_cflag) || | 2014 | if ((tty->termios->c_cflag != old_termios->c_cflag) || |
1977 | (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))) { |
1978 | 2016 | ||
2017 | spin_lock_irqsave(&info->slock, flags); | ||
1979 | mxser_change_speed(info, old_termios); | 2018 | mxser_change_speed(info, old_termios); |
2019 | spin_unlock_irqrestore(&info->slock, flags); | ||
1980 | 2020 | ||
1981 | if ((old_termios->c_cflag & CRTSCTS) && | 2021 | if ((old_termios->c_cflag & CRTSCTS) && |
1982 | !(tty->termios->c_cflag & CRTSCTS)) { | 2022 | !(tty->termios->c_cflag & CRTSCTS)) { |
@@ -2066,7 +2106,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) | |||
2066 | /* | 2106 | /* |
2067 | * This routine is called by tty_hangup() when a hangup is signaled. | 2107 | * This routine is called by tty_hangup() when a hangup is signaled. |
2068 | */ | 2108 | */ |
2069 | void mxser_hangup(struct tty_struct *tty) | 2109 | static void mxser_hangup(struct tty_struct *tty) |
2070 | { | 2110 | { |
2071 | struct mxser_port *info = tty->driver_data; | 2111 | struct mxser_port *info = tty->driver_data; |
2072 | 2112 | ||
@@ -2105,9 +2145,6 @@ static void mxser_receive_chars(struct mxser_port *port, int *status) | |||
2105 | int cnt = 0; | 2145 | int cnt = 0; |
2106 | int recv_room; | 2146 | int recv_room; |
2107 | int max = 256; | 2147 | int max = 256; |
2108 | unsigned long flags; | ||
2109 | |||
2110 | spin_lock_irqsave(&port->slock, flags); | ||
2111 | 2148 | ||
2112 | recv_room = tty->receive_room; | 2149 | recv_room = tty->receive_room; |
2113 | if ((recv_room == 0) && (!port->ldisc_stop_rx)) | 2150 | if ((recv_room == 0) && (!port->ldisc_stop_rx)) |
@@ -2169,7 +2206,8 @@ intr_old: | |||
2169 | } else if (*status & UART_LSR_OE) { | 2206 | } else if (*status & UART_LSR_OE) { |
2170 | flag = TTY_OVERRUN; | 2207 | flag = TTY_OVERRUN; |
2171 | port->icount.overrun++; | 2208 | port->icount.overrun++; |
2172 | } | 2209 | } else |
2210 | flag = TTY_BREAK; | ||
2173 | } | 2211 | } |
2174 | tty_insert_flip_char(tty, ch, flag); | 2212 | tty_insert_flip_char(tty, ch, flag); |
2175 | cnt++; | 2213 | cnt++; |
@@ -2191,7 +2229,6 @@ end_intr: | |||
2191 | mxvar_log.rxcnt[port->tty->index] += cnt; | 2229 | mxvar_log.rxcnt[port->tty->index] += cnt; |
2192 | port->mon_data.rxcnt += cnt; | 2230 | port->mon_data.rxcnt += cnt; |
2193 | port->mon_data.up_rxcnt += cnt; | 2231 | port->mon_data.up_rxcnt += cnt; |
2194 | spin_unlock_irqrestore(&port->slock, flags); | ||
2195 | 2232 | ||
2196 | tty_flip_buffer_push(tty); | 2233 | tty_flip_buffer_push(tty); |
2197 | } | 2234 | } |
@@ -2199,9 +2236,6 @@ end_intr: | |||
2199 | static void mxser_transmit_chars(struct mxser_port *port) | 2236 | static void mxser_transmit_chars(struct mxser_port *port) |
2200 | { | 2237 | { |
2201 | int count, cnt; | 2238 | int count, cnt; |
2202 | unsigned long flags; | ||
2203 | |||
2204 | spin_lock_irqsave(&port->slock, flags); | ||
2205 | 2239 | ||
2206 | if (port->x_char) { | 2240 | if (port->x_char) { |
2207 | outb(port->x_char, port->ioaddr + UART_TX); | 2241 | outb(port->x_char, port->ioaddr + UART_TX); |
@@ -2210,11 +2244,11 @@ static void mxser_transmit_chars(struct mxser_port *port) | |||
2210 | port->mon_data.txcnt++; | 2244 | port->mon_data.txcnt++; |
2211 | port->mon_data.up_txcnt++; | 2245 | port->mon_data.up_txcnt++; |
2212 | port->icount.tx++; | 2246 | port->icount.tx++; |
2213 | goto unlock; | 2247 | return; |
2214 | } | 2248 | } |
2215 | 2249 | ||
2216 | if (port->xmit_buf == 0) | 2250 | if (port->xmit_buf == 0) |
2217 | goto unlock; | 2251 | return; |
2218 | 2252 | ||
2219 | if ((port->xmit_cnt <= 0) || port->tty->stopped || | 2253 | if ((port->xmit_cnt <= 0) || port->tty->stopped || |
2220 | (port->tty->hw_stopped && | 2254 | (port->tty->hw_stopped && |
@@ -2222,7 +2256,7 @@ static void mxser_transmit_chars(struct mxser_port *port) | |||
2222 | (!port->board->chip_flag))) { | 2256 | (!port->board->chip_flag))) { |
2223 | port->IER &= ~UART_IER_THRI; | 2257 | port->IER &= ~UART_IER_THRI; |
2224 | outb(port->IER, port->ioaddr + UART_IER); | 2258 | outb(port->IER, port->ioaddr + UART_IER); |
2225 | goto unlock; | 2259 | return; |
2226 | } | 2260 | } |
2227 | 2261 | ||
2228 | cnt = port->xmit_cnt; | 2262 | cnt = port->xmit_cnt; |
@@ -2240,16 +2274,13 @@ static void mxser_transmit_chars(struct mxser_port *port) | |||
2240 | port->mon_data.up_txcnt += (cnt - port->xmit_cnt); | 2274 | port->mon_data.up_txcnt += (cnt - port->xmit_cnt); |
2241 | port->icount.tx += (cnt - port->xmit_cnt); | 2275 | port->icount.tx += (cnt - port->xmit_cnt); |
2242 | 2276 | ||
2243 | if (port->xmit_cnt < WAKEUP_CHARS) { | 2277 | if (port->xmit_cnt < WAKEUP_CHARS) |
2244 | set_bit(MXSER_EVENT_TXLOW, &port->event); | 2278 | tty_wakeup(port->tty); |
2245 | schedule_work(&port->tqueue); | 2279 | |
2246 | } | ||
2247 | if (port->xmit_cnt <= 0) { | 2280 | if (port->xmit_cnt <= 0) { |
2248 | port->IER &= ~UART_IER_THRI; | 2281 | port->IER &= ~UART_IER_THRI; |
2249 | outb(port->IER, port->ioaddr + UART_IER); | 2282 | outb(port->IER, port->ioaddr + UART_IER); |
2250 | } | 2283 | } |
2251 | unlock: | ||
2252 | spin_unlock_irqrestore(&port->slock, flags); | ||
2253 | } | 2284 | } |
2254 | 2285 | ||
2255 | /* | 2286 | /* |
@@ -2261,8 +2292,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2261 | struct mxser_board *brd = NULL; | 2292 | struct mxser_board *brd = NULL; |
2262 | struct mxser_port *port; | 2293 | struct mxser_port *port; |
2263 | int max, irqbits, bits, msr; | 2294 | int max, irqbits, bits, msr; |
2264 | int pass_counter = 0; | 2295 | unsigned int int_cnt, pass_counter = 0; |
2265 | unsigned int int_cnt; | ||
2266 | int handled = IRQ_NONE; | 2296 | int handled = IRQ_NONE; |
2267 | 2297 | ||
2268 | for (i = 0; i < MXSER_BOARDS; i++) | 2298 | for (i = 0; i < MXSER_BOARDS; i++) |
@@ -2276,7 +2306,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2276 | if (brd == NULL) | 2306 | if (brd == NULL) |
2277 | goto irq_stop; | 2307 | goto irq_stop; |
2278 | max = brd->info->nports; | 2308 | max = brd->info->nports; |
2279 | while (1) { | 2309 | while (pass_counter++ < MXSER_ISR_PASS_LIMIT) { |
2280 | irqbits = inb(brd->vector) & brd->vector_mask; | 2310 | irqbits = inb(brd->vector) & brd->vector_mask; |
2281 | if (irqbits == brd->vector_mask) | 2311 | if (irqbits == brd->vector_mask) |
2282 | break; | 2312 | break; |
@@ -2290,12 +2320,16 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2290 | port = &brd->ports[i]; | 2320 | port = &brd->ports[i]; |
2291 | 2321 | ||
2292 | int_cnt = 0; | 2322 | int_cnt = 0; |
2323 | spin_lock(&port->slock); | ||
2293 | do { | 2324 | do { |
2294 | iir = inb(port->ioaddr + UART_IIR); | 2325 | iir = inb(port->ioaddr + UART_IIR); |
2295 | if (iir & UART_IIR_NO_INT) | 2326 | if (iir & UART_IIR_NO_INT) |
2296 | break; | 2327 | break; |
2297 | iir &= MOXA_MUST_IIR_MASK; | 2328 | iir &= MOXA_MUST_IIR_MASK; |
2298 | if (!port->tty) { | 2329 | if (!port->tty || |
2330 | (port->flags & ASYNC_CLOSING) || | ||
2331 | !(port->flags & | ||
2332 | ASYNC_INITIALIZED)) { | ||
2299 | status = inb(port->ioaddr + UART_LSR); | 2333 | status = inb(port->ioaddr + UART_LSR); |
2300 | outb(0x27, port->ioaddr + UART_FCR); | 2334 | outb(0x27, port->ioaddr + UART_FCR); |
2301 | inb(port->ioaddr + UART_MSR); | 2335 | inb(port->ioaddr + UART_MSR); |
@@ -2341,9 +2375,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) | |||
2341 | mxser_transmit_chars(port); | 2375 | mxser_transmit_chars(port); |
2342 | } | 2376 | } |
2343 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); | 2377 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); |
2378 | spin_unlock(&port->slock); | ||
2344 | } | 2379 | } |
2345 | if (pass_counter++ > MXSER_ISR_PASS_LIMIT) | ||
2346 | break; /* Prevent infinite loops */ | ||
2347 | } | 2380 | } |
2348 | 2381 | ||
2349 | irq_stop: | 2382 | irq_stop: |
@@ -2385,7 +2418,6 @@ static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev, | |||
2385 | #ifdef CONFIG_PCI | 2418 | #ifdef CONFIG_PCI |
2386 | pci_release_region(pdev, 2); | 2419 | pci_release_region(pdev, 2); |
2387 | pci_release_region(pdev, 3); | 2420 | pci_release_region(pdev, 3); |
2388 | pci_dev_put(pdev); | ||
2389 | #endif | 2421 | #endif |
2390 | } else { | 2422 | } else { |
2391 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); | 2423 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); |
@@ -2420,11 +2452,10 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, | |||
2420 | info->custom_divisor = info->baud_base * 16; | 2452 | info->custom_divisor = info->baud_base * 16; |
2421 | info->close_delay = 5 * HZ / 10; | 2453 | info->close_delay = 5 * HZ / 10; |
2422 | info->closing_wait = 30 * HZ; | 2454 | info->closing_wait = 30 * HZ; |
2423 | INIT_WORK(&info->tqueue, mxser_do_softint); | ||
2424 | info->normal_termios = mxvar_sdriver->init_termios; | 2455 | info->normal_termios = mxvar_sdriver->init_termios; |
2425 | init_waitqueue_head(&info->open_wait); | 2456 | init_waitqueue_head(&info->open_wait); |
2426 | init_waitqueue_head(&info->close_wait); | ||
2427 | init_waitqueue_head(&info->delta_msr_wait); | 2457 | init_waitqueue_head(&info->delta_msr_wait); |
2458 | info->speed = 9600; | ||
2428 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); | 2459 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); |
2429 | info->err_shadow = 0; | 2460 | info->err_shadow = 0; |
2430 | spin_lock_init(&info->slock); | 2461 | spin_lock_init(&info->slock); |
@@ -2433,22 +2464,17 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, | |||
2433 | outb(inb(info->ioaddr + UART_IER) & 0xf0, | 2464 | outb(inb(info->ioaddr + UART_IER) & 0xf0, |
2434 | info->ioaddr + UART_IER); | 2465 | info->ioaddr + UART_IER); |
2435 | } | 2466 | } |
2436 | /* | ||
2437 | * Allocate the IRQ if necessary | ||
2438 | */ | ||
2439 | 2467 | ||
2440 | retval = request_irq(brd->irq, mxser_interrupt, | 2468 | retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", |
2441 | (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : | 2469 | brd); |
2442 | IRQF_DISABLED, "mxser", brd); | ||
2443 | if (retval) { | 2470 | if (retval) { |
2444 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " | 2471 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " |
2445 | "conflict with another device.\n", | 2472 | "conflict with another device.\n", |
2446 | brd->info->name, brd->irq); | 2473 | brd->info->name, brd->irq); |
2447 | /* We hold resources, we need to release them. */ | 2474 | /* We hold resources, we need to release them. */ |
2448 | mxser_release_res(brd, pdev, 0); | 2475 | mxser_release_res(brd, pdev, 0); |
2449 | return retval; | ||
2450 | } | 2476 | } |
2451 | return 0; | 2477 | return retval; |
2452 | } | 2478 | } |
2453 | 2479 | ||
2454 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | 2480 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) |
@@ -2633,8 +2659,9 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2633 | } | 2659 | } |
2634 | 2660 | ||
2635 | /* mxser_initbrd will hook ISR. */ | 2661 | /* mxser_initbrd will hook ISR. */ |
2636 | if (mxser_initbrd(brd, pdev) < 0) | 2662 | retval = mxser_initbrd(brd, pdev); |
2637 | goto err_relvec; | 2663 | if (retval) |
2664 | goto err_null; | ||
2638 | 2665 | ||
2639 | for (i = 0; i < brd->info->nports; i++) | 2666 | for (i = 0; i < brd->info->nports; i++) |
2640 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); | 2667 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); |
@@ -2642,10 +2669,9 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2642 | pci_set_drvdata(pdev, brd); | 2669 | pci_set_drvdata(pdev, brd); |
2643 | 2670 | ||
2644 | return 0; | 2671 | return 0; |
2645 | err_relvec: | ||
2646 | pci_release_region(pdev, 3); | ||
2647 | err_relio: | 2672 | err_relio: |
2648 | pci_release_region(pdev, 2); | 2673 | pci_release_region(pdev, 2); |
2674 | err_null: | ||
2649 | brd->info = NULL; | 2675 | brd->info = NULL; |
2650 | err: | 2676 | err: |
2651 | return retval; | 2677 | return retval; |
@@ -2663,6 +2689,7 @@ static void __devexit mxser_remove(struct pci_dev *pdev) | |||
2663 | tty_unregister_device(mxvar_sdriver, brd->idx + i); | 2689 | tty_unregister_device(mxvar_sdriver, brd->idx + i); |
2664 | 2690 | ||
2665 | mxser_release_res(brd, pdev, 1); | 2691 | mxser_release_res(brd, pdev, 1); |
2692 | brd->info = NULL; | ||
2666 | } | 2693 | } |
2667 | 2694 | ||
2668 | static struct pci_driver mxser_driver = { | 2695 | static struct pci_driver mxser_driver = { |
@@ -2684,7 +2711,6 @@ static int __init mxser_module_init(void) | |||
2684 | mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); | 2711 | mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); |
2685 | if (!mxvar_sdriver) | 2712 | if (!mxvar_sdriver) |
2686 | return -ENOMEM; | 2713 | return -ENOMEM; |
2687 | spin_lock_init(&gm_lock); | ||
2688 | 2714 | ||
2689 | printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", | 2715 | printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", |
2690 | MXSER_VERSION); | 2716 | MXSER_VERSION); |