diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2006-12-08 05:38:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:28:54 -0500 |
commit | a8dea4ec8012b5f55f8a68819a1809fe70635e29 (patch) | |
tree | b5d711cb5cf7d01f5ed007d1f17fb3dc69e29088 /drivers/char/mxser_new.c | |
parent | c88cb8f952e28d11af6b168eca28c08560009cca (diff) |
[PATCH] Char: mxser_new, code upside down
Reorder functions upside down not to have too many prototypes of each function
and have some order (similar to other drivers).
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/mxser_new.c')
-rw-r--r-- | drivers/char/mxser_new.c | 3045 |
1 files changed, 1488 insertions, 1557 deletions
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 0e22f8010446..92ca016d2e3e 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c | |||
@@ -191,7 +191,6 @@ static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = { | |||
191 | {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} | 191 | {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} |
192 | }; | 192 | }; |
193 | 193 | ||
194 | |||
195 | static struct pci_device_id mxser_pcibrds[] = { | 194 | static struct pci_device_id mxser_pcibrds[] = { |
196 | { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168), | 195 | { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168), |
197 | .driver_data = MXSER_BOARD_C168_PCI }, | 196 | .driver_data = MXSER_BOARD_C168_PCI }, |
@@ -377,57 +376,6 @@ static struct mxser_mon_ext mon_data_ext; | |||
377 | static int mxser_set_baud_method[MXSER_PORTS + 1]; | 376 | static int mxser_set_baud_method[MXSER_PORTS + 1]; |
378 | static spinlock_t gm_lock; | 377 | static spinlock_t gm_lock; |
379 | 378 | ||
380 | /* | ||
381 | * static functions: | ||
382 | */ | ||
383 | |||
384 | static int mxser_init(void); | ||
385 | |||
386 | /* static void mxser_poll(unsigned long); */ | ||
387 | static int mxser_get_ISA_conf(int, struct mxser_board *); | ||
388 | static void mxser_do_softint(void *); | ||
389 | static int mxser_open(struct tty_struct *, struct file *); | ||
390 | static void mxser_close(struct tty_struct *, struct file *); | ||
391 | static int mxser_write(struct tty_struct *, const unsigned char *, int); | ||
392 | static int mxser_write_room(struct tty_struct *); | ||
393 | static void mxser_flush_buffer(struct tty_struct *); | ||
394 | static int mxser_chars_in_buffer(struct tty_struct *); | ||
395 | static void mxser_flush_chars(struct tty_struct *); | ||
396 | static void mxser_put_char(struct tty_struct *, unsigned char); | ||
397 | static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong); | ||
398 | static int mxser_ioctl_special(unsigned int, void __user *); | ||
399 | static void mxser_throttle(struct tty_struct *); | ||
400 | static void mxser_unthrottle(struct tty_struct *); | ||
401 | static void mxser_set_termios(struct tty_struct *, struct termios *); | ||
402 | static void mxser_stop(struct tty_struct *); | ||
403 | static void mxser_start(struct tty_struct *); | ||
404 | static void mxser_hangup(struct tty_struct *); | ||
405 | static void mxser_rs_break(struct tty_struct *, int); | ||
406 | static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *); | ||
407 | static void mxser_receive_chars(struct mxser_port *, int *); | ||
408 | static void mxser_transmit_chars(struct mxser_port *); | ||
409 | static void mxser_check_modem_status(struct mxser_port *, int); | ||
410 | static int mxser_block_til_ready(struct tty_struct *, struct file *, | ||
411 | struct mxser_port *); | ||
412 | static int mxser_startup(struct mxser_port *); | ||
413 | static void mxser_shutdown(struct mxser_port *); | ||
414 | static int mxser_change_speed(struct mxser_port *, struct termios *); | ||
415 | static int mxser_get_serial_info(struct mxser_port *, | ||
416 | struct serial_struct __user *); | ||
417 | static int mxser_set_serial_info(struct mxser_port *, | ||
418 | struct serial_struct __user *); | ||
419 | static int mxser_get_lsr_info(struct mxser_port *, unsigned int __user *); | ||
420 | static void mxser_send_break(struct mxser_port *, int); | ||
421 | static int mxser_tiocmget(struct tty_struct *, struct file *); | ||
422 | static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, | ||
423 | unsigned int); | ||
424 | static int mxser_set_baud(struct mxser_port *, long); | ||
425 | static void mxser_wait_until_sent(struct tty_struct *, int); | ||
426 | |||
427 | static void mxser_startrx(struct tty_struct *); | ||
428 | static void mxser_stoprx(struct tty_struct *); | ||
429 | |||
430 | |||
431 | static int CheckIsMoxaMust(int io) | 379 | static int CheckIsMoxaMust(int io) |
432 | { | 380 | { |
433 | u8 oldmcr, hwid; | 381 | u8 oldmcr, hwid; |
@@ -453,75 +401,6 @@ static int CheckIsMoxaMust(int io) | |||
453 | 401 | ||
454 | /* above is modified by Victor Yu. 08-15-2002 */ | 402 | /* above is modified by Victor Yu. 08-15-2002 */ |
455 | 403 | ||
456 | static const struct tty_operations mxser_ops = { | ||
457 | .open = mxser_open, | ||
458 | .close = mxser_close, | ||
459 | .write = mxser_write, | ||
460 | .put_char = mxser_put_char, | ||
461 | .flush_chars = mxser_flush_chars, | ||
462 | .write_room = mxser_write_room, | ||
463 | .chars_in_buffer = mxser_chars_in_buffer, | ||
464 | .flush_buffer = mxser_flush_buffer, | ||
465 | .ioctl = mxser_ioctl, | ||
466 | .throttle = mxser_throttle, | ||
467 | .unthrottle = mxser_unthrottle, | ||
468 | .set_termios = mxser_set_termios, | ||
469 | .stop = mxser_stop, | ||
470 | .start = mxser_start, | ||
471 | .hangup = mxser_hangup, | ||
472 | .break_ctl = mxser_rs_break, | ||
473 | .wait_until_sent = mxser_wait_until_sent, | ||
474 | .tiocmget = mxser_tiocmget, | ||
475 | .tiocmset = mxser_tiocmset, | ||
476 | }; | ||
477 | |||
478 | /* | ||
479 | * The MOXA Smartio/Industio serial driver boot-time initialization code! | ||
480 | */ | ||
481 | |||
482 | static int __init mxser_module_init(void) | ||
483 | { | ||
484 | int ret; | ||
485 | |||
486 | pr_debug("Loading module mxser ...\n"); | ||
487 | ret = mxser_init(); | ||
488 | pr_debug("Done.\n"); | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | static void __exit mxser_module_exit(void) | ||
493 | { | ||
494 | int i, err; | ||
495 | |||
496 | pr_debug("Unloading module mxser ...\n"); | ||
497 | |||
498 | err = tty_unregister_driver(mxvar_sdriver); | ||
499 | if (!err) | ||
500 | put_tty_driver(mxvar_sdriver); | ||
501 | else | ||
502 | printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n"); | ||
503 | |||
504 | for (i = 0; i < MXSER_BOARDS; i++) { | ||
505 | struct pci_dev *pdev; | ||
506 | |||
507 | if (mxser_boards[i].board_type == -1) | ||
508 | continue; | ||
509 | else { | ||
510 | pdev = mxser_boards[i].pdev; | ||
511 | free_irq(mxser_boards[i].irq, &mxser_boards[i]); | ||
512 | if (pdev != NULL) { /* PCI */ | ||
513 | pci_release_region(pdev, 2); | ||
514 | pci_release_region(pdev, 3); | ||
515 | pci_dev_put(pdev); | ||
516 | } else { | ||
517 | release_region(mxser_boards[i].ports[0].ioaddr, 8 * mxser_boards[i].nports); | ||
518 | release_region(mxser_boards[i].vector, 1); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | pr_debug("Done.\n"); | ||
523 | } | ||
524 | |||
525 | static void process_txrx_fifo(struct mxser_port *info) | 404 | static void process_txrx_fifo(struct mxser_port *info) |
526 | { | 405 | { |
527 | int i; | 406 | int i; |
@@ -542,349 +421,581 @@ static void process_txrx_fifo(struct mxser_port *info) | |||
542 | } | 421 | } |
543 | } | 422 | } |
544 | 423 | ||
545 | static int __devinit mxser_initbrd(struct mxser_board *brd) | 424 | static void mxser_do_softint(void *private_) |
546 | { | 425 | { |
547 | struct mxser_port *info; | 426 | struct mxser_port *info = private_; |
548 | unsigned int i; | 427 | struct tty_struct *tty; |
549 | int retval; | ||
550 | 428 | ||
551 | printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud); | 429 | tty = info->tty; |
552 | 430 | ||
553 | for (i = 0; i < brd->nports; i++) { | 431 | if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) |
554 | info = &brd->ports[i]; | 432 | tty_wakeup(tty); |
555 | info->board = brd; | 433 | if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) |
556 | info->stop_rx = 0; | 434 | tty_hangup(tty); |
557 | info->ldisc_stop_rx = 0; | 435 | } |
558 | 436 | ||
559 | /* Enhance mode enabled here */ | 437 | static unsigned char mxser_get_msr(int baseaddr, int mode, int port) |
560 | if (brd->chip_flag != MOXA_OTHER_UART) | 438 | { |
561 | ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr); | 439 | unsigned char status = 0; |
562 | 440 | ||
563 | info->flags = ASYNC_SHARE_IRQ; | 441 | status = inb(baseaddr + UART_MSR); |
564 | info->type = brd->uart_type; | ||
565 | 442 | ||
566 | process_txrx_fifo(info); | 443 | mxser_msr[port] &= 0x0F; |
444 | mxser_msr[port] |= status; | ||
445 | status = mxser_msr[port]; | ||
446 | if (mode) | ||
447 | mxser_msr[port] = 0; | ||
567 | 448 | ||
568 | info->custom_divisor = info->baud_base * 16; | 449 | return status; |
569 | info->close_delay = 5 * HZ / 10; | 450 | } |
570 | info->closing_wait = 30 * HZ; | ||
571 | INIT_WORK(&info->tqueue, mxser_do_softint, info); | ||
572 | info->normal_termios = mxvar_sdriver->init_termios; | ||
573 | init_waitqueue_head(&info->open_wait); | ||
574 | init_waitqueue_head(&info->close_wait); | ||
575 | init_waitqueue_head(&info->delta_msr_wait); | ||
576 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); | ||
577 | info->err_shadow = 0; | ||
578 | spin_lock_init(&info->slock); | ||
579 | 451 | ||
580 | /* before set INT ISR, disable all int */ | 452 | static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, |
581 | outb(inb(info->ioaddr + UART_IER) & 0xf0, | 453 | struct mxser_port *port) |
582 | info->ioaddr + UART_IER); | 454 | { |
455 | DECLARE_WAITQUEUE(wait, current); | ||
456 | int retval; | ||
457 | int do_clocal = 0; | ||
458 | unsigned long flags; | ||
459 | |||
460 | /* | ||
461 | * If non-blocking mode is set, or the port is not enabled, | ||
462 | * then make the check up front and then exit. | ||
463 | */ | ||
464 | if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { | ||
465 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
466 | return 0; | ||
583 | } | 467 | } |
468 | |||
469 | if (tty->termios->c_cflag & CLOCAL) | ||
470 | do_clocal = 1; | ||
471 | |||
584 | /* | 472 | /* |
585 | * Allocate the IRQ if necessary | 473 | * Block waiting for the carrier detect and the line to become |
474 | * free (i.e., not in use by the callout). While we are in | ||
475 | * this loop, port->count is dropped by one, so that | ||
476 | * mxser_close() knows when to free things. We restore it upon | ||
477 | * exit, either normal or abnormal. | ||
586 | */ | 478 | */ |
479 | retval = 0; | ||
480 | add_wait_queue(&port->open_wait, &wait); | ||
587 | 481 | ||
588 | retval = request_irq(brd->irq, mxser_interrupt, | 482 | spin_lock_irqsave(&port->slock, flags); |
589 | (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : | 483 | if (!tty_hung_up_p(filp)) |
590 | IRQF_DISABLED, "mxser", brd); | 484 | port->count--; |
591 | if (retval) { | 485 | spin_unlock_irqrestore(&port->slock, flags); |
592 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " | 486 | port->blocked_open++; |
593 | "conflict with another device.\n", | 487 | while (1) { |
594 | mxser_brdname[brd->board_type - 1], brd->irq); | 488 | spin_lock_irqsave(&port->slock, flags); |
595 | return retval; | 489 | outb(inb(port->ioaddr + UART_MCR) | |
490 | UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR); | ||
491 | spin_unlock_irqrestore(&port->slock, flags); | ||
492 | set_current_state(TASK_INTERRUPTIBLE); | ||
493 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { | ||
494 | if (port->flags & ASYNC_HUP_NOTIFY) | ||
495 | retval = -EAGAIN; | ||
496 | else | ||
497 | retval = -ERESTARTSYS; | ||
498 | break; | ||
499 | } | ||
500 | if (!(port->flags & ASYNC_CLOSING) && | ||
501 | (do_clocal || | ||
502 | (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD))) | ||
503 | break; | ||
504 | if (signal_pending(current)) { | ||
505 | retval = -ERESTARTSYS; | ||
506 | break; | ||
507 | } | ||
508 | schedule(); | ||
596 | } | 509 | } |
510 | set_current_state(TASK_RUNNING); | ||
511 | remove_wait_queue(&port->open_wait, &wait); | ||
512 | if (!tty_hung_up_p(filp)) | ||
513 | port->count++; | ||
514 | port->blocked_open--; | ||
515 | if (retval) | ||
516 | return retval; | ||
517 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
597 | return 0; | 518 | return 0; |
598 | } | 519 | } |
599 | 520 | ||
600 | static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd, | 521 | static int mxser_set_baud(struct mxser_port *info, long newspd) |
601 | struct pci_dev *pdev) | ||
602 | { | 522 | { |
603 | unsigned int i, j; | 523 | int quot = 0; |
604 | unsigned long ioaddress; | 524 | unsigned char cval; |
605 | int retval; | 525 | int ret = 0; |
526 | unsigned long flags; | ||
606 | 527 | ||
607 | /* io address */ | 528 | if (!info->tty || !info->tty->termios) |
608 | brd->board_type = board_type; | 529 | return ret; |
609 | brd->nports = mxser_numports[board_type - 1]; | ||
610 | ioaddress = pci_resource_start(pdev, 2); | ||
611 | retval = pci_request_region(pdev, 2, "mxser(IO)"); | ||
612 | if (retval) | ||
613 | goto err; | ||
614 | 530 | ||
615 | for (i = 0; i < brd->nports; i++) | 531 | if (!(info->ioaddr)) |
616 | brd->ports[i].ioaddr = ioaddress + 8 * i; | 532 | return ret; |
617 | 533 | ||
618 | /* vector */ | 534 | if (newspd > info->max_baud) |
619 | ioaddress = pci_resource_start(pdev, 3); | 535 | return 0; |
620 | retval = pci_request_region(pdev, 3, "mxser(vector)"); | ||
621 | if (retval) | ||
622 | goto err_relio; | ||
623 | brd->vector = ioaddress; | ||
624 | 536 | ||
625 | /* irq */ | 537 | info->realbaud = newspd; |
626 | brd->irq = pdev->irq; | 538 | if (newspd == 134) { |
539 | quot = (2 * info->baud_base / 269); | ||
540 | } else if (newspd) { | ||
541 | quot = info->baud_base / newspd; | ||
542 | if (quot == 0) | ||
543 | quot = 1; | ||
544 | } else { | ||
545 | quot = 0; | ||
546 | } | ||
627 | 547 | ||
628 | brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr); | 548 | info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); |
629 | brd->uart_type = PORT_16550A; | 549 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ |
630 | brd->vector_mask = 0; | ||
631 | 550 | ||
632 | for (i = 0; i < brd->nports; i++) { | 551 | if (quot) { |
633 | for (j = 0; j < UART_INFO_NUM; j++) { | 552 | spin_lock_irqsave(&info->slock, flags); |
634 | if (Gpci_uart_info[j].type == brd->chip_flag) { | 553 | info->MCR |= UART_MCR_DTR; |
635 | brd->ports[i].max_baud = | 554 | outb(info->MCR, info->ioaddr + UART_MCR); |
636 | Gpci_uart_info[j].max_baud; | 555 | spin_unlock_irqrestore(&info->slock, flags); |
556 | } else { | ||
557 | spin_lock_irqsave(&info->slock, flags); | ||
558 | info->MCR &= ~UART_MCR_DTR; | ||
559 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
560 | spin_unlock_irqrestore(&info->slock, flags); | ||
561 | return ret; | ||
562 | } | ||
637 | 563 | ||
638 | /* exception....CP-102 */ | 564 | cval = inb(info->ioaddr + UART_LCR); |
639 | if (board_type == MXSER_BOARD_CP102) | 565 | |
640 | brd->ports[i].max_baud = 921600; | 566 | outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */ |
567 | |||
568 | outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */ | ||
569 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ | ||
570 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
571 | |||
572 | |||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * This routine is called to set the UART divisor registers to match | ||
578 | * the specified baud rate for a serial port. | ||
579 | */ | ||
580 | static int mxser_change_speed(struct mxser_port *info, | ||
581 | struct termios *old_termios) | ||
582 | { | ||
583 | unsigned cflag, cval, fcr; | ||
584 | int ret = 0; | ||
585 | unsigned char status; | ||
586 | long baud; | ||
587 | unsigned long flags; | ||
588 | |||
589 | if (!info->tty || !info->tty->termios) | ||
590 | return ret; | ||
591 | cflag = info->tty->termios->c_cflag; | ||
592 | if (!(info->ioaddr)) | ||
593 | return ret; | ||
594 | |||
595 | #ifndef B921600 | ||
596 | #define B921600 (B460800 +1) | ||
597 | #endif | ||
598 | if (mxser_set_baud_method[info->tty->index] == 0) { | ||
599 | baud = tty_get_baud_rate(info->tty); | ||
600 | mxser_set_baud(info, baud); | ||
601 | } | ||
602 | |||
603 | /* byte size and parity */ | ||
604 | switch (cflag & CSIZE) { | ||
605 | case CS5: | ||
606 | cval = 0x00; | ||
607 | break; | ||
608 | case CS6: | ||
609 | cval = 0x01; | ||
610 | break; | ||
611 | case CS7: | ||
612 | cval = 0x02; | ||
613 | break; | ||
614 | case CS8: | ||
615 | cval = 0x03; | ||
616 | break; | ||
617 | default: | ||
618 | cval = 0x00; | ||
619 | break; /* too keep GCC shut... */ | ||
620 | } | ||
621 | if (cflag & CSTOPB) | ||
622 | cval |= 0x04; | ||
623 | if (cflag & PARENB) | ||
624 | cval |= UART_LCR_PARITY; | ||
625 | if (!(cflag & PARODD)) | ||
626 | cval |= UART_LCR_EPAR; | ||
627 | if (cflag & CMSPAR) | ||
628 | cval |= UART_LCR_SPAR; | ||
629 | |||
630 | if ((info->type == PORT_8250) || (info->type == PORT_16450)) { | ||
631 | if (info->board->chip_flag) { | ||
632 | fcr = UART_FCR_ENABLE_FIFO; | ||
633 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
634 | SET_MOXA_MUST_FIFO_VALUE(info); | ||
635 | } else | ||
636 | fcr = 0; | ||
637 | } else { | ||
638 | fcr = UART_FCR_ENABLE_FIFO; | ||
639 | /* following add by Victor Yu. 08-30-2002 */ | ||
640 | if (info->board->chip_flag) { | ||
641 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
642 | SET_MOXA_MUST_FIFO_VALUE(info); | ||
643 | } else { | ||
644 | /* above add by Victor Yu. 08-30-2002 */ | ||
645 | switch (info->rx_trigger) { | ||
646 | case 1: | ||
647 | fcr |= UART_FCR_TRIGGER_1; | ||
648 | break; | ||
649 | case 4: | ||
650 | fcr |= UART_FCR_TRIGGER_4; | ||
651 | break; | ||
652 | case 8: | ||
653 | fcr |= UART_FCR_TRIGGER_8; | ||
654 | break; | ||
655 | default: | ||
656 | fcr |= UART_FCR_TRIGGER_14; | ||
641 | break; | 657 | break; |
642 | } | 658 | } |
643 | } | 659 | } |
644 | } | 660 | } |
645 | 661 | ||
646 | if (brd->chip_flag == MOXA_MUST_MU860_HWID) { | 662 | /* CTS flow control flag and modem status interrupts */ |
647 | for (i = 0; i < brd->nports; i++) { | 663 | info->IER &= ~UART_IER_MSI; |
648 | if (i < 4) | 664 | info->MCR &= ~UART_MCR_AFE; |
649 | brd->ports[i].opmode_ioaddr = ioaddress + 4; | 665 | if (cflag & CRTSCTS) { |
650 | else | 666 | info->flags |= ASYNC_CTS_FLOW; |
651 | brd->ports[i].opmode_ioaddr = ioaddress + 0x0c; | 667 | info->IER |= UART_IER_MSI; |
668 | if ((info->type == PORT_16550A) || (info->board->chip_flag)) { | ||
669 | info->MCR |= UART_MCR_AFE; | ||
670 | /* status = mxser_get_msr(info->ioaddr, 0, info->port); */ | ||
671 | /* | ||
672 | save_flags(flags); | ||
673 | cli(); | ||
674 | status = inb(baseaddr + UART_MSR); | ||
675 | restore_flags(flags); | ||
676 | */ | ||
677 | /* mxser_check_modem_status(info, status); */ | ||
678 | } else { | ||
679 | /* status = mxser_get_msr(info->ioaddr, 0, info->port); */ | ||
680 | /* MX_LOCK(&info->slock); */ | ||
681 | status = inb(info->ioaddr + UART_MSR); | ||
682 | /* MX_UNLOCK(&info->slock); */ | ||
683 | if (info->tty->hw_stopped) { | ||
684 | if (status & UART_MSR_CTS) { | ||
685 | info->tty->hw_stopped = 0; | ||
686 | if (info->type != PORT_16550A && | ||
687 | !info->board->chip_flag) { | ||
688 | outb(info->IER & ~UART_IER_THRI, | ||
689 | info->ioaddr + | ||
690 | UART_IER); | ||
691 | info->IER |= UART_IER_THRI; | ||
692 | outb(info->IER, info->ioaddr + | ||
693 | UART_IER); | ||
694 | } | ||
695 | set_bit(MXSER_EVENT_TXLOW, &info->event); | ||
696 | schedule_work(&info->tqueue); } | ||
697 | } else { | ||
698 | if (!(status & UART_MSR_CTS)) { | ||
699 | info->tty->hw_stopped = 1; | ||
700 | if ((info->type != PORT_16550A) && | ||
701 | (!info->board->chip_flag)) { | ||
702 | info->IER &= ~UART_IER_THRI; | ||
703 | outb(info->IER, info->ioaddr + | ||
704 | UART_IER); | ||
705 | } | ||
706 | } | ||
707 | } | ||
652 | } | 708 | } |
653 | outb(0, ioaddress + 4); /* default set to RS232 mode */ | 709 | } else { |
654 | outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ | 710 | info->flags &= ~ASYNC_CTS_FLOW; |
655 | } | 711 | } |
656 | 712 | outb(info->MCR, info->ioaddr + UART_MCR); | |
657 | for (i = 0; i < brd->nports; i++) { | 713 | if (cflag & CLOCAL) { |
658 | brd->vector_mask |= (1 << i); | 714 | info->flags &= ~ASYNC_CHECK_CD; |
659 | brd->ports[i].baud_base = 921600; | 715 | } else { |
716 | info->flags |= ASYNC_CHECK_CD; | ||
717 | info->IER |= UART_IER_MSI; | ||
660 | } | 718 | } |
661 | return 0; | 719 | outb(info->IER, info->ioaddr + UART_IER); |
662 | err_relio: | ||
663 | pci_release_region(pdev, 2); | ||
664 | err: | ||
665 | return retval; | ||
666 | } | ||
667 | |||
668 | static int __init mxser_init(void) | ||
669 | { | ||
670 | struct pci_dev *pdev = NULL; | ||
671 | struct mxser_board *brd; | ||
672 | unsigned int i, m; | ||
673 | int retval, b, n; | ||
674 | |||
675 | mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); | ||
676 | if (!mxvar_sdriver) | ||
677 | return -ENOMEM; | ||
678 | spin_lock_init(&gm_lock); | ||
679 | 720 | ||
680 | for (i = 0; i < MXSER_BOARDS; i++) | 721 | /* |
681 | mxser_boards[i].board_type = -1; | 722 | * Set up parity check flag |
723 | */ | ||
724 | info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; | ||
725 | if (I_INPCK(info->tty)) | ||
726 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; | ||
727 | if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) | ||
728 | info->read_status_mask |= UART_LSR_BI; | ||
682 | 729 | ||
683 | printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", | 730 | info->ignore_status_mask = 0; |
684 | MXSER_VERSION); | ||
685 | 731 | ||
686 | /* Initialize the tty_driver structure */ | 732 | if (I_IGNBRK(info->tty)) { |
687 | mxvar_sdriver->magic = TTY_DRIVER_MAGIC; | 733 | info->ignore_status_mask |= UART_LSR_BI; |
688 | mxvar_sdriver->name = "ttyM"; | 734 | info->read_status_mask |= UART_LSR_BI; |
689 | mxvar_sdriver->major = ttymajor; | 735 | /* |
690 | mxvar_sdriver->minor_start = 0; | 736 | * If we're ignore parity and break indicators, ignore |
691 | mxvar_sdriver->num = MXSER_PORTS + 1; | 737 | * overruns too. (For real raw support). |
692 | mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; | 738 | */ |
693 | mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; | 739 | if (I_IGNPAR(info->tty)) { |
694 | mxvar_sdriver->init_termios = tty_std_termios; | 740 | info->ignore_status_mask |= |
695 | mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; | 741 | UART_LSR_OE | |
696 | mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW; | 742 | UART_LSR_PE | |
697 | tty_set_operations(mxvar_sdriver, &mxser_ops); | 743 | UART_LSR_FE; |
698 | mxvar_sdriver->ttys = mxvar_tty; | 744 | info->read_status_mask |= |
699 | mxvar_sdriver->termios = mxvar_termios; | 745 | UART_LSR_OE | |
700 | mxvar_sdriver->termios_locked = mxvar_termios_locked; | 746 | UART_LSR_PE | |
747 | UART_LSR_FE; | ||
748 | } | ||
749 | } | ||
750 | /* following add by Victor Yu. 09-02-2002 */ | ||
751 | if (info->board->chip_flag) { | ||
752 | spin_lock_irqsave(&info->slock, flags); | ||
753 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); | ||
754 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); | ||
755 | if (I_IXON(info->tty)) { | ||
756 | ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
757 | } else { | ||
758 | DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
759 | } | ||
760 | if (I_IXOFF(info->tty)) { | ||
761 | ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
762 | } else { | ||
763 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
764 | } | ||
765 | /* | ||
766 | if ( I_IXANY(info->tty) ) { | ||
767 | info->MCR |= MOXA_MUST_MCR_XON_ANY; | ||
768 | ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr); | ||
769 | } else { | ||
770 | info->MCR &= ~MOXA_MUST_MCR_XON_ANY; | ||
771 | DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr); | ||
772 | } | ||
773 | */ | ||
774 | spin_unlock_irqrestore(&info->slock, flags); | ||
775 | } | ||
776 | /* above add by Victor Yu. 09-02-2002 */ | ||
701 | 777 | ||
702 | mxvar_diagflag = 0; | ||
703 | 778 | ||
704 | m = 0; | 779 | outb(fcr, info->ioaddr + UART_FCR); /* set fcr */ |
705 | /* Start finding ISA boards here */ | 780 | outb(cval, info->ioaddr + UART_LCR); |
706 | for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { | ||
707 | int cap; | ||
708 | 781 | ||
709 | if (!(cap = mxserBoardCAP[b])) | 782 | return ret; |
710 | continue; | 783 | } |
711 | 784 | ||
712 | brd = &mxser_boards[m]; | 785 | static void mxser_check_modem_status(struct mxser_port *port, int status) |
713 | retval = mxser_get_ISA_conf(cap, brd); | 786 | { |
787 | /* update input line counters */ | ||
788 | if (status & UART_MSR_TERI) | ||
789 | port->icount.rng++; | ||
790 | if (status & UART_MSR_DDSR) | ||
791 | port->icount.dsr++; | ||
792 | if (status & UART_MSR_DDCD) | ||
793 | port->icount.dcd++; | ||
794 | if (status & UART_MSR_DCTS) | ||
795 | port->icount.cts++; | ||
796 | port->mon_data.modem_status = status; | ||
797 | wake_up_interruptible(&port->delta_msr_wait); | ||
714 | 798 | ||
715 | if (retval != 0) | 799 | if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { |
716 | printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", | 800 | if (status & UART_MSR_DCD) |
717 | mxser_brdname[brd->board_type - 1], ioaddr[b]); | 801 | wake_up_interruptible(&port->open_wait); |
802 | schedule_work(&port->tqueue); | ||
803 | } | ||
718 | 804 | ||
719 | if (retval <= 0) { | 805 | if (port->flags & ASYNC_CTS_FLOW) { |
720 | if (retval == MXSER_ERR_IRQ) | 806 | if (port->tty->hw_stopped) { |
721 | printk(KERN_ERR "Invalid interrupt number, " | 807 | if (status & UART_MSR_CTS) { |
722 | "board not configured\n"); | 808 | port->tty->hw_stopped = 0; |
723 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
724 | printk(KERN_ERR "Invalid interrupt number, " | ||
725 | "board not configured\n"); | ||
726 | else if (retval == MXSER_ERR_VECTOR) | ||
727 | printk(KERN_ERR "Invalid interrupt vector, " | ||
728 | "board not configured\n"); | ||
729 | else if (retval == MXSER_ERR_IOADDR) | ||
730 | printk(KERN_ERR "Invalid I/O address, " | ||
731 | "board not configured\n"); | ||
732 | 809 | ||
733 | continue; | 810 | if ((port->type != PORT_16550A) && |
811 | (!port->board->chip_flag)) { | ||
812 | outb(port->IER & ~UART_IER_THRI, | ||
813 | port->ioaddr + UART_IER); | ||
814 | port->IER |= UART_IER_THRI; | ||
815 | outb(port->IER, port->ioaddr + | ||
816 | UART_IER); | ||
817 | } | ||
818 | set_bit(MXSER_EVENT_TXLOW, &port->event); | ||
819 | schedule_work(&port->tqueue); | ||
820 | } | ||
821 | } else { | ||
822 | if (!(status & UART_MSR_CTS)) { | ||
823 | port->tty->hw_stopped = 1; | ||
824 | if (port->type != PORT_16550A && | ||
825 | !port->board->chip_flag) { | ||
826 | port->IER &= ~UART_IER_THRI; | ||
827 | outb(port->IER, port->ioaddr + | ||
828 | UART_IER); | ||
829 | } | ||
830 | } | ||
734 | } | 831 | } |
832 | } | ||
833 | } | ||
735 | 834 | ||
736 | brd->pdev = NULL; | 835 | static int mxser_startup(struct mxser_port *info) |
836 | { | ||
837 | unsigned long page; | ||
838 | unsigned long flags; | ||
737 | 839 | ||
738 | /* mxser_initbrd will hook ISR. */ | 840 | page = __get_free_page(GFP_KERNEL); |
739 | if (mxser_initbrd(brd) < 0) | 841 | if (!page) |
740 | continue; | 842 | return -ENOMEM; |
741 | 843 | ||
742 | m++; | 844 | spin_lock_irqsave(&info->slock, flags); |
743 | } | ||
744 | 845 | ||
745 | /* Start finding ISA boards from module arg */ | 846 | if (info->flags & ASYNC_INITIALIZED) { |
746 | for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { | 847 | free_page(page); |
747 | unsigned long cap; | 848 | spin_unlock_irqrestore(&info->slock, flags); |
849 | return 0; | ||
850 | } | ||
748 | 851 | ||
749 | if (!(cap = ioaddr[b])) | 852 | if (!info->ioaddr || !info->type) { |
750 | continue; | 853 | if (info->tty) |
854 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
855 | free_page(page); | ||
856 | spin_unlock_irqrestore(&info->slock, flags); | ||
857 | return 0; | ||
858 | } | ||
859 | if (info->xmit_buf) | ||
860 | free_page(page); | ||
861 | else | ||
862 | info->xmit_buf = (unsigned char *) page; | ||
751 | 863 | ||
752 | brd = &mxser_boards[m]; | 864 | /* |
753 | retval = mxser_get_ISA_conf(cap, &mxser_boards[m]); | 865 | * Clear the FIFO buffers and disable them |
866 | * (they will be reenabled in mxser_change_speed()) | ||
867 | */ | ||
868 | if (info->board->chip_flag) | ||
869 | outb((UART_FCR_CLEAR_RCVR | | ||
870 | UART_FCR_CLEAR_XMIT | | ||
871 | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); | ||
872 | else | ||
873 | outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), | ||
874 | info->ioaddr + UART_FCR); | ||
754 | 875 | ||
755 | if (retval != 0) | 876 | /* |
756 | printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", | 877 | * At this point there's no way the LSR could still be 0xFF; |
757 | mxser_brdname[brd->board_type - 1], ioaddr[b]); | 878 | * if it is, then bail out, because there's likely no UART |
879 | * here. | ||
880 | */ | ||
881 | if (inb(info->ioaddr + UART_LSR) == 0xff) { | ||
882 | spin_unlock_irqrestore(&info->slock, flags); | ||
883 | if (capable(CAP_SYS_ADMIN)) { | ||
884 | if (info->tty) | ||
885 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
886 | return 0; | ||
887 | } else | ||
888 | return -ENODEV; | ||
889 | } | ||
758 | 890 | ||
759 | if (retval <= 0) { | 891 | /* |
760 | if (retval == MXSER_ERR_IRQ) | 892 | * Clear the interrupt registers. |
761 | printk(KERN_ERR "Invalid interrupt number, " | 893 | */ |
762 | "board not configured\n"); | 894 | (void) inb(info->ioaddr + UART_LSR); |
763 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | 895 | (void) inb(info->ioaddr + UART_RX); |
764 | printk(KERN_ERR "Invalid interrupt number, " | 896 | (void) inb(info->ioaddr + UART_IIR); |
765 | "board not configured\n"); | 897 | (void) inb(info->ioaddr + UART_MSR); |
766 | else if (retval == MXSER_ERR_VECTOR) | ||
767 | printk(KERN_ERR "Invalid interrupt vector, " | ||
768 | "board not configured\n"); | ||
769 | else if (retval == MXSER_ERR_IOADDR) | ||
770 | printk(KERN_ERR "Invalid I/O address, " | ||
771 | "board not configured\n"); | ||
772 | 898 | ||
773 | continue; | 899 | /* |
774 | } | 900 | * Now, initialize the UART |
901 | */ | ||
902 | outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
903 | info->MCR = UART_MCR_DTR | UART_MCR_RTS; | ||
904 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
775 | 905 | ||
776 | brd->pdev = NULL; | 906 | /* |
777 | /* mxser_initbrd will hook ISR. */ | 907 | * Finally, enable interrupts |
778 | if (mxser_initbrd(brd) < 0) | 908 | */ |
779 | continue; | 909 | info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; |
910 | /* info->IER = UART_IER_RLSI | UART_IER_RDI; */ | ||
780 | 911 | ||
781 | m++; | 912 | /* following add by Victor Yu. 08-30-2002 */ |
782 | } | 913 | if (info->board->chip_flag) |
914 | info->IER |= MOXA_MUST_IER_EGDAI; | ||
915 | /* above add by Victor Yu. 08-30-2002 */ | ||
916 | outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */ | ||
783 | 917 | ||
784 | /* start finding PCI board here */ | 918 | /* |
785 | n = ARRAY_SIZE(mxser_pcibrds) - 1; | 919 | * And clear the interrupt registers again for luck. |
786 | b = 0; | 920 | */ |
787 | while (b < n) { | 921 | (void) inb(info->ioaddr + UART_LSR); |
788 | pdev = pci_get_device(mxser_pcibrds[b].vendor, | 922 | (void) inb(info->ioaddr + UART_RX); |
789 | mxser_pcibrds[b].device, pdev); | 923 | (void) inb(info->ioaddr + UART_IIR); |
790 | if (pdev == NULL) { | 924 | (void) inb(info->ioaddr + UART_MSR); |
791 | b++; | ||
792 | continue; | ||
793 | } | ||
794 | printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", | ||
795 | mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], | ||
796 | pdev->bus->number, PCI_SLOT(pdev->devfn)); | ||
797 | if (m >= MXSER_BOARDS) | ||
798 | printk(KERN_ERR | ||
799 | "Too many Smartio/Industio family boards find " | ||
800 | "(maximum %d), board not configured\n", | ||
801 | MXSER_BOARDS); | ||
802 | else { | ||
803 | if (pci_enable_device(pdev)) { | ||
804 | printk(KERN_ERR "Moxa SmartI/O PCI enable " | ||
805 | "fail !\n"); | ||
806 | continue; | ||
807 | } | ||
808 | brd = &mxser_boards[m]; | ||
809 | brd->pdev = pdev; | ||
810 | retval = mxser_get_PCI_conf( | ||
811 | (int)mxser_pcibrds[b].driver_data, | ||
812 | brd, pdev); | ||
813 | if (retval < 0) { | ||
814 | if (retval == MXSER_ERR_IRQ) | ||
815 | printk(KERN_ERR | ||
816 | "Invalid interrupt number, " | ||
817 | "board not configured\n"); | ||
818 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
819 | printk(KERN_ERR | ||
820 | "Invalid interrupt number, " | ||
821 | "board not configured\n"); | ||
822 | else if (retval == MXSER_ERR_VECTOR) | ||
823 | printk(KERN_ERR | ||
824 | "Invalid interrupt vector, " | ||
825 | "board not configured\n"); | ||
826 | else if (retval == MXSER_ERR_IOADDR) | ||
827 | printk(KERN_ERR | ||
828 | "Invalid I/O address, " | ||
829 | "board not configured\n"); | ||
830 | continue; | ||
831 | } | ||
832 | /* mxser_initbrd will hook ISR. */ | ||
833 | if (mxser_initbrd(brd) < 0) | ||
834 | continue; | ||
835 | m++; | ||
836 | /* Keep an extra reference if we succeeded. It will | ||
837 | be returned at unload time */ | ||
838 | pci_dev_get(pdev); | ||
839 | } | ||
840 | } | ||
841 | 925 | ||
842 | retval = tty_register_driver(mxvar_sdriver); | 926 | if (info->tty) |
843 | if (retval) { | 927 | clear_bit(TTY_IO_ERROR, &info->tty->flags); |
844 | printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family" | 928 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
845 | " driver !\n"); | ||
846 | put_tty_driver(mxvar_sdriver); | ||
847 | 929 | ||
848 | for (i = 0; i < MXSER_BOARDS; i++) { | 930 | /* |
849 | if (mxser_boards[i].board_type == -1) | 931 | * and set the speed of the serial port |
850 | continue; | 932 | */ |
851 | else { | 933 | spin_unlock_irqrestore(&info->slock, flags); |
852 | free_irq(mxser_boards[i].irq, &mxser_boards[i]); | 934 | mxser_change_speed(info, NULL); |
853 | /* todo: release io, vector */ | ||
854 | } | ||
855 | } | ||
856 | return retval; | ||
857 | } | ||
858 | 935 | ||
936 | info->flags |= ASYNC_INITIALIZED; | ||
859 | return 0; | 937 | return 0; |
860 | } | 938 | } |
861 | 939 | ||
862 | static void mxser_do_softint(void *private_) | 940 | /* |
941 | * This routine will shutdown a serial port; interrupts maybe disabled, and | ||
942 | * DTR is dropped if the hangup on close termio flag is on. | ||
943 | */ | ||
944 | static void mxser_shutdown(struct mxser_port *info) | ||
863 | { | 945 | { |
864 | struct mxser_port *info = private_; | 946 | unsigned long flags; |
865 | struct tty_struct *tty; | ||
866 | 947 | ||
867 | tty = info->tty; | 948 | if (!(info->flags & ASYNC_INITIALIZED)) |
949 | return; | ||
868 | 950 | ||
869 | if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) | 951 | spin_lock_irqsave(&info->slock, flags); |
870 | tty_wakeup(tty); | ||
871 | if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) | ||
872 | tty_hangup(tty); | ||
873 | } | ||
874 | 952 | ||
875 | static unsigned char mxser_get_msr(int baseaddr, int mode, int port) | 953 | /* |
876 | { | 954 | * clear delta_msr_wait queue to avoid mem leaks: we may free the irq |
877 | unsigned char status = 0; | 955 | * here so the queue might never be waken up |
956 | */ | ||
957 | wake_up_interruptible(&info->delta_msr_wait); | ||
878 | 958 | ||
879 | status = inb(baseaddr + UART_MSR); | 959 | /* |
960 | * Free the IRQ, if necessary | ||
961 | */ | ||
962 | if (info->xmit_buf) { | ||
963 | free_page((unsigned long) info->xmit_buf); | ||
964 | info->xmit_buf = NULL; | ||
965 | } | ||
880 | 966 | ||
881 | mxser_msr[port] &= 0x0F; | 967 | info->IER = 0; |
882 | mxser_msr[port] |= status; | 968 | outb(0x00, info->ioaddr + UART_IER); |
883 | status = mxser_msr[port]; | ||
884 | if (mode) | ||
885 | mxser_msr[port] = 0; | ||
886 | 969 | ||
887 | return status; | 970 | if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) |
971 | info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); | ||
972 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
973 | |||
974 | /* clear Rx/Tx FIFO's */ | ||
975 | /* following add by Victor Yu. 08-30-2002 */ | ||
976 | if (info->board->chip_flag) | ||
977 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | | ||
978 | MOXA_MUST_FCR_GDA_MODE_ENABLE, | ||
979 | info->ioaddr + UART_FCR); | ||
980 | else | ||
981 | /* above add by Victor Yu. 08-30-2002 */ | ||
982 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, | ||
983 | info->ioaddr + UART_FCR); | ||
984 | |||
985 | /* read data port to reset things */ | ||
986 | (void) inb(info->ioaddr + UART_RX); | ||
987 | |||
988 | if (info->tty) | ||
989 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
990 | |||
991 | info->flags &= ~ASYNC_INITIALIZED; | ||
992 | |||
993 | /* following add by Victor Yu. 09-23-2002 */ | ||
994 | if (info->board->chip_flag) | ||
995 | SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
996 | /* above add by Victor Yu. 09-23-2002 */ | ||
997 | |||
998 | spin_unlock_irqrestore(&info->slock, flags); | ||
888 | } | 999 | } |
889 | 1000 | ||
890 | /* | 1001 | /* |
@@ -1200,250 +1311,295 @@ static void mxser_flush_buffer(struct tty_struct *tty) | |||
1200 | (tty->ldisc.write_wakeup) (tty); | 1311 | (tty->ldisc.write_wakeup) (tty); |
1201 | } | 1312 | } |
1202 | 1313 | ||
1203 | static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) | 1314 | /* |
1315 | * ------------------------------------------------------------ | ||
1316 | * friends of mxser_ioctl() | ||
1317 | * ------------------------------------------------------------ | ||
1318 | */ | ||
1319 | static int mxser_get_serial_info(struct mxser_port *info, | ||
1320 | struct serial_struct __user *retinfo) | ||
1204 | { | 1321 | { |
1205 | struct mxser_port *info = tty->driver_data; | 1322 | struct serial_struct tmp; |
1206 | int retval; | ||
1207 | struct async_icount cprev, cnow; /* kernel counter temps */ | ||
1208 | struct serial_icounter_struct __user *p_cuser; | ||
1209 | unsigned long templ; | ||
1210 | unsigned long flags; | ||
1211 | void __user *argp = (void __user *)arg; | ||
1212 | 1323 | ||
1213 | if (tty->index == MXSER_PORTS) | 1324 | if (!retinfo) |
1214 | return mxser_ioctl_special(cmd, argp); | 1325 | return -EFAULT; |
1326 | memset(&tmp, 0, sizeof(tmp)); | ||
1327 | tmp.type = info->type; | ||
1328 | tmp.line = info->tty->index; | ||
1329 | tmp.port = info->ioaddr; | ||
1330 | tmp.irq = info->board->irq; | ||
1331 | tmp.flags = info->flags; | ||
1332 | tmp.baud_base = info->baud_base; | ||
1333 | tmp.close_delay = info->close_delay; | ||
1334 | tmp.closing_wait = info->closing_wait; | ||
1335 | tmp.custom_divisor = info->custom_divisor; | ||
1336 | tmp.hub6 = 0; | ||
1337 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
1338 | return -EFAULT; | ||
1339 | return 0; | ||
1340 | } | ||
1215 | 1341 | ||
1216 | /* following add by Victor Yu. 01-05-2004 */ | 1342 | static int mxser_set_serial_info(struct mxser_port *info, |
1217 | if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { | 1343 | struct serial_struct __user *new_info) |
1218 | int p; | 1344 | { |
1219 | unsigned long opmode; | 1345 | struct serial_struct new_serial; |
1220 | static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; | 1346 | unsigned int flags; |
1221 | int shiftbit; | 1347 | int retval = 0; |
1222 | unsigned char val, mask; | ||
1223 | 1348 | ||
1224 | p = tty->index % 4; | 1349 | if (!new_info || !info->ioaddr) |
1225 | if (cmd == MOXA_SET_OP_MODE) { | 1350 | return -EFAULT; |
1226 | if (get_user(opmode, (int __user *) argp)) | 1351 | if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) |
1227 | return -EFAULT; | 1352 | return -EFAULT; |
1228 | if (opmode != RS232_MODE && | ||
1229 | opmode != RS485_2WIRE_MODE && | ||
1230 | opmode != RS422_MODE && | ||
1231 | opmode != RS485_4WIRE_MODE) | ||
1232 | return -EFAULT; | ||
1233 | mask = ModeMask[p]; | ||
1234 | shiftbit = p * 2; | ||
1235 | val = inb(info->opmode_ioaddr); | ||
1236 | val &= mask; | ||
1237 | val |= (opmode << shiftbit); | ||
1238 | outb(val, info->opmode_ioaddr); | ||
1239 | } else { | ||
1240 | shiftbit = p * 2; | ||
1241 | opmode = inb(info->opmode_ioaddr) >> shiftbit; | ||
1242 | opmode &= OP_MODE_MASK; | ||
1243 | if (copy_to_user(argp, &opmode, sizeof(int))) | ||
1244 | return -EFAULT; | ||
1245 | } | ||
1246 | return 0; | ||
1247 | } | ||
1248 | /* above add by Victor Yu. 01-05-2004 */ | ||
1249 | 1353 | ||
1250 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | 1354 | if ((new_serial.irq != info->board->irq) || |
1251 | if (tty->flags & (1 << TTY_IO_ERROR)) | 1355 | (new_serial.port != info->ioaddr) || |
1252 | return -EIO; | 1356 | (new_serial.custom_divisor != info->custom_divisor) || |
1253 | } | 1357 | (new_serial.baud_base != info->baud_base)) |
1254 | switch (cmd) { | 1358 | return -EPERM; |
1255 | case TCSBRK: /* SVID version: non-zero arg --> no break */ | ||
1256 | retval = tty_check_change(tty); | ||
1257 | if (retval) | ||
1258 | return retval; | ||
1259 | tty_wait_until_sent(tty, 0); | ||
1260 | if (!arg) | ||
1261 | mxser_send_break(info, HZ / 4); /* 1/4 second */ | ||
1262 | return 0; | ||
1263 | case TCSBRKP: /* support for POSIX tcsendbreak() */ | ||
1264 | retval = tty_check_change(tty); | ||
1265 | if (retval) | ||
1266 | return retval; | ||
1267 | tty_wait_until_sent(tty, 0); | ||
1268 | mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); | ||
1269 | return 0; | ||
1270 | case TIOCGSOFTCAR: | ||
1271 | return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp); | ||
1272 | case TIOCSSOFTCAR: | ||
1273 | if (get_user(templ, (unsigned long __user *) argp)) | ||
1274 | return -EFAULT; | ||
1275 | arg = templ; | ||
1276 | tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); | ||
1277 | return 0; | ||
1278 | case TIOCGSERIAL: | ||
1279 | return mxser_get_serial_info(info, argp); | ||
1280 | case TIOCSSERIAL: | ||
1281 | return mxser_set_serial_info(info, argp); | ||
1282 | case TIOCSERGETLSR: /* Get line status register */ | ||
1283 | return mxser_get_lsr_info(info, argp); | ||
1284 | /* | ||
1285 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
1286 | * - mask passed in arg for lines of interest | ||
1287 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
1288 | * Caller should use TIOCGICOUNT to see which one it was | ||
1289 | */ | ||
1290 | case TIOCMIWAIT: { | ||
1291 | DECLARE_WAITQUEUE(wait, current); | ||
1292 | int ret; | ||
1293 | spin_lock_irqsave(&info->slock, flags); | ||
1294 | cprev = info->icount; /* note the counters on entry */ | ||
1295 | spin_unlock_irqrestore(&info->slock, flags); | ||
1296 | 1359 | ||
1297 | add_wait_queue(&info->delta_msr_wait, &wait); | 1360 | flags = info->flags & ASYNC_SPD_MASK; |
1298 | while (1) { | 1361 | |
1299 | spin_lock_irqsave(&info->slock, flags); | 1362 | if (!capable(CAP_SYS_ADMIN)) { |
1300 | cnow = info->icount; /* atomic copy */ | 1363 | if ((new_serial.baud_base != info->baud_base) || |
1301 | spin_unlock_irqrestore(&info->slock, flags); | 1364 | (new_serial.close_delay != info->close_delay) || |
1302 | 1365 | ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) | |
1303 | set_current_state(TASK_INTERRUPTIBLE); | 1366 | return -EPERM; |
1304 | if (((arg & TIOCM_RNG) && | 1367 | info->flags = ((info->flags & ~ASYNC_USR_MASK) | |
1305 | (cnow.rng != cprev.rng)) || | 1368 | (new_serial.flags & ASYNC_USR_MASK)); |
1306 | ((arg & TIOCM_DSR) && | 1369 | } else { |
1307 | (cnow.dsr != cprev.dsr)) || | ||
1308 | ((arg & TIOCM_CD) && | ||
1309 | (cnow.dcd != cprev.dcd)) || | ||
1310 | ((arg & TIOCM_CTS) && | ||
1311 | (cnow.cts != cprev.cts))) { | ||
1312 | ret = 0; | ||
1313 | break; | ||
1314 | } | ||
1315 | /* see if a signal did it */ | ||
1316 | if (signal_pending(current)) { | ||
1317 | ret = -ERESTARTSYS; | ||
1318 | break; | ||
1319 | } | ||
1320 | cprev = cnow; | ||
1321 | } | ||
1322 | current->state = TASK_RUNNING; | ||
1323 | remove_wait_queue(&info->delta_msr_wait, &wait); | ||
1324 | break; | ||
1325 | } | ||
1326 | /* NOTREACHED */ | ||
1327 | /* | 1370 | /* |
1328 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | 1371 | * OK, past this point, all the error checking has been done. |
1329 | * Return: write counters to the user passed counter struct | 1372 | * At this point, we start making changes..... |
1330 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1331 | * RI where only 0->1 is counted. | ||
1332 | */ | 1373 | */ |
1333 | case TIOCGICOUNT: | 1374 | info->flags = ((info->flags & ~ASYNC_FLAGS) | |
1334 | spin_lock_irqsave(&info->slock, flags); | 1375 | (new_serial.flags & ASYNC_FLAGS)); |
1335 | cnow = info->icount; | 1376 | info->close_delay = new_serial.close_delay * HZ / 100; |
1336 | spin_unlock_irqrestore(&info->slock, flags); | 1377 | info->closing_wait = new_serial.closing_wait * HZ / 100; |
1337 | p_cuser = argp; | 1378 | info->tty->low_latency = |
1338 | /* modified by casper 1/11/2000 */ | 1379 | (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1339 | if (put_user(cnow.frame, &p_cuser->frame)) | 1380 | info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */ |
1340 | return -EFAULT; | 1381 | } |
1341 | if (put_user(cnow.brk, &p_cuser->brk)) | ||
1342 | return -EFAULT; | ||
1343 | if (put_user(cnow.overrun, &p_cuser->overrun)) | ||
1344 | return -EFAULT; | ||
1345 | if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) | ||
1346 | return -EFAULT; | ||
1347 | if (put_user(cnow.parity, &p_cuser->parity)) | ||
1348 | return -EFAULT; | ||
1349 | if (put_user(cnow.rx, &p_cuser->rx)) | ||
1350 | return -EFAULT; | ||
1351 | if (put_user(cnow.tx, &p_cuser->tx)) | ||
1352 | return -EFAULT; | ||
1353 | put_user(cnow.cts, &p_cuser->cts); | ||
1354 | put_user(cnow.dsr, &p_cuser->dsr); | ||
1355 | put_user(cnow.rng, &p_cuser->rng); | ||
1356 | put_user(cnow.dcd, &p_cuser->dcd); | ||
1357 | return 0; | ||
1358 | case MOXA_HighSpeedOn: | ||
1359 | return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); | ||
1360 | case MOXA_SDS_RSTICOUNTER: { | ||
1361 | info->mon_data.rxcnt = 0; | ||
1362 | info->mon_data.txcnt = 0; | ||
1363 | return 0; | ||
1364 | } | ||
1365 | /* (above) added by James. */ | ||
1366 | case MOXA_ASPP_SETBAUD:{ | ||
1367 | long baud; | ||
1368 | if (get_user(baud, (long __user *)argp)) | ||
1369 | return -EFAULT; | ||
1370 | mxser_set_baud(info, baud); | ||
1371 | return 0; | ||
1372 | } | ||
1373 | case MOXA_ASPP_GETBAUD: | ||
1374 | if (copy_to_user(argp, &info->realbaud, sizeof(long))) | ||
1375 | return -EFAULT; | ||
1376 | 1382 | ||
1377 | return 0; | 1383 | /* added by casper, 3/17/2000, for mouse */ |
1384 | info->type = new_serial.type; | ||
1378 | 1385 | ||
1379 | case MOXA_ASPP_OQUEUE:{ | 1386 | process_txrx_fifo(info); |
1380 | int len, lsr; | ||
1381 | 1387 | ||
1382 | len = mxser_chars_in_buffer(tty); | 1388 | if (info->flags & ASYNC_INITIALIZED) { |
1389 | if (flags != (info->flags & ASYNC_SPD_MASK)) | ||
1390 | mxser_change_speed(info, NULL); | ||
1391 | } else | ||
1392 | retval = mxser_startup(info); | ||
1383 | 1393 | ||
1384 | lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT; | 1394 | return retval; |
1395 | } | ||
1385 | 1396 | ||
1386 | len += (lsr ? 0 : 1); | 1397 | /* |
1398 | * mxser_get_lsr_info - get line status register info | ||
1399 | * | ||
1400 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
1401 | * is emptied. On bus types like RS485, the transmitter must | ||
1402 | * release the bus after transmitting. This must be done when | ||
1403 | * the transmit shift register is empty, not be done when the | ||
1404 | * transmit holding register is empty. This functionality | ||
1405 | * allows an RS485 driver to be written in user space. | ||
1406 | */ | ||
1407 | static int mxser_get_lsr_info(struct mxser_port *info, | ||
1408 | unsigned int __user *value) | ||
1409 | { | ||
1410 | unsigned char status; | ||
1411 | unsigned int result; | ||
1412 | unsigned long flags; | ||
1387 | 1413 | ||
1388 | if (copy_to_user(argp, &len, sizeof(int))) | 1414 | spin_lock_irqsave(&info->slock, flags); |
1389 | return -EFAULT; | 1415 | status = inb(info->ioaddr + UART_LSR); |
1416 | spin_unlock_irqrestore(&info->slock, flags); | ||
1417 | result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); | ||
1418 | return put_user(result, value); | ||
1419 | } | ||
1390 | 1420 | ||
1391 | return 0; | 1421 | /* |
1392 | } | 1422 | * This routine sends a break character out the serial port. |
1393 | case MOXA_ASPP_MON: { | 1423 | */ |
1394 | int mcr, status; | 1424 | static void mxser_send_break(struct mxser_port *info, int duration) |
1425 | { | ||
1426 | unsigned long flags; | ||
1395 | 1427 | ||
1396 | /* info->mon_data.ser_param = tty->termios->c_cflag; */ | 1428 | if (!info->ioaddr) |
1429 | return; | ||
1430 | set_current_state(TASK_INTERRUPTIBLE); | ||
1431 | spin_lock_irqsave(&info->slock, flags); | ||
1432 | outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC, | ||
1433 | info->ioaddr + UART_LCR); | ||
1434 | spin_unlock_irqrestore(&info->slock, flags); | ||
1435 | schedule_timeout(duration); | ||
1436 | spin_lock_irqsave(&info->slock, flags); | ||
1437 | outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, | ||
1438 | info->ioaddr + UART_LCR); | ||
1439 | spin_unlock_irqrestore(&info->slock, flags); | ||
1440 | } | ||
1397 | 1441 | ||
1398 | status = mxser_get_msr(info->ioaddr, 1, tty->index); | 1442 | static int mxser_tiocmget(struct tty_struct *tty, struct file *file) |
1399 | mxser_check_modem_status(info, status); | 1443 | { |
1444 | struct mxser_port *info = tty->driver_data; | ||
1445 | unsigned char control, status; | ||
1446 | unsigned long flags; | ||
1400 | 1447 | ||
1401 | mcr = inb(info->ioaddr + UART_MCR); | ||
1402 | if (mcr & MOXA_MUST_MCR_XON_FLAG) | ||
1403 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; | ||
1404 | else | ||
1405 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; | ||
1406 | 1448 | ||
1407 | if (mcr & MOXA_MUST_MCR_TX_XON) | 1449 | if (tty->index == MXSER_PORTS) |
1408 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; | 1450 | return -ENOIOCTLCMD; |
1409 | else | 1451 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1410 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; | 1452 | return -EIO; |
1411 | 1453 | ||
1412 | if (info->tty->hw_stopped) | 1454 | control = info->MCR; |
1413 | info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; | ||
1414 | else | ||
1415 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; | ||
1416 | 1455 | ||
1417 | if (copy_to_user(argp, &info->mon_data, | 1456 | spin_lock_irqsave(&info->slock, flags); |
1418 | sizeof(struct mxser_mon))) | 1457 | status = inb(info->ioaddr + UART_MSR); |
1419 | return -EFAULT; | 1458 | if (status & UART_MSR_ANY_DELTA) |
1459 | mxser_check_modem_status(info, status); | ||
1460 | spin_unlock_irqrestore(&info->slock, flags); | ||
1461 | return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | | ||
1462 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | | ||
1463 | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | | ||
1464 | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | | ||
1465 | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | | ||
1466 | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); | ||
1467 | } | ||
1420 | 1468 | ||
1421 | return 0; | 1469 | static int mxser_tiocmset(struct tty_struct *tty, struct file *file, |
1422 | } | 1470 | unsigned int set, unsigned int clear) |
1471 | { | ||
1472 | struct mxser_port *info = tty->driver_data; | ||
1473 | unsigned long flags; | ||
1423 | 1474 | ||
1424 | case MOXA_ASPP_LSTATUS: { | ||
1425 | if (copy_to_user(argp, &info->err_shadow, | ||
1426 | sizeof(unsigned char))) | ||
1427 | return -EFAULT; | ||
1428 | 1475 | ||
1429 | info->err_shadow = 0; | 1476 | if (tty->index == MXSER_PORTS) |
1430 | return 0; | 1477 | return -ENOIOCTLCMD; |
1431 | } | 1478 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1432 | case MOXA_SET_BAUD_METHOD: { | 1479 | return -EIO; |
1433 | int method; | ||
1434 | 1480 | ||
1435 | if (get_user(method, (int __user *)argp)) | 1481 | spin_lock_irqsave(&info->slock, flags); |
1436 | return -EFAULT; | ||
1437 | mxser_set_baud_method[tty->index] = method; | ||
1438 | if (copy_to_user(argp, &method, sizeof(int))) | ||
1439 | return -EFAULT; | ||
1440 | 1482 | ||
1441 | return 0; | 1483 | if (set & TIOCM_RTS) |
1484 | info->MCR |= UART_MCR_RTS; | ||
1485 | if (set & TIOCM_DTR) | ||
1486 | info->MCR |= UART_MCR_DTR; | ||
1487 | |||
1488 | if (clear & TIOCM_RTS) | ||
1489 | info->MCR &= ~UART_MCR_RTS; | ||
1490 | if (clear & TIOCM_DTR) | ||
1491 | info->MCR &= ~UART_MCR_DTR; | ||
1492 | |||
1493 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
1494 | spin_unlock_irqrestore(&info->slock, flags); | ||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | static int mxser_program_mode(int port) | ||
1499 | { | ||
1500 | int id, i, j, n; | ||
1501 | /* unsigned long flags; */ | ||
1502 | |||
1503 | spin_lock(&gm_lock); | ||
1504 | outb(0, port); | ||
1505 | outb(0, port); | ||
1506 | outb(0, port); | ||
1507 | (void)inb(port); | ||
1508 | (void)inb(port); | ||
1509 | outb(0, port); | ||
1510 | (void)inb(port); | ||
1511 | /* restore_flags(flags); */ | ||
1512 | spin_unlock(&gm_lock); | ||
1513 | |||
1514 | id = inb(port + 1) & 0x1F; | ||
1515 | if ((id != C168_ASIC_ID) && | ||
1516 | (id != C104_ASIC_ID) && | ||
1517 | (id != C102_ASIC_ID) && | ||
1518 | (id != CI132_ASIC_ID) && | ||
1519 | (id != CI134_ASIC_ID) && | ||
1520 | (id != CI104J_ASIC_ID)) | ||
1521 | return -1; | ||
1522 | for (i = 0, j = 0; i < 4; i++) { | ||
1523 | n = inb(port + 2); | ||
1524 | if (n == 'M') { | ||
1525 | j = 1; | ||
1526 | } else if ((j == 1) && (n == 1)) { | ||
1527 | j = 2; | ||
1528 | break; | ||
1529 | } else | ||
1530 | j = 0; | ||
1531 | } | ||
1532 | if (j != 2) | ||
1533 | id = -2; | ||
1534 | return id; | ||
1535 | } | ||
1536 | |||
1537 | static void mxser_normal_mode(int port) | ||
1538 | { | ||
1539 | int i, n; | ||
1540 | |||
1541 | outb(0xA5, port + 1); | ||
1542 | outb(0x80, port + 3); | ||
1543 | outb(12, port + 0); /* 9600 bps */ | ||
1544 | outb(0, port + 1); | ||
1545 | outb(0x03, port + 3); /* 8 data bits */ | ||
1546 | outb(0x13, port + 4); /* loop back mode */ | ||
1547 | for (i = 0; i < 16; i++) { | ||
1548 | n = inb(port + 5); | ||
1549 | if ((n & 0x61) == 0x60) | ||
1550 | break; | ||
1551 | if ((n & 1) == 1) | ||
1552 | (void)inb(port); | ||
1553 | } | ||
1554 | outb(0x00, port + 4); | ||
1555 | } | ||
1556 | |||
1557 | #define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ | ||
1558 | #define CHIP_DO 0x02 /* Serial Data Output in Eprom */ | ||
1559 | #define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ | ||
1560 | #define CHIP_DI 0x08 /* Serial Data Input in Eprom */ | ||
1561 | #define EN_CCMD 0x000 /* Chip's command register */ | ||
1562 | #define EN0_RSARLO 0x008 /* Remote start address reg 0 */ | ||
1563 | #define EN0_RSARHI 0x009 /* Remote start address reg 1 */ | ||
1564 | #define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ | ||
1565 | #define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ | ||
1566 | #define EN0_DCFG 0x00E /* Data configuration reg WR */ | ||
1567 | #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ | ||
1568 | #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ | ||
1569 | #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ | ||
1570 | static int mxser_read_register(int port, unsigned short *regs) | ||
1571 | { | ||
1572 | int i, k, value, id; | ||
1573 | unsigned int j; | ||
1574 | |||
1575 | id = mxser_program_mode(port); | ||
1576 | if (id < 0) | ||
1577 | return id; | ||
1578 | for (i = 0; i < 14; i++) { | ||
1579 | k = (i & 0x3F) | 0x180; | ||
1580 | for (j = 0x100; j > 0; j >>= 1) { | ||
1581 | outb(CHIP_CS, port); | ||
1582 | if (k & j) { | ||
1583 | outb(CHIP_CS | CHIP_DO, port); | ||
1584 | outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ | ||
1585 | } else { | ||
1586 | outb(CHIP_CS, port); | ||
1587 | outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ | ||
1588 | } | ||
1442 | } | 1589 | } |
1443 | default: | 1590 | (void)inb(port); |
1444 | return -ENOIOCTLCMD; | 1591 | value = 0; |
1592 | for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { | ||
1593 | outb(CHIP_CS, port); | ||
1594 | outb(CHIP_CS | CHIP_SK, port); | ||
1595 | if (inb(port) & CHIP_DI) | ||
1596 | value |= j; | ||
1597 | } | ||
1598 | regs[i] = value; | ||
1599 | outb(0, port); | ||
1445 | } | 1600 | } |
1446 | return 0; | 1601 | mxser_normal_mode(port); |
1602 | return id; | ||
1447 | } | 1603 | } |
1448 | 1604 | ||
1449 | #ifndef CMSPAR | 1605 | #ifndef CMSPAR |
@@ -1609,6 +1765,251 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | |||
1609 | return 0; | 1765 | return 0; |
1610 | } | 1766 | } |
1611 | 1767 | ||
1768 | static int mxser_ioctl(struct tty_struct *tty, struct file *file, | ||
1769 | unsigned int cmd, unsigned long arg) | ||
1770 | { | ||
1771 | struct mxser_port *info = tty->driver_data; | ||
1772 | struct async_icount cprev, cnow; /* kernel counter temps */ | ||
1773 | struct serial_icounter_struct __user *p_cuser; | ||
1774 | unsigned long templ; | ||
1775 | unsigned long flags; | ||
1776 | void __user *argp = (void __user *)arg; | ||
1777 | int retval; | ||
1778 | |||
1779 | if (tty->index == MXSER_PORTS) | ||
1780 | return mxser_ioctl_special(cmd, argp); | ||
1781 | |||
1782 | /* following add by Victor Yu. 01-05-2004 */ | ||
1783 | if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { | ||
1784 | int p; | ||
1785 | unsigned long opmode; | ||
1786 | static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; | ||
1787 | int shiftbit; | ||
1788 | unsigned char val, mask; | ||
1789 | |||
1790 | p = tty->index % 4; | ||
1791 | if (cmd == MOXA_SET_OP_MODE) { | ||
1792 | if (get_user(opmode, (int __user *) argp)) | ||
1793 | return -EFAULT; | ||
1794 | if (opmode != RS232_MODE && | ||
1795 | opmode != RS485_2WIRE_MODE && | ||
1796 | opmode != RS422_MODE && | ||
1797 | opmode != RS485_4WIRE_MODE) | ||
1798 | return -EFAULT; | ||
1799 | mask = ModeMask[p]; | ||
1800 | shiftbit = p * 2; | ||
1801 | val = inb(info->opmode_ioaddr); | ||
1802 | val &= mask; | ||
1803 | val |= (opmode << shiftbit); | ||
1804 | outb(val, info->opmode_ioaddr); | ||
1805 | } else { | ||
1806 | shiftbit = p * 2; | ||
1807 | opmode = inb(info->opmode_ioaddr) >> shiftbit; | ||
1808 | opmode &= OP_MODE_MASK; | ||
1809 | if (copy_to_user(argp, &opmode, sizeof(int))) | ||
1810 | return -EFAULT; | ||
1811 | } | ||
1812 | return 0; | ||
1813 | } | ||
1814 | /* above add by Victor Yu. 01-05-2004 */ | ||
1815 | |||
1816 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | ||
1817 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1818 | return -EIO; | ||
1819 | } | ||
1820 | switch (cmd) { | ||
1821 | case TCSBRK: /* SVID version: non-zero arg --> no break */ | ||
1822 | retval = tty_check_change(tty); | ||
1823 | if (retval) | ||
1824 | return retval; | ||
1825 | tty_wait_until_sent(tty, 0); | ||
1826 | if (!arg) | ||
1827 | mxser_send_break(info, HZ / 4); /* 1/4 second */ | ||
1828 | return 0; | ||
1829 | case TCSBRKP: /* support for POSIX tcsendbreak() */ | ||
1830 | retval = tty_check_change(tty); | ||
1831 | if (retval) | ||
1832 | return retval; | ||
1833 | tty_wait_until_sent(tty, 0); | ||
1834 | mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); | ||
1835 | return 0; | ||
1836 | case TIOCGSOFTCAR: | ||
1837 | return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp); | ||
1838 | case TIOCSSOFTCAR: | ||
1839 | if (get_user(templ, (unsigned long __user *) argp)) | ||
1840 | return -EFAULT; | ||
1841 | arg = templ; | ||
1842 | tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); | ||
1843 | return 0; | ||
1844 | case TIOCGSERIAL: | ||
1845 | return mxser_get_serial_info(info, argp); | ||
1846 | case TIOCSSERIAL: | ||
1847 | return mxser_set_serial_info(info, argp); | ||
1848 | case TIOCSERGETLSR: /* Get line status register */ | ||
1849 | return mxser_get_lsr_info(info, argp); | ||
1850 | /* | ||
1851 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
1852 | * - mask passed in arg for lines of interest | ||
1853 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
1854 | * Caller should use TIOCGICOUNT to see which one it was | ||
1855 | */ | ||
1856 | case TIOCMIWAIT: { | ||
1857 | DECLARE_WAITQUEUE(wait, current); | ||
1858 | int ret; | ||
1859 | spin_lock_irqsave(&info->slock, flags); | ||
1860 | cprev = info->icount; /* note the counters on entry */ | ||
1861 | spin_unlock_irqrestore(&info->slock, flags); | ||
1862 | |||
1863 | add_wait_queue(&info->delta_msr_wait, &wait); | ||
1864 | while (1) { | ||
1865 | spin_lock_irqsave(&info->slock, flags); | ||
1866 | cnow = info->icount; /* atomic copy */ | ||
1867 | spin_unlock_irqrestore(&info->slock, flags); | ||
1868 | |||
1869 | set_current_state(TASK_INTERRUPTIBLE); | ||
1870 | if (((arg & TIOCM_RNG) && | ||
1871 | (cnow.rng != cprev.rng)) || | ||
1872 | ((arg & TIOCM_DSR) && | ||
1873 | (cnow.dsr != cprev.dsr)) || | ||
1874 | ((arg & TIOCM_CD) && | ||
1875 | (cnow.dcd != cprev.dcd)) || | ||
1876 | ((arg & TIOCM_CTS) && | ||
1877 | (cnow.cts != cprev.cts))) { | ||
1878 | ret = 0; | ||
1879 | break; | ||
1880 | } | ||
1881 | /* see if a signal did it */ | ||
1882 | if (signal_pending(current)) { | ||
1883 | ret = -ERESTARTSYS; | ||
1884 | break; | ||
1885 | } | ||
1886 | cprev = cnow; | ||
1887 | } | ||
1888 | current->state = TASK_RUNNING; | ||
1889 | remove_wait_queue(&info->delta_msr_wait, &wait); | ||
1890 | break; | ||
1891 | } | ||
1892 | /* NOTREACHED */ | ||
1893 | /* | ||
1894 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1895 | * Return: write counters to the user passed counter struct | ||
1896 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1897 | * RI where only 0->1 is counted. | ||
1898 | */ | ||
1899 | case TIOCGICOUNT: | ||
1900 | spin_lock_irqsave(&info->slock, flags); | ||
1901 | cnow = info->icount; | ||
1902 | spin_unlock_irqrestore(&info->slock, flags); | ||
1903 | p_cuser = argp; | ||
1904 | /* modified by casper 1/11/2000 */ | ||
1905 | if (put_user(cnow.frame, &p_cuser->frame)) | ||
1906 | return -EFAULT; | ||
1907 | if (put_user(cnow.brk, &p_cuser->brk)) | ||
1908 | return -EFAULT; | ||
1909 | if (put_user(cnow.overrun, &p_cuser->overrun)) | ||
1910 | return -EFAULT; | ||
1911 | if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) | ||
1912 | return -EFAULT; | ||
1913 | if (put_user(cnow.parity, &p_cuser->parity)) | ||
1914 | return -EFAULT; | ||
1915 | if (put_user(cnow.rx, &p_cuser->rx)) | ||
1916 | return -EFAULT; | ||
1917 | if (put_user(cnow.tx, &p_cuser->tx)) | ||
1918 | return -EFAULT; | ||
1919 | put_user(cnow.cts, &p_cuser->cts); | ||
1920 | put_user(cnow.dsr, &p_cuser->dsr); | ||
1921 | put_user(cnow.rng, &p_cuser->rng); | ||
1922 | put_user(cnow.dcd, &p_cuser->dcd); | ||
1923 | return 0; | ||
1924 | case MOXA_HighSpeedOn: | ||
1925 | return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); | ||
1926 | case MOXA_SDS_RSTICOUNTER: | ||
1927 | info->mon_data.rxcnt = 0; | ||
1928 | info->mon_data.txcnt = 0; | ||
1929 | return 0; | ||
1930 | /* (above) added by James. */ | ||
1931 | case MOXA_ASPP_SETBAUD:{ | ||
1932 | long baud; | ||
1933 | if (get_user(baud, (long __user *)argp)) | ||
1934 | return -EFAULT; | ||
1935 | mxser_set_baud(info, baud); | ||
1936 | return 0; | ||
1937 | } | ||
1938 | case MOXA_ASPP_GETBAUD: | ||
1939 | if (copy_to_user(argp, &info->realbaud, sizeof(long))) | ||
1940 | return -EFAULT; | ||
1941 | |||
1942 | return 0; | ||
1943 | |||
1944 | case MOXA_ASPP_OQUEUE:{ | ||
1945 | int len, lsr; | ||
1946 | |||
1947 | len = mxser_chars_in_buffer(tty); | ||
1948 | |||
1949 | lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT; | ||
1950 | |||
1951 | len += (lsr ? 0 : 1); | ||
1952 | |||
1953 | if (copy_to_user(argp, &len, sizeof(int))) | ||
1954 | return -EFAULT; | ||
1955 | |||
1956 | return 0; | ||
1957 | } | ||
1958 | case MOXA_ASPP_MON: { | ||
1959 | int mcr, status; | ||
1960 | |||
1961 | /* info->mon_data.ser_param = tty->termios->c_cflag; */ | ||
1962 | |||
1963 | status = mxser_get_msr(info->ioaddr, 1, tty->index); | ||
1964 | mxser_check_modem_status(info, status); | ||
1965 | |||
1966 | mcr = inb(info->ioaddr + UART_MCR); | ||
1967 | if (mcr & MOXA_MUST_MCR_XON_FLAG) | ||
1968 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; | ||
1969 | else | ||
1970 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; | ||
1971 | |||
1972 | if (mcr & MOXA_MUST_MCR_TX_XON) | ||
1973 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; | ||
1974 | else | ||
1975 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; | ||
1976 | |||
1977 | if (info->tty->hw_stopped) | ||
1978 | info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; | ||
1979 | else | ||
1980 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; | ||
1981 | |||
1982 | if (copy_to_user(argp, &info->mon_data, | ||
1983 | sizeof(struct mxser_mon))) | ||
1984 | return -EFAULT; | ||
1985 | |||
1986 | return 0; | ||
1987 | } | ||
1988 | case MOXA_ASPP_LSTATUS: { | ||
1989 | if (copy_to_user(argp, &info->err_shadow, | ||
1990 | sizeof(unsigned char))) | ||
1991 | return -EFAULT; | ||
1992 | |||
1993 | info->err_shadow = 0; | ||
1994 | return 0; | ||
1995 | } | ||
1996 | case MOXA_SET_BAUD_METHOD: { | ||
1997 | int method; | ||
1998 | |||
1999 | if (get_user(method, (int __user *)argp)) | ||
2000 | return -EFAULT; | ||
2001 | mxser_set_baud_method[tty->index] = method; | ||
2002 | if (copy_to_user(argp, &method, sizeof(int))) | ||
2003 | return -EFAULT; | ||
2004 | |||
2005 | return 0; | ||
2006 | } | ||
2007 | default: | ||
2008 | return -ENOIOCTLCMD; | ||
2009 | } | ||
2010 | return 0; | ||
2011 | } | ||
2012 | |||
1612 | static void mxser_stoprx(struct tty_struct *tty) | 2013 | static void mxser_stoprx(struct tty_struct *tty) |
1613 | { | 2014 | { |
1614 | struct mxser_port *info = tty->driver_data; | 2015 | struct mxser_port *info = tty->driver_data; |
@@ -1633,10 +2034,20 @@ static void mxser_stoprx(struct tty_struct *tty) | |||
1633 | } | 2034 | } |
1634 | } | 2035 | } |
1635 | 2036 | ||
1636 | static void mxser_startrx(struct tty_struct *tty) | 2037 | /* |
2038 | * This routine is called by the upper-layer tty layer to signal that | ||
2039 | * incoming characters should be throttled. | ||
2040 | */ | ||
2041 | static void mxser_throttle(struct tty_struct *tty) | ||
2042 | { | ||
2043 | mxser_stoprx(tty); | ||
2044 | } | ||
2045 | |||
2046 | static void mxser_unthrottle(struct tty_struct *tty) | ||
1637 | { | 2047 | { |
1638 | struct mxser_port *info = tty->driver_data; | 2048 | struct mxser_port *info = tty->driver_data; |
1639 | 2049 | ||
2050 | /* startrx */ | ||
1640 | info->ldisc_stop_rx = 0; | 2051 | info->ldisc_stop_rx = 0; |
1641 | if (I_IXOFF(tty)) { | 2052 | if (I_IXOFF(tty)) { |
1642 | if (info->x_char) | 2053 | if (info->x_char) |
@@ -1662,17 +2073,37 @@ static void mxser_startrx(struct tty_struct *tty) | |||
1662 | } | 2073 | } |
1663 | 2074 | ||
1664 | /* | 2075 | /* |
1665 | * This routine is called by the upper-layer tty layer to signal that | 2076 | * mxser_stop() and mxser_start() |
1666 | * incoming characters should be throttled. | 2077 | * |
2078 | * This routines are called before setting or resetting tty->stopped. | ||
2079 | * They enable or disable transmitter interrupts, as necessary. | ||
1667 | */ | 2080 | */ |
1668 | static void mxser_throttle(struct tty_struct *tty) | 2081 | static void mxser_stop(struct tty_struct *tty) |
1669 | { | 2082 | { |
1670 | mxser_stoprx(tty); | 2083 | struct mxser_port *info = tty->driver_data; |
2084 | unsigned long flags; | ||
2085 | |||
2086 | spin_lock_irqsave(&info->slock, flags); | ||
2087 | if (info->IER & UART_IER_THRI) { | ||
2088 | info->IER &= ~UART_IER_THRI; | ||
2089 | outb(info->IER, info->ioaddr + UART_IER); | ||
2090 | } | ||
2091 | spin_unlock_irqrestore(&info->slock, flags); | ||
1671 | } | 2092 | } |
1672 | 2093 | ||
1673 | static void mxser_unthrottle(struct tty_struct *tty) | 2094 | static void mxser_start(struct tty_struct *tty) |
1674 | { | 2095 | { |
1675 | mxser_startrx(tty); | 2096 | struct mxser_port *info = tty->driver_data; |
2097 | unsigned long flags; | ||
2098 | |||
2099 | spin_lock_irqsave(&info->slock, flags); | ||
2100 | if (info->xmit_cnt && info->xmit_buf | ||
2101 | /* && !(info->IER & UART_IER_THRI) */) { | ||
2102 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); | ||
2103 | info->IER |= UART_IER_THRI; | ||
2104 | outb(info->IER, info->ioaddr + UART_IER); | ||
2105 | } | ||
2106 | spin_unlock_irqrestore(&info->slock, flags); | ||
1676 | } | 2107 | } |
1677 | 2108 | ||
1678 | static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) | 2109 | static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios) |
@@ -1710,40 +2141,6 @@ static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termio | |||
1710 | } | 2141 | } |
1711 | 2142 | ||
1712 | /* | 2143 | /* |
1713 | * mxser_stop() and mxser_start() | ||
1714 | * | ||
1715 | * This routines are called before setting or resetting tty->stopped. | ||
1716 | * They enable or disable transmitter interrupts, as necessary. | ||
1717 | */ | ||
1718 | static void mxser_stop(struct tty_struct *tty) | ||
1719 | { | ||
1720 | struct mxser_port *info = tty->driver_data; | ||
1721 | unsigned long flags; | ||
1722 | |||
1723 | spin_lock_irqsave(&info->slock, flags); | ||
1724 | if (info->IER & UART_IER_THRI) { | ||
1725 | info->IER &= ~UART_IER_THRI; | ||
1726 | outb(info->IER, info->ioaddr + UART_IER); | ||
1727 | } | ||
1728 | spin_unlock_irqrestore(&info->slock, flags); | ||
1729 | } | ||
1730 | |||
1731 | static void mxser_start(struct tty_struct *tty) | ||
1732 | { | ||
1733 | struct mxser_port *info = tty->driver_data; | ||
1734 | unsigned long flags; | ||
1735 | |||
1736 | spin_lock_irqsave(&info->slock, flags); | ||
1737 | if (info->xmit_cnt && info->xmit_buf | ||
1738 | /* && !(info->IER & UART_IER_THRI) */) { | ||
1739 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); | ||
1740 | info->IER |= UART_IER_THRI; | ||
1741 | outb(info->IER, info->ioaddr + UART_IER); | ||
1742 | } | ||
1743 | spin_unlock_irqrestore(&info->slock, flags); | ||
1744 | } | ||
1745 | |||
1746 | /* | ||
1747 | * mxser_wait_until_sent() --- wait until the transmitter is empty | 2144 | * mxser_wait_until_sent() --- wait until the transmitter is empty |
1748 | */ | 2145 | */ |
1749 | static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) | 2146 | static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) |
@@ -1845,122 +2242,6 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state) | |||
1845 | 2242 | ||
1846 | /* (above) added by James. */ | 2243 | /* (above) added by James. */ |
1847 | 2244 | ||
1848 | |||
1849 | /* | ||
1850 | * This is the serial driver's generic interrupt routine | ||
1851 | */ | ||
1852 | static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1853 | { | ||
1854 | int status, iir, i; | ||
1855 | struct mxser_board *brd = NULL; | ||
1856 | struct mxser_port *port; | ||
1857 | int max, irqbits, bits, msr; | ||
1858 | int pass_counter = 0; | ||
1859 | unsigned int int_cnt; | ||
1860 | int handled = IRQ_NONE; | ||
1861 | |||
1862 | /* spin_lock(&gm_lock); */ | ||
1863 | |||
1864 | for (i = 0; i < MXSER_BOARDS; i++) | ||
1865 | if (dev_id == &mxser_boards[i]) { | ||
1866 | brd = dev_id; | ||
1867 | break; | ||
1868 | } | ||
1869 | |||
1870 | if (i == MXSER_BOARDS) | ||
1871 | goto irq_stop; | ||
1872 | if (brd == NULL) | ||
1873 | goto irq_stop; | ||
1874 | max = mxser_numports[brd->board_type - 1]; | ||
1875 | while (1) { | ||
1876 | irqbits = inb(brd->vector) & brd->vector_mask; | ||
1877 | if (irqbits == brd->vector_mask) | ||
1878 | break; | ||
1879 | |||
1880 | handled = IRQ_HANDLED; | ||
1881 | for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { | ||
1882 | if (irqbits == brd->vector_mask) | ||
1883 | break; | ||
1884 | if (bits & irqbits) | ||
1885 | continue; | ||
1886 | port = &brd->ports[i]; | ||
1887 | |||
1888 | int_cnt = 0; | ||
1889 | do { | ||
1890 | /* following add by Victor Yu. 09-13-2002 */ | ||
1891 | iir = inb(port->ioaddr + UART_IIR); | ||
1892 | if (iir & UART_IIR_NO_INT) | ||
1893 | break; | ||
1894 | iir &= MOXA_MUST_IIR_MASK; | ||
1895 | if (!port->tty) { | ||
1896 | status = inb(port->ioaddr + UART_LSR); | ||
1897 | outb(0x27, port->ioaddr + UART_FCR); | ||
1898 | inb(port->ioaddr + UART_MSR); | ||
1899 | break; | ||
1900 | } | ||
1901 | /* above add by Victor Yu. 09-13-2002 */ | ||
1902 | |||
1903 | /* following add by Victor Yu. 09-02-2002 */ | ||
1904 | status = inb(port->ioaddr + UART_LSR); | ||
1905 | |||
1906 | if (status & UART_LSR_PE) | ||
1907 | port->err_shadow |= NPPI_NOTIFY_PARITY; | ||
1908 | if (status & UART_LSR_FE) | ||
1909 | port->err_shadow |= NPPI_NOTIFY_FRAMING; | ||
1910 | if (status & UART_LSR_OE) | ||
1911 | port->err_shadow |= | ||
1912 | NPPI_NOTIFY_HW_OVERRUN; | ||
1913 | if (status & UART_LSR_BI) | ||
1914 | port->err_shadow |= NPPI_NOTIFY_BREAK; | ||
1915 | |||
1916 | if (port->board->chip_flag) { | ||
1917 | /* | ||
1918 | if ( (status & 0x02) && !(status & 0x01) ) { | ||
1919 | outb(port->ioaddr+UART_FCR, 0x23); | ||
1920 | continue; | ||
1921 | } | ||
1922 | */ | ||
1923 | if (iir == MOXA_MUST_IIR_GDA || | ||
1924 | iir == MOXA_MUST_IIR_RDA || | ||
1925 | iir == MOXA_MUST_IIR_RTO || | ||
1926 | iir == MOXA_MUST_IIR_LSR) | ||
1927 | mxser_receive_chars(port, | ||
1928 | &status); | ||
1929 | |||
1930 | } else { | ||
1931 | /* above add by Victor Yu. 09-02-2002 */ | ||
1932 | |||
1933 | status &= port->read_status_mask; | ||
1934 | if (status & UART_LSR_DR) | ||
1935 | mxser_receive_chars(port, | ||
1936 | &status); | ||
1937 | } | ||
1938 | msr = inb(port->ioaddr + UART_MSR); | ||
1939 | if (msr & UART_MSR_ANY_DELTA) | ||
1940 | mxser_check_modem_status(port, msr); | ||
1941 | |||
1942 | /* following add by Victor Yu. 09-13-2002 */ | ||
1943 | if (port->board->chip_flag) { | ||
1944 | if (iir == 0x02 && (status & | ||
1945 | UART_LSR_THRE)) | ||
1946 | mxser_transmit_chars(port); | ||
1947 | } else { | ||
1948 | /* above add by Victor Yu. 09-13-2002 */ | ||
1949 | |||
1950 | if (status & UART_LSR_THRE) | ||
1951 | mxser_transmit_chars(port); | ||
1952 | } | ||
1953 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); | ||
1954 | } | ||
1955 | if (pass_counter++ > MXSER_ISR_PASS_LIMIT) | ||
1956 | break; /* Prevent infinite loops */ | ||
1957 | } | ||
1958 | |||
1959 | irq_stop: | ||
1960 | /* spin_unlock(&gm_lock); */ | ||
1961 | return handled; | ||
1962 | } | ||
1963 | |||
1964 | static void mxser_receive_chars(struct mxser_port *port, int *status) | 2245 | static void mxser_receive_chars(struct mxser_port *port, int *status) |
1965 | { | 2246 | { |
1966 | struct tty_struct *tty = port->tty; | 2247 | struct tty_struct *tty = port->tty; |
@@ -2155,744 +2436,202 @@ unlock: | |||
2155 | spin_unlock_irqrestore(&port->slock, flags); | 2436 | spin_unlock_irqrestore(&port->slock, flags); |
2156 | } | 2437 | } |
2157 | 2438 | ||
2158 | static void mxser_check_modem_status(struct mxser_port *port, int status) | 2439 | /* |
2440 | * This is the serial driver's generic interrupt routine | ||
2441 | */ | ||
2442 | static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
2159 | { | 2443 | { |
2160 | /* update input line counters */ | 2444 | int status, iir, i; |
2161 | if (status & UART_MSR_TERI) | 2445 | struct mxser_board *brd = NULL; |
2162 | port->icount.rng++; | 2446 | struct mxser_port *port; |
2163 | if (status & UART_MSR_DDSR) | 2447 | int max, irqbits, bits, msr; |
2164 | port->icount.dsr++; | 2448 | int pass_counter = 0; |
2165 | if (status & UART_MSR_DDCD) | 2449 | unsigned int int_cnt; |
2166 | port->icount.dcd++; | 2450 | int handled = IRQ_NONE; |
2167 | if (status & UART_MSR_DCTS) | ||
2168 | port->icount.cts++; | ||
2169 | port->mon_data.modem_status = status; | ||
2170 | wake_up_interruptible(&port->delta_msr_wait); | ||
2171 | |||
2172 | if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { | ||
2173 | if (status & UART_MSR_DCD) | ||
2174 | wake_up_interruptible(&port->open_wait); | ||
2175 | schedule_work(&port->tqueue); | ||
2176 | } | ||
2177 | 2451 | ||
2178 | if (port->flags & ASYNC_CTS_FLOW) { | 2452 | /* spin_lock(&gm_lock); */ |
2179 | if (port->tty->hw_stopped) { | ||
2180 | if (status & UART_MSR_CTS) { | ||
2181 | port->tty->hw_stopped = 0; | ||
2182 | 2453 | ||
2183 | if ((port->type != PORT_16550A) && | 2454 | for (i = 0; i < MXSER_BOARDS; i++) |
2184 | (!port->board->chip_flag)) { | 2455 | if (dev_id == &mxser_boards[i]) { |
2185 | outb(port->IER & ~UART_IER_THRI, | 2456 | brd = dev_id; |
2186 | port->ioaddr + UART_IER); | 2457 | break; |
2187 | port->IER |= UART_IER_THRI; | ||
2188 | outb(port->IER, port->ioaddr + | ||
2189 | UART_IER); | ||
2190 | } | ||
2191 | set_bit(MXSER_EVENT_TXLOW, &port->event); | ||
2192 | schedule_work(&port->tqueue); | ||
2193 | } | ||
2194 | } else { | ||
2195 | if (!(status & UART_MSR_CTS)) { | ||
2196 | port->tty->hw_stopped = 1; | ||
2197 | if (port->type != PORT_16550A && | ||
2198 | !port->board->chip_flag) { | ||
2199 | port->IER &= ~UART_IER_THRI; | ||
2200 | outb(port->IER, port->ioaddr + | ||
2201 | UART_IER); | ||
2202 | } | ||
2203 | } | ||
2204 | } | 2458 | } |
2205 | } | ||
2206 | } | ||
2207 | |||
2208 | static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_port *port) | ||
2209 | { | ||
2210 | DECLARE_WAITQUEUE(wait, current); | ||
2211 | int retval; | ||
2212 | int do_clocal = 0; | ||
2213 | unsigned long flags; | ||
2214 | 2459 | ||
2215 | /* | 2460 | if (i == MXSER_BOARDS) |
2216 | * If non-blocking mode is set, or the port is not enabled, | 2461 | goto irq_stop; |
2217 | * then make the check up front and then exit. | 2462 | if (brd == NULL) |
2218 | */ | 2463 | goto irq_stop; |
2219 | if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { | 2464 | max = mxser_numports[brd->board_type - 1]; |
2220 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
2221 | return 0; | ||
2222 | } | ||
2223 | |||
2224 | if (tty->termios->c_cflag & CLOCAL) | ||
2225 | do_clocal = 1; | ||
2226 | |||
2227 | /* | ||
2228 | * Block waiting for the carrier detect and the line to become | ||
2229 | * free (i.e., not in use by the callout). While we are in | ||
2230 | * this loop, port->count is dropped by one, so that | ||
2231 | * mxser_close() knows when to free things. We restore it upon | ||
2232 | * exit, either normal or abnormal. | ||
2233 | */ | ||
2234 | retval = 0; | ||
2235 | add_wait_queue(&port->open_wait, &wait); | ||
2236 | |||
2237 | spin_lock_irqsave(&port->slock, flags); | ||
2238 | if (!tty_hung_up_p(filp)) | ||
2239 | port->count--; | ||
2240 | spin_unlock_irqrestore(&port->slock, flags); | ||
2241 | port->blocked_open++; | ||
2242 | while (1) { | 2465 | while (1) { |
2243 | spin_lock_irqsave(&port->slock, flags); | 2466 | irqbits = inb(brd->vector) & brd->vector_mask; |
2244 | outb(inb(port->ioaddr + UART_MCR) | | 2467 | if (irqbits == brd->vector_mask) |
2245 | UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR); | ||
2246 | spin_unlock_irqrestore(&port->slock, flags); | ||
2247 | set_current_state(TASK_INTERRUPTIBLE); | ||
2248 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { | ||
2249 | if (port->flags & ASYNC_HUP_NOTIFY) | ||
2250 | retval = -EAGAIN; | ||
2251 | else | ||
2252 | retval = -ERESTARTSYS; | ||
2253 | break; | ||
2254 | } | ||
2255 | if (!(port->flags & ASYNC_CLOSING) && | ||
2256 | (do_clocal || | ||
2257 | (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD))) | ||
2258 | break; | ||
2259 | if (signal_pending(current)) { | ||
2260 | retval = -ERESTARTSYS; | ||
2261 | break; | 2468 | break; |
2262 | } | ||
2263 | schedule(); | ||
2264 | } | ||
2265 | set_current_state(TASK_RUNNING); | ||
2266 | remove_wait_queue(&port->open_wait, &wait); | ||
2267 | if (!tty_hung_up_p(filp)) | ||
2268 | port->count++; | ||
2269 | port->blocked_open--; | ||
2270 | if (retval) | ||
2271 | return retval; | ||
2272 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
2273 | return 0; | ||
2274 | } | ||
2275 | |||
2276 | static int mxser_startup(struct mxser_port *info) | ||
2277 | { | ||
2278 | unsigned long page; | ||
2279 | unsigned long flags; | ||
2280 | |||
2281 | page = __get_free_page(GFP_KERNEL); | ||
2282 | if (!page) | ||
2283 | return -ENOMEM; | ||
2284 | |||
2285 | spin_lock_irqsave(&info->slock, flags); | ||
2286 | |||
2287 | if (info->flags & ASYNC_INITIALIZED) { | ||
2288 | free_page(page); | ||
2289 | spin_unlock_irqrestore(&info->slock, flags); | ||
2290 | return 0; | ||
2291 | } | ||
2292 | 2469 | ||
2293 | if (!info->ioaddr || !info->type) { | 2470 | handled = IRQ_HANDLED; |
2294 | if (info->tty) | 2471 | for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { |
2295 | set_bit(TTY_IO_ERROR, &info->tty->flags); | 2472 | if (irqbits == brd->vector_mask) |
2296 | free_page(page); | ||
2297 | spin_unlock_irqrestore(&info->slock, flags); | ||
2298 | return 0; | ||
2299 | } | ||
2300 | if (info->xmit_buf) | ||
2301 | free_page(page); | ||
2302 | else | ||
2303 | info->xmit_buf = (unsigned char *) page; | ||
2304 | |||
2305 | /* | ||
2306 | * Clear the FIFO buffers and disable them | ||
2307 | * (they will be reenabled in mxser_change_speed()) | ||
2308 | */ | ||
2309 | if (info->board->chip_flag) | ||
2310 | outb((UART_FCR_CLEAR_RCVR | | ||
2311 | UART_FCR_CLEAR_XMIT | | ||
2312 | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); | ||
2313 | else | ||
2314 | outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), | ||
2315 | info->ioaddr + UART_FCR); | ||
2316 | |||
2317 | /* | ||
2318 | * At this point there's no way the LSR could still be 0xFF; | ||
2319 | * if it is, then bail out, because there's likely no UART | ||
2320 | * here. | ||
2321 | */ | ||
2322 | if (inb(info->ioaddr + UART_LSR) == 0xff) { | ||
2323 | spin_unlock_irqrestore(&info->slock, flags); | ||
2324 | if (capable(CAP_SYS_ADMIN)) { | ||
2325 | if (info->tty) | ||
2326 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
2327 | return 0; | ||
2328 | } else | ||
2329 | return -ENODEV; | ||
2330 | } | ||
2331 | |||
2332 | /* | ||
2333 | * Clear the interrupt registers. | ||
2334 | */ | ||
2335 | (void) inb(info->ioaddr + UART_LSR); | ||
2336 | (void) inb(info->ioaddr + UART_RX); | ||
2337 | (void) inb(info->ioaddr + UART_IIR); | ||
2338 | (void) inb(info->ioaddr + UART_MSR); | ||
2339 | |||
2340 | /* | ||
2341 | * Now, initialize the UART | ||
2342 | */ | ||
2343 | outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
2344 | info->MCR = UART_MCR_DTR | UART_MCR_RTS; | ||
2345 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
2346 | |||
2347 | /* | ||
2348 | * Finally, enable interrupts | ||
2349 | */ | ||
2350 | info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; | ||
2351 | /* info->IER = UART_IER_RLSI | UART_IER_RDI; */ | ||
2352 | |||
2353 | /* following add by Victor Yu. 08-30-2002 */ | ||
2354 | if (info->board->chip_flag) | ||
2355 | info->IER |= MOXA_MUST_IER_EGDAI; | ||
2356 | /* above add by Victor Yu. 08-30-2002 */ | ||
2357 | outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */ | ||
2358 | |||
2359 | /* | ||
2360 | * And clear the interrupt registers again for luck. | ||
2361 | */ | ||
2362 | (void) inb(info->ioaddr + UART_LSR); | ||
2363 | (void) inb(info->ioaddr + UART_RX); | ||
2364 | (void) inb(info->ioaddr + UART_IIR); | ||
2365 | (void) inb(info->ioaddr + UART_MSR); | ||
2366 | |||
2367 | if (info->tty) | ||
2368 | clear_bit(TTY_IO_ERROR, &info->tty->flags); | ||
2369 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
2370 | |||
2371 | /* | ||
2372 | * and set the speed of the serial port | ||
2373 | */ | ||
2374 | spin_unlock_irqrestore(&info->slock, flags); | ||
2375 | mxser_change_speed(info, NULL); | ||
2376 | |||
2377 | info->flags |= ASYNC_INITIALIZED; | ||
2378 | return 0; | ||
2379 | } | ||
2380 | |||
2381 | /* | ||
2382 | * This routine will shutdown a serial port; interrupts maybe disabled, and | ||
2383 | * DTR is dropped if the hangup on close termio flag is on. | ||
2384 | */ | ||
2385 | static void mxser_shutdown(struct mxser_port *info) | ||
2386 | { | ||
2387 | unsigned long flags; | ||
2388 | |||
2389 | if (!(info->flags & ASYNC_INITIALIZED)) | ||
2390 | return; | ||
2391 | |||
2392 | spin_lock_irqsave(&info->slock, flags); | ||
2393 | |||
2394 | /* | ||
2395 | * clear delta_msr_wait queue to avoid mem leaks: we may free the irq | ||
2396 | * here so the queue might never be waken up | ||
2397 | */ | ||
2398 | wake_up_interruptible(&info->delta_msr_wait); | ||
2399 | |||
2400 | /* | ||
2401 | * Free the IRQ, if necessary | ||
2402 | */ | ||
2403 | if (info->xmit_buf) { | ||
2404 | free_page((unsigned long) info->xmit_buf); | ||
2405 | info->xmit_buf = NULL; | ||
2406 | } | ||
2407 | |||
2408 | info->IER = 0; | ||
2409 | outb(0x00, info->ioaddr + UART_IER); | ||
2410 | |||
2411 | if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) | ||
2412 | info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); | ||
2413 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
2414 | |||
2415 | /* clear Rx/Tx FIFO's */ | ||
2416 | /* following add by Victor Yu. 08-30-2002 */ | ||
2417 | if (info->board->chip_flag) | ||
2418 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | | ||
2419 | MOXA_MUST_FCR_GDA_MODE_ENABLE, | ||
2420 | info->ioaddr + UART_FCR); | ||
2421 | else | ||
2422 | /* above add by Victor Yu. 08-30-2002 */ | ||
2423 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, | ||
2424 | info->ioaddr + UART_FCR); | ||
2425 | |||
2426 | /* read data port to reset things */ | ||
2427 | (void) inb(info->ioaddr + UART_RX); | ||
2428 | |||
2429 | if (info->tty) | ||
2430 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
2431 | |||
2432 | info->flags &= ~ASYNC_INITIALIZED; | ||
2433 | |||
2434 | /* following add by Victor Yu. 09-23-2002 */ | ||
2435 | if (info->board->chip_flag) | ||
2436 | SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
2437 | /* above add by Victor Yu. 09-23-2002 */ | ||
2438 | |||
2439 | spin_unlock_irqrestore(&info->slock, flags); | ||
2440 | } | ||
2441 | |||
2442 | /* | ||
2443 | * This routine is called to set the UART divisor registers to match | ||
2444 | * the specified baud rate for a serial port. | ||
2445 | */ | ||
2446 | static int mxser_change_speed(struct mxser_port *info, | ||
2447 | struct termios *old_termios) | ||
2448 | { | ||
2449 | unsigned cflag, cval, fcr; | ||
2450 | int ret = 0; | ||
2451 | unsigned char status; | ||
2452 | long baud; | ||
2453 | unsigned long flags; | ||
2454 | |||
2455 | if (!info->tty || !info->tty->termios) | ||
2456 | return ret; | ||
2457 | cflag = info->tty->termios->c_cflag; | ||
2458 | if (!(info->ioaddr)) | ||
2459 | return ret; | ||
2460 | |||
2461 | #ifndef B921600 | ||
2462 | #define B921600 (B460800 +1) | ||
2463 | #endif | ||
2464 | if (mxser_set_baud_method[info->tty->index] == 0) { | ||
2465 | baud = tty_get_baud_rate(info->tty); | ||
2466 | mxser_set_baud(info, baud); | ||
2467 | } | ||
2468 | |||
2469 | /* byte size and parity */ | ||
2470 | switch (cflag & CSIZE) { | ||
2471 | case CS5: | ||
2472 | cval = 0x00; | ||
2473 | break; | ||
2474 | case CS6: | ||
2475 | cval = 0x01; | ||
2476 | break; | ||
2477 | case CS7: | ||
2478 | cval = 0x02; | ||
2479 | break; | ||
2480 | case CS8: | ||
2481 | cval = 0x03; | ||
2482 | break; | ||
2483 | default: | ||
2484 | cval = 0x00; | ||
2485 | break; /* too keep GCC shut... */ | ||
2486 | } | ||
2487 | if (cflag & CSTOPB) | ||
2488 | cval |= 0x04; | ||
2489 | if (cflag & PARENB) | ||
2490 | cval |= UART_LCR_PARITY; | ||
2491 | if (!(cflag & PARODD)) | ||
2492 | cval |= UART_LCR_EPAR; | ||
2493 | if (cflag & CMSPAR) | ||
2494 | cval |= UART_LCR_SPAR; | ||
2495 | |||
2496 | if ((info->type == PORT_8250) || (info->type == PORT_16450)) { | ||
2497 | if (info->board->chip_flag) { | ||
2498 | fcr = UART_FCR_ENABLE_FIFO; | ||
2499 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
2500 | SET_MOXA_MUST_FIFO_VALUE(info); | ||
2501 | } else | ||
2502 | fcr = 0; | ||
2503 | } else { | ||
2504 | fcr = UART_FCR_ENABLE_FIFO; | ||
2505 | /* following add by Victor Yu. 08-30-2002 */ | ||
2506 | if (info->board->chip_flag) { | ||
2507 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
2508 | SET_MOXA_MUST_FIFO_VALUE(info); | ||
2509 | } else { | ||
2510 | /* above add by Victor Yu. 08-30-2002 */ | ||
2511 | switch (info->rx_trigger) { | ||
2512 | case 1: | ||
2513 | fcr |= UART_FCR_TRIGGER_1; | ||
2514 | break; | ||
2515 | case 4: | ||
2516 | fcr |= UART_FCR_TRIGGER_4; | ||
2517 | break; | ||
2518 | case 8: | ||
2519 | fcr |= UART_FCR_TRIGGER_8; | ||
2520 | break; | ||
2521 | default: | ||
2522 | fcr |= UART_FCR_TRIGGER_14; | ||
2523 | break; | 2473 | break; |
2524 | } | 2474 | if (bits & irqbits) |
2525 | } | 2475 | continue; |
2526 | } | 2476 | port = &brd->ports[i]; |
2527 | 2477 | ||
2528 | /* CTS flow control flag and modem status interrupts */ | 2478 | int_cnt = 0; |
2529 | info->IER &= ~UART_IER_MSI; | 2479 | do { |
2530 | info->MCR &= ~UART_MCR_AFE; | 2480 | /* following add by Victor Yu. 09-13-2002 */ |
2531 | if (cflag & CRTSCTS) { | 2481 | iir = inb(port->ioaddr + UART_IIR); |
2532 | info->flags |= ASYNC_CTS_FLOW; | 2482 | if (iir & UART_IIR_NO_INT) |
2533 | info->IER |= UART_IER_MSI; | 2483 | break; |
2534 | if ((info->type == PORT_16550A) || (info->board->chip_flag)) { | 2484 | iir &= MOXA_MUST_IIR_MASK; |
2535 | info->MCR |= UART_MCR_AFE; | 2485 | if (!port->tty) { |
2536 | /* status = mxser_get_msr(info->ioaddr, 0, info->port); */ | 2486 | status = inb(port->ioaddr + UART_LSR); |
2537 | /* | 2487 | outb(0x27, port->ioaddr + UART_FCR); |
2538 | save_flags(flags); | 2488 | inb(port->ioaddr + UART_MSR); |
2539 | cli(); | 2489 | break; |
2540 | status = inb(baseaddr + UART_MSR); | ||
2541 | restore_flags(flags); | ||
2542 | */ | ||
2543 | /* mxser_check_modem_status(info, status); */ | ||
2544 | } else { | ||
2545 | /* status = mxser_get_msr(info->ioaddr, 0, info->port); */ | ||
2546 | /* MX_LOCK(&info->slock); */ | ||
2547 | status = inb(info->ioaddr + UART_MSR); | ||
2548 | /* MX_UNLOCK(&info->slock); */ | ||
2549 | if (info->tty->hw_stopped) { | ||
2550 | if (status & UART_MSR_CTS) { | ||
2551 | info->tty->hw_stopped = 0; | ||
2552 | if (info->type != PORT_16550A && | ||
2553 | !info->board->chip_flag) { | ||
2554 | outb(info->IER & ~UART_IER_THRI, | ||
2555 | info->ioaddr + | ||
2556 | UART_IER); | ||
2557 | info->IER |= UART_IER_THRI; | ||
2558 | outb(info->IER, info->ioaddr + | ||
2559 | UART_IER); | ||
2560 | } | ||
2561 | set_bit(MXSER_EVENT_TXLOW, &info->event); | ||
2562 | schedule_work(&info->tqueue); } | ||
2563 | } else { | ||
2564 | if (!(status & UART_MSR_CTS)) { | ||
2565 | info->tty->hw_stopped = 1; | ||
2566 | if ((info->type != PORT_16550A) && | ||
2567 | (!info->board->chip_flag)) { | ||
2568 | info->IER &= ~UART_IER_THRI; | ||
2569 | outb(info->IER, info->ioaddr + | ||
2570 | UART_IER); | ||
2571 | } | ||
2572 | } | 2490 | } |
2573 | } | 2491 | /* above add by Victor Yu. 09-13-2002 */ |
2574 | } | ||
2575 | } else { | ||
2576 | info->flags &= ~ASYNC_CTS_FLOW; | ||
2577 | } | ||
2578 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
2579 | if (cflag & CLOCAL) { | ||
2580 | info->flags &= ~ASYNC_CHECK_CD; | ||
2581 | } else { | ||
2582 | info->flags |= ASYNC_CHECK_CD; | ||
2583 | info->IER |= UART_IER_MSI; | ||
2584 | } | ||
2585 | outb(info->IER, info->ioaddr + UART_IER); | ||
2586 | |||
2587 | /* | ||
2588 | * Set up parity check flag | ||
2589 | */ | ||
2590 | info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; | ||
2591 | if (I_INPCK(info->tty)) | ||
2592 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; | ||
2593 | if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) | ||
2594 | info->read_status_mask |= UART_LSR_BI; | ||
2595 | |||
2596 | info->ignore_status_mask = 0; | ||
2597 | |||
2598 | if (I_IGNBRK(info->tty)) { | ||
2599 | info->ignore_status_mask |= UART_LSR_BI; | ||
2600 | info->read_status_mask |= UART_LSR_BI; | ||
2601 | /* | ||
2602 | * If we're ignore parity and break indicators, ignore | ||
2603 | * overruns too. (For real raw support). | ||
2604 | */ | ||
2605 | if (I_IGNPAR(info->tty)) { | ||
2606 | info->ignore_status_mask |= | ||
2607 | UART_LSR_OE | | ||
2608 | UART_LSR_PE | | ||
2609 | UART_LSR_FE; | ||
2610 | info->read_status_mask |= | ||
2611 | UART_LSR_OE | | ||
2612 | UART_LSR_PE | | ||
2613 | UART_LSR_FE; | ||
2614 | } | ||
2615 | } | ||
2616 | /* following add by Victor Yu. 09-02-2002 */ | ||
2617 | if (info->board->chip_flag) { | ||
2618 | spin_lock_irqsave(&info->slock, flags); | ||
2619 | SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); | ||
2620 | SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); | ||
2621 | if (I_IXON(info->tty)) { | ||
2622 | ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
2623 | } else { | ||
2624 | DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
2625 | } | ||
2626 | if (I_IXOFF(info->tty)) { | ||
2627 | ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
2628 | } else { | ||
2629 | DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
2630 | } | ||
2631 | /* | ||
2632 | if ( I_IXANY(info->tty) ) { | ||
2633 | info->MCR |= MOXA_MUST_MCR_XON_ANY; | ||
2634 | ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr); | ||
2635 | } else { | ||
2636 | info->MCR &= ~MOXA_MUST_MCR_XON_ANY; | ||
2637 | DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr); | ||
2638 | } | ||
2639 | */ | ||
2640 | spin_unlock_irqrestore(&info->slock, flags); | ||
2641 | } | ||
2642 | /* above add by Victor Yu. 09-02-2002 */ | ||
2643 | |||
2644 | |||
2645 | outb(fcr, info->ioaddr + UART_FCR); /* set fcr */ | ||
2646 | outb(cval, info->ioaddr + UART_LCR); | ||
2647 | |||
2648 | return ret; | ||
2649 | } | ||
2650 | |||
2651 | |||
2652 | static int mxser_set_baud(struct mxser_port *info, long newspd) | ||
2653 | { | ||
2654 | int quot = 0; | ||
2655 | unsigned char cval; | ||
2656 | int ret = 0; | ||
2657 | unsigned long flags; | ||
2658 | |||
2659 | if (!info->tty || !info->tty->termios) | ||
2660 | return ret; | ||
2661 | |||
2662 | if (!(info->ioaddr)) | ||
2663 | return ret; | ||
2664 | |||
2665 | if (newspd > info->max_baud) | ||
2666 | return 0; | ||
2667 | |||
2668 | info->realbaud = newspd; | ||
2669 | if (newspd == 134) { | ||
2670 | quot = (2 * info->baud_base / 269); | ||
2671 | } else if (newspd) { | ||
2672 | quot = info->baud_base / newspd; | ||
2673 | if (quot == 0) | ||
2674 | quot = 1; | ||
2675 | } else { | ||
2676 | quot = 0; | ||
2677 | } | ||
2678 | |||
2679 | info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); | ||
2680 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ | ||
2681 | |||
2682 | if (quot) { | ||
2683 | spin_lock_irqsave(&info->slock, flags); | ||
2684 | info->MCR |= UART_MCR_DTR; | ||
2685 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
2686 | spin_unlock_irqrestore(&info->slock, flags); | ||
2687 | } else { | ||
2688 | spin_lock_irqsave(&info->slock, flags); | ||
2689 | info->MCR &= ~UART_MCR_DTR; | ||
2690 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
2691 | spin_unlock_irqrestore(&info->slock, flags); | ||
2692 | return ret; | ||
2693 | } | ||
2694 | |||
2695 | cval = inb(info->ioaddr + UART_LCR); | ||
2696 | |||
2697 | outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */ | ||
2698 | |||
2699 | outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */ | ||
2700 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ | ||
2701 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
2702 | |||
2703 | |||
2704 | return ret; | ||
2705 | } | ||
2706 | 2492 | ||
2707 | /* | 2493 | /* following add by Victor Yu. 09-02-2002 */ |
2708 | * ------------------------------------------------------------ | 2494 | status = inb(port->ioaddr + UART_LSR); |
2709 | * friends of mxser_ioctl() | ||
2710 | * ------------------------------------------------------------ | ||
2711 | */ | ||
2712 | static int mxser_get_serial_info(struct mxser_port *info, | ||
2713 | struct serial_struct __user *retinfo) | ||
2714 | { | ||
2715 | struct serial_struct tmp; | ||
2716 | 2495 | ||
2717 | if (!retinfo) | 2496 | if (status & UART_LSR_PE) |
2718 | return -EFAULT; | 2497 | port->err_shadow |= NPPI_NOTIFY_PARITY; |
2719 | memset(&tmp, 0, sizeof(tmp)); | 2498 | if (status & UART_LSR_FE) |
2720 | tmp.type = info->type; | 2499 | port->err_shadow |= NPPI_NOTIFY_FRAMING; |
2721 | tmp.line = info->tty->index; | 2500 | if (status & UART_LSR_OE) |
2722 | tmp.port = info->ioaddr; | 2501 | port->err_shadow |= |
2723 | tmp.irq = info->board->irq; | 2502 | NPPI_NOTIFY_HW_OVERRUN; |
2724 | tmp.flags = info->flags; | 2503 | if (status & UART_LSR_BI) |
2725 | tmp.baud_base = info->baud_base; | 2504 | port->err_shadow |= NPPI_NOTIFY_BREAK; |
2726 | tmp.close_delay = info->close_delay; | ||
2727 | tmp.closing_wait = info->closing_wait; | ||
2728 | tmp.custom_divisor = info->custom_divisor; | ||
2729 | tmp.hub6 = 0; | ||
2730 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
2731 | return -EFAULT; | ||
2732 | return 0; | ||
2733 | } | ||
2734 | 2505 | ||
2735 | static int mxser_set_serial_info(struct mxser_port *info, | 2506 | if (port->board->chip_flag) { |
2736 | struct serial_struct __user *new_info) | 2507 | /* |
2737 | { | 2508 | if ( (status & 0x02) && !(status & 0x01) ) { |
2738 | struct serial_struct new_serial; | 2509 | outb(port->ioaddr+UART_FCR, 0x23); |
2739 | unsigned int flags; | 2510 | continue; |
2740 | int retval = 0; | 2511 | } |
2512 | */ | ||
2513 | if (iir == MOXA_MUST_IIR_GDA || | ||
2514 | iir == MOXA_MUST_IIR_RDA || | ||
2515 | iir == MOXA_MUST_IIR_RTO || | ||
2516 | iir == MOXA_MUST_IIR_LSR) | ||
2517 | mxser_receive_chars(port, | ||
2518 | &status); | ||
2741 | 2519 | ||
2742 | if (!new_info || !info->ioaddr) | 2520 | } else { |
2743 | return -EFAULT; | 2521 | /* above add by Victor Yu. 09-02-2002 */ |
2744 | if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) | ||
2745 | return -EFAULT; | ||
2746 | 2522 | ||
2747 | if ((new_serial.irq != info->board->irq) || | 2523 | status &= port->read_status_mask; |
2748 | (new_serial.port != info->ioaddr) || | 2524 | if (status & UART_LSR_DR) |
2749 | (new_serial.custom_divisor != info->custom_divisor) || | 2525 | mxser_receive_chars(port, |
2750 | (new_serial.baud_base != info->baud_base)) | 2526 | &status); |
2751 | return -EPERM; | 2527 | } |
2528 | msr = inb(port->ioaddr + UART_MSR); | ||
2529 | if (msr & UART_MSR_ANY_DELTA) | ||
2530 | mxser_check_modem_status(port, msr); | ||
2752 | 2531 | ||
2753 | flags = info->flags & ASYNC_SPD_MASK; | 2532 | /* following add by Victor Yu. 09-13-2002 */ |
2533 | if (port->board->chip_flag) { | ||
2534 | if (iir == 0x02 && (status & | ||
2535 | UART_LSR_THRE)) | ||
2536 | mxser_transmit_chars(port); | ||
2537 | } else { | ||
2538 | /* above add by Victor Yu. 09-13-2002 */ | ||
2754 | 2539 | ||
2755 | if (!capable(CAP_SYS_ADMIN)) { | 2540 | if (status & UART_LSR_THRE) |
2756 | if ((new_serial.baud_base != info->baud_base) || | 2541 | mxser_transmit_chars(port); |
2757 | (new_serial.close_delay != info->close_delay) || | 2542 | } |
2758 | ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) | 2543 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); |
2759 | return -EPERM; | 2544 | } |
2760 | info->flags = ((info->flags & ~ASYNC_USR_MASK) | | 2545 | if (pass_counter++ > MXSER_ISR_PASS_LIMIT) |
2761 | (new_serial.flags & ASYNC_USR_MASK)); | 2546 | break; /* Prevent infinite loops */ |
2762 | } else { | ||
2763 | /* | ||
2764 | * OK, past this point, all the error checking has been done. | ||
2765 | * At this point, we start making changes..... | ||
2766 | */ | ||
2767 | info->flags = ((info->flags & ~ASYNC_FLAGS) | | ||
2768 | (new_serial.flags & ASYNC_FLAGS)); | ||
2769 | info->close_delay = new_serial.close_delay * HZ / 100; | ||
2770 | info->closing_wait = new_serial.closing_wait * HZ / 100; | ||
2771 | info->tty->low_latency = | ||
2772 | (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
2773 | info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */ | ||
2774 | } | 2547 | } |
2775 | 2548 | ||
2776 | /* added by casper, 3/17/2000, for mouse */ | 2549 | irq_stop: |
2777 | info->type = new_serial.type; | 2550 | /* spin_unlock(&gm_lock); */ |
2778 | 2551 | return handled; | |
2779 | process_txrx_fifo(info); | ||
2780 | |||
2781 | if (info->flags & ASYNC_INITIALIZED) { | ||
2782 | if (flags != (info->flags & ASYNC_SPD_MASK)) | ||
2783 | mxser_change_speed(info, NULL); | ||
2784 | } else | ||
2785 | retval = mxser_startup(info); | ||
2786 | |||
2787 | return retval; | ||
2788 | } | 2552 | } |
2789 | 2553 | ||
2790 | /* | 2554 | static const struct tty_operations mxser_ops = { |
2791 | * mxser_get_lsr_info - get line status register info | 2555 | .open = mxser_open, |
2792 | * | 2556 | .close = mxser_close, |
2793 | * Purpose: Let user call ioctl() to get info when the UART physically | 2557 | .write = mxser_write, |
2794 | * is emptied. On bus types like RS485, the transmitter must | 2558 | .put_char = mxser_put_char, |
2795 | * release the bus after transmitting. This must be done when | 2559 | .flush_chars = mxser_flush_chars, |
2796 | * the transmit shift register is empty, not be done when the | 2560 | .write_room = mxser_write_room, |
2797 | * transmit holding register is empty. This functionality | 2561 | .chars_in_buffer = mxser_chars_in_buffer, |
2798 | * allows an RS485 driver to be written in user space. | 2562 | .flush_buffer = mxser_flush_buffer, |
2799 | */ | 2563 | .ioctl = mxser_ioctl, |
2800 | static int mxser_get_lsr_info(struct mxser_port *info, | 2564 | .throttle = mxser_throttle, |
2801 | unsigned int __user *value) | 2565 | .unthrottle = mxser_unthrottle, |
2802 | { | 2566 | .set_termios = mxser_set_termios, |
2803 | unsigned char status; | 2567 | .stop = mxser_stop, |
2804 | unsigned int result; | 2568 | .start = mxser_start, |
2805 | unsigned long flags; | 2569 | .hangup = mxser_hangup, |
2806 | 2570 | .break_ctl = mxser_rs_break, | |
2807 | spin_lock_irqsave(&info->slock, flags); | 2571 | .wait_until_sent = mxser_wait_until_sent, |
2808 | status = inb(info->ioaddr + UART_LSR); | 2572 | .tiocmget = mxser_tiocmget, |
2809 | spin_unlock_irqrestore(&info->slock, flags); | 2573 | .tiocmset = mxser_tiocmset, |
2810 | result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); | 2574 | }; |
2811 | return put_user(result, value); | ||
2812 | } | ||
2813 | 2575 | ||
2814 | /* | 2576 | /* |
2815 | * This routine sends a break character out the serial port. | 2577 | * The MOXA Smartio/Industio serial driver boot-time initialization code! |
2816 | */ | 2578 | */ |
2817 | static void mxser_send_break(struct mxser_port *info, int duration) | ||
2818 | { | ||
2819 | unsigned long flags; | ||
2820 | 2579 | ||
2821 | if (!info->ioaddr) | 2580 | static int __devinit mxser_initbrd(struct mxser_board *brd) |
2822 | return; | ||
2823 | set_current_state(TASK_INTERRUPTIBLE); | ||
2824 | spin_lock_irqsave(&info->slock, flags); | ||
2825 | outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC, | ||
2826 | info->ioaddr + UART_LCR); | ||
2827 | spin_unlock_irqrestore(&info->slock, flags); | ||
2828 | schedule_timeout(duration); | ||
2829 | spin_lock_irqsave(&info->slock, flags); | ||
2830 | outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, | ||
2831 | info->ioaddr + UART_LCR); | ||
2832 | spin_unlock_irqrestore(&info->slock, flags); | ||
2833 | } | ||
2834 | |||
2835 | static int mxser_tiocmget(struct tty_struct *tty, struct file *file) | ||
2836 | { | 2581 | { |
2837 | struct mxser_port *info = tty->driver_data; | 2582 | struct mxser_port *info; |
2838 | unsigned char control, status; | 2583 | unsigned int i; |
2839 | unsigned long flags; | 2584 | int retval; |
2840 | |||
2841 | |||
2842 | if (tty->index == MXSER_PORTS) | ||
2843 | return -ENOIOCTLCMD; | ||
2844 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
2845 | return -EIO; | ||
2846 | |||
2847 | control = info->MCR; | ||
2848 | 2585 | ||
2849 | spin_lock_irqsave(&info->slock, flags); | 2586 | printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud); |
2850 | status = inb(info->ioaddr + UART_MSR); | ||
2851 | if (status & UART_MSR_ANY_DELTA) | ||
2852 | mxser_check_modem_status(info, status); | ||
2853 | spin_unlock_irqrestore(&info->slock, flags); | ||
2854 | return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | | ||
2855 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | | ||
2856 | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | | ||
2857 | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | | ||
2858 | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | | ||
2859 | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); | ||
2860 | } | ||
2861 | 2587 | ||
2862 | static int mxser_tiocmset(struct tty_struct *tty, struct file *file, | 2588 | for (i = 0; i < brd->nports; i++) { |
2863 | unsigned int set, unsigned int clear) | 2589 | info = &brd->ports[i]; |
2864 | { | 2590 | info->board = brd; |
2865 | struct mxser_port *info = tty->driver_data; | 2591 | info->stop_rx = 0; |
2866 | unsigned long flags; | 2592 | info->ldisc_stop_rx = 0; |
2867 | 2593 | ||
2594 | /* Enhance mode enabled here */ | ||
2595 | if (brd->chip_flag != MOXA_OTHER_UART) | ||
2596 | ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr); | ||
2868 | 2597 | ||
2869 | if (tty->index == MXSER_PORTS) | 2598 | info->flags = ASYNC_SHARE_IRQ; |
2870 | return -ENOIOCTLCMD; | 2599 | info->type = brd->uart_type; |
2871 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
2872 | return -EIO; | ||
2873 | 2600 | ||
2874 | spin_lock_irqsave(&info->slock, flags); | 2601 | process_txrx_fifo(info); |
2875 | 2602 | ||
2876 | if (set & TIOCM_RTS) | 2603 | info->custom_divisor = info->baud_base * 16; |
2877 | info->MCR |= UART_MCR_RTS; | 2604 | info->close_delay = 5 * HZ / 10; |
2878 | if (set & TIOCM_DTR) | 2605 | info->closing_wait = 30 * HZ; |
2879 | info->MCR |= UART_MCR_DTR; | 2606 | INIT_WORK(&info->tqueue, mxser_do_softint, info); |
2607 | info->normal_termios = mxvar_sdriver->init_termios; | ||
2608 | init_waitqueue_head(&info->open_wait); | ||
2609 | init_waitqueue_head(&info->close_wait); | ||
2610 | init_waitqueue_head(&info->delta_msr_wait); | ||
2611 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); | ||
2612 | info->err_shadow = 0; | ||
2613 | spin_lock_init(&info->slock); | ||
2880 | 2614 | ||
2881 | if (clear & TIOCM_RTS) | 2615 | /* before set INT ISR, disable all int */ |
2882 | info->MCR &= ~UART_MCR_RTS; | 2616 | outb(inb(info->ioaddr + UART_IER) & 0xf0, |
2883 | if (clear & TIOCM_DTR) | 2617 | info->ioaddr + UART_IER); |
2884 | info->MCR &= ~UART_MCR_DTR; | 2618 | } |
2619 | /* | ||
2620 | * Allocate the IRQ if necessary | ||
2621 | */ | ||
2885 | 2622 | ||
2886 | outb(info->MCR, info->ioaddr + UART_MCR); | 2623 | retval = request_irq(brd->irq, mxser_interrupt, |
2887 | spin_unlock_irqrestore(&info->slock, flags); | 2624 | (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : |
2625 | IRQF_DISABLED, "mxser", brd); | ||
2626 | if (retval) { | ||
2627 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " | ||
2628 | "conflict with another device.\n", | ||
2629 | mxser_brdname[brd->board_type - 1], brd->irq); | ||
2630 | return retval; | ||
2631 | } | ||
2888 | return 0; | 2632 | return 0; |
2889 | } | 2633 | } |
2890 | 2634 | ||
2891 | |||
2892 | static int mxser_read_register(int, unsigned short *); | ||
2893 | static int mxser_program_mode(int); | ||
2894 | static void mxser_normal_mode(int); | ||
2895 | |||
2896 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | 2635 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) |
2897 | { | 2636 | { |
2898 | int id, i, bits; | 2637 | int id, i, bits; |
@@ -2988,111 +2727,303 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | |||
2988 | return brd->nports; | 2727 | return brd->nports; |
2989 | } | 2728 | } |
2990 | 2729 | ||
2991 | #define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ | 2730 | static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd, |
2992 | #define CHIP_DO 0x02 /* Serial Data Output in Eprom */ | 2731 | struct pci_dev *pdev) |
2993 | #define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ | ||
2994 | #define CHIP_DI 0x08 /* Serial Data Input in Eprom */ | ||
2995 | #define EN_CCMD 0x000 /* Chip's command register */ | ||
2996 | #define EN0_RSARLO 0x008 /* Remote start address reg 0 */ | ||
2997 | #define EN0_RSARHI 0x009 /* Remote start address reg 1 */ | ||
2998 | #define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ | ||
2999 | #define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ | ||
3000 | #define EN0_DCFG 0x00E /* Data configuration reg WR */ | ||
3001 | #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ | ||
3002 | #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ | ||
3003 | #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ | ||
3004 | static int mxser_read_register(int port, unsigned short *regs) | ||
3005 | { | 2732 | { |
3006 | int i, k, value, id; | 2733 | unsigned int i, j; |
3007 | unsigned int j; | 2734 | unsigned long ioaddress; |
2735 | int retval; | ||
3008 | 2736 | ||
3009 | id = mxser_program_mode(port); | 2737 | /* io address */ |
3010 | if (id < 0) | 2738 | brd->board_type = board_type; |
3011 | return id; | 2739 | brd->nports = mxser_numports[board_type - 1]; |
3012 | for (i = 0; i < 14; i++) { | 2740 | ioaddress = pci_resource_start(pdev, 2); |
3013 | k = (i & 0x3F) | 0x180; | 2741 | retval = pci_request_region(pdev, 2, "mxser(IO)"); |
3014 | for (j = 0x100; j > 0; j >>= 1) { | 2742 | if (retval) |
3015 | outb(CHIP_CS, port); | 2743 | goto err; |
3016 | if (k & j) { | 2744 | |
3017 | outb(CHIP_CS | CHIP_DO, port); | 2745 | for (i = 0; i < brd->nports; i++) |
3018 | outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ | 2746 | brd->ports[i].ioaddr = ioaddress + 8 * i; |
3019 | } else { | 2747 | |
3020 | outb(CHIP_CS, port); | 2748 | /* vector */ |
3021 | outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ | 2749 | ioaddress = pci_resource_start(pdev, 3); |
2750 | retval = pci_request_region(pdev, 3, "mxser(vector)"); | ||
2751 | if (retval) | ||
2752 | goto err_relio; | ||
2753 | brd->vector = ioaddress; | ||
2754 | |||
2755 | /* irq */ | ||
2756 | brd->irq = pdev->irq; | ||
2757 | |||
2758 | brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr); | ||
2759 | brd->uart_type = PORT_16550A; | ||
2760 | brd->vector_mask = 0; | ||
2761 | |||
2762 | for (i = 0; i < brd->nports; i++) { | ||
2763 | for (j = 0; j < UART_INFO_NUM; j++) { | ||
2764 | if (Gpci_uart_info[j].type == brd->chip_flag) { | ||
2765 | brd->ports[i].max_baud = | ||
2766 | Gpci_uart_info[j].max_baud; | ||
2767 | |||
2768 | /* exception....CP-102 */ | ||
2769 | if (board_type == MXSER_BOARD_CP102) | ||
2770 | brd->ports[i].max_baud = 921600; | ||
2771 | break; | ||
3022 | } | 2772 | } |
3023 | } | 2773 | } |
3024 | (void)inb(port); | 2774 | } |
3025 | value = 0; | 2775 | |
3026 | for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { | 2776 | if (brd->chip_flag == MOXA_MUST_MU860_HWID) { |
3027 | outb(CHIP_CS, port); | 2777 | for (i = 0; i < brd->nports; i++) { |
3028 | outb(CHIP_CS | CHIP_SK, port); | 2778 | if (i < 4) |
3029 | if (inb(port) & CHIP_DI) | 2779 | brd->ports[i].opmode_ioaddr = ioaddress + 4; |
3030 | value |= j; | 2780 | else |
2781 | brd->ports[i].opmode_ioaddr = ioaddress + 0x0c; | ||
3031 | } | 2782 | } |
3032 | regs[i] = value; | 2783 | outb(0, ioaddress + 4); /* default set to RS232 mode */ |
3033 | outb(0, port); | 2784 | outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ |
3034 | } | 2785 | } |
3035 | mxser_normal_mode(port); | 2786 | |
3036 | return id; | 2787 | for (i = 0; i < brd->nports; i++) { |
2788 | brd->vector_mask |= (1 << i); | ||
2789 | brd->ports[i].baud_base = 921600; | ||
2790 | } | ||
2791 | return 0; | ||
2792 | err_relio: | ||
2793 | pci_release_region(pdev, 2); | ||
2794 | err: | ||
2795 | return retval; | ||
3037 | } | 2796 | } |
3038 | 2797 | ||
3039 | static int mxser_program_mode(int port) | 2798 | static int __init mxser_module_init(void) |
3040 | { | 2799 | { |
3041 | int id, i, j, n; | 2800 | struct pci_dev *pdev = NULL; |
3042 | /* unsigned long flags; */ | 2801 | struct mxser_board *brd; |
2802 | unsigned int i, m; | ||
2803 | int retval, b, n; | ||
3043 | 2804 | ||
3044 | spin_lock(&gm_lock); | 2805 | pr_debug("Loading module mxser ...\n"); |
3045 | outb(0, port); | ||
3046 | outb(0, port); | ||
3047 | outb(0, port); | ||
3048 | (void)inb(port); | ||
3049 | (void)inb(port); | ||
3050 | outb(0, port); | ||
3051 | (void)inb(port); | ||
3052 | /* restore_flags(flags); */ | ||
3053 | spin_unlock(&gm_lock); | ||
3054 | 2806 | ||
3055 | id = inb(port + 1) & 0x1F; | 2807 | mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); |
3056 | if ((id != C168_ASIC_ID) && | 2808 | if (!mxvar_sdriver) |
3057 | (id != C104_ASIC_ID) && | 2809 | return -ENOMEM; |
3058 | (id != C102_ASIC_ID) && | 2810 | spin_lock_init(&gm_lock); |
3059 | (id != CI132_ASIC_ID) && | 2811 | |
3060 | (id != CI134_ASIC_ID) && | 2812 | for (i = 0; i < MXSER_BOARDS; i++) |
3061 | (id != CI104J_ASIC_ID)) | 2813 | mxser_boards[i].board_type = -1; |
3062 | return -1; | 2814 | |
3063 | for (i = 0, j = 0; i < 4; i++) { | 2815 | printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", |
3064 | n = inb(port + 2); | 2816 | MXSER_VERSION); |
3065 | if (n == 'M') { | 2817 | |
3066 | j = 1; | 2818 | /* Initialize the tty_driver structure */ |
3067 | } else if ((j == 1) && (n == 1)) { | 2819 | mxvar_sdriver->magic = TTY_DRIVER_MAGIC; |
3068 | j = 2; | 2820 | mxvar_sdriver->name = "ttyM"; |
3069 | break; | 2821 | mxvar_sdriver->major = ttymajor; |
3070 | } else | 2822 | mxvar_sdriver->minor_start = 0; |
3071 | j = 0; | 2823 | mxvar_sdriver->num = MXSER_PORTS + 1; |
2824 | mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
2825 | mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; | ||
2826 | mxvar_sdriver->init_termios = tty_std_termios; | ||
2827 | mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; | ||
2828 | mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW; | ||
2829 | tty_set_operations(mxvar_sdriver, &mxser_ops); | ||
2830 | mxvar_sdriver->ttys = mxvar_tty; | ||
2831 | mxvar_sdriver->termios = mxvar_termios; | ||
2832 | mxvar_sdriver->termios_locked = mxvar_termios_locked; | ||
2833 | |||
2834 | mxvar_diagflag = 0; | ||
2835 | |||
2836 | m = 0; | ||
2837 | /* Start finding ISA boards here */ | ||
2838 | for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { | ||
2839 | int cap; | ||
2840 | |||
2841 | if (!(cap = mxserBoardCAP[b])) | ||
2842 | continue; | ||
2843 | |||
2844 | brd = &mxser_boards[m]; | ||
2845 | retval = mxser_get_ISA_conf(cap, brd); | ||
2846 | |||
2847 | if (retval != 0) | ||
2848 | printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", | ||
2849 | mxser_brdname[brd->board_type - 1], ioaddr[b]); | ||
2850 | |||
2851 | if (retval <= 0) { | ||
2852 | if (retval == MXSER_ERR_IRQ) | ||
2853 | printk(KERN_ERR "Invalid interrupt number, " | ||
2854 | "board not configured\n"); | ||
2855 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
2856 | printk(KERN_ERR "Invalid interrupt number, " | ||
2857 | "board not configured\n"); | ||
2858 | else if (retval == MXSER_ERR_VECTOR) | ||
2859 | printk(KERN_ERR "Invalid interrupt vector, " | ||
2860 | "board not configured\n"); | ||
2861 | else if (retval == MXSER_ERR_IOADDR) | ||
2862 | printk(KERN_ERR "Invalid I/O address, " | ||
2863 | "board not configured\n"); | ||
2864 | |||
2865 | continue; | ||
2866 | } | ||
2867 | |||
2868 | brd->pdev = NULL; | ||
2869 | |||
2870 | /* mxser_initbrd will hook ISR. */ | ||
2871 | if (mxser_initbrd(brd) < 0) | ||
2872 | continue; | ||
2873 | |||
2874 | m++; | ||
3072 | } | 2875 | } |
3073 | if (j != 2) | 2876 | |
3074 | id = -2; | 2877 | /* Start finding ISA boards from module arg */ |
3075 | return id; | 2878 | for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) { |
2879 | unsigned long cap; | ||
2880 | |||
2881 | if (!(cap = ioaddr[b])) | ||
2882 | continue; | ||
2883 | |||
2884 | brd = &mxser_boards[m]; | ||
2885 | retval = mxser_get_ISA_conf(cap, &mxser_boards[m]); | ||
2886 | |||
2887 | if (retval != 0) | ||
2888 | printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", | ||
2889 | mxser_brdname[brd->board_type - 1], ioaddr[b]); | ||
2890 | |||
2891 | if (retval <= 0) { | ||
2892 | if (retval == MXSER_ERR_IRQ) | ||
2893 | printk(KERN_ERR "Invalid interrupt number, " | ||
2894 | "board not configured\n"); | ||
2895 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
2896 | printk(KERN_ERR "Invalid interrupt number, " | ||
2897 | "board not configured\n"); | ||
2898 | else if (retval == MXSER_ERR_VECTOR) | ||
2899 | printk(KERN_ERR "Invalid interrupt vector, " | ||
2900 | "board not configured\n"); | ||
2901 | else if (retval == MXSER_ERR_IOADDR) | ||
2902 | printk(KERN_ERR "Invalid I/O address, " | ||
2903 | "board not configured\n"); | ||
2904 | |||
2905 | continue; | ||
2906 | } | ||
2907 | |||
2908 | brd->pdev = NULL; | ||
2909 | /* mxser_initbrd will hook ISR. */ | ||
2910 | if (mxser_initbrd(brd) < 0) | ||
2911 | continue; | ||
2912 | |||
2913 | m++; | ||
2914 | } | ||
2915 | |||
2916 | /* start finding PCI board here */ | ||
2917 | n = ARRAY_SIZE(mxser_pcibrds) - 1; | ||
2918 | b = 0; | ||
2919 | while (b < n) { | ||
2920 | pdev = pci_get_device(mxser_pcibrds[b].vendor, | ||
2921 | mxser_pcibrds[b].device, pdev); | ||
2922 | if (pdev == NULL) { | ||
2923 | b++; | ||
2924 | continue; | ||
2925 | } | ||
2926 | printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", | ||
2927 | mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], | ||
2928 | pdev->bus->number, PCI_SLOT(pdev->devfn)); | ||
2929 | if (m >= MXSER_BOARDS) | ||
2930 | printk(KERN_ERR | ||
2931 | "Too many Smartio/Industio family boards find " | ||
2932 | "(maximum %d), board not configured\n", | ||
2933 | MXSER_BOARDS); | ||
2934 | else { | ||
2935 | if (pci_enable_device(pdev)) { | ||
2936 | printk(KERN_ERR "Moxa SmartI/O PCI enable " | ||
2937 | "fail !\n"); | ||
2938 | continue; | ||
2939 | } | ||
2940 | brd = &mxser_boards[m]; | ||
2941 | brd->pdev = pdev; | ||
2942 | retval = mxser_get_PCI_conf( | ||
2943 | (int)mxser_pcibrds[b].driver_data, | ||
2944 | brd, pdev); | ||
2945 | if (retval < 0) { | ||
2946 | if (retval == MXSER_ERR_IRQ) | ||
2947 | printk(KERN_ERR | ||
2948 | "Invalid interrupt number, " | ||
2949 | "board not configured\n"); | ||
2950 | else if (retval == MXSER_ERR_IRQ_CONFLIT) | ||
2951 | printk(KERN_ERR | ||
2952 | "Invalid interrupt number, " | ||
2953 | "board not configured\n"); | ||
2954 | else if (retval == MXSER_ERR_VECTOR) | ||
2955 | printk(KERN_ERR | ||
2956 | "Invalid interrupt vector, " | ||
2957 | "board not configured\n"); | ||
2958 | else if (retval == MXSER_ERR_IOADDR) | ||
2959 | printk(KERN_ERR | ||
2960 | "Invalid I/O address, " | ||
2961 | "board not configured\n"); | ||
2962 | continue; | ||
2963 | } | ||
2964 | /* mxser_initbrd will hook ISR. */ | ||
2965 | if (mxser_initbrd(brd) < 0) | ||
2966 | continue; | ||
2967 | m++; | ||
2968 | /* Keep an extra reference if we succeeded. It will | ||
2969 | be returned at unload time */ | ||
2970 | pci_dev_get(pdev); | ||
2971 | } | ||
2972 | } | ||
2973 | |||
2974 | retval = tty_register_driver(mxvar_sdriver); | ||
2975 | if (retval) { | ||
2976 | printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family" | ||
2977 | " driver !\n"); | ||
2978 | put_tty_driver(mxvar_sdriver); | ||
2979 | |||
2980 | for (i = 0; i < MXSER_BOARDS; i++) { | ||
2981 | if (mxser_boards[i].board_type == -1) | ||
2982 | continue; | ||
2983 | else { | ||
2984 | free_irq(mxser_boards[i].irq, &mxser_boards[i]); | ||
2985 | /* todo: release io, vector */ | ||
2986 | } | ||
2987 | } | ||
2988 | return retval; | ||
2989 | } | ||
2990 | |||
2991 | pr_debug("Done.\n"); | ||
2992 | |||
2993 | return retval; | ||
3076 | } | 2994 | } |
3077 | 2995 | ||
3078 | static void mxser_normal_mode(int port) | 2996 | static void __exit mxser_module_exit(void) |
3079 | { | 2997 | { |
3080 | int i, n; | 2998 | int i, err; |
3081 | 2999 | ||
3082 | outb(0xA5, port + 1); | 3000 | pr_debug("Unloading module mxser ...\n"); |
3083 | outb(0x80, port + 3); | 3001 | |
3084 | outb(12, port + 0); /* 9600 bps */ | 3002 | err = tty_unregister_driver(mxvar_sdriver); |
3085 | outb(0, port + 1); | 3003 | if (!err) |
3086 | outb(0x03, port + 3); /* 8 data bits */ | 3004 | put_tty_driver(mxvar_sdriver); |
3087 | outb(0x13, port + 4); /* loop back mode */ | 3005 | else |
3088 | for (i = 0; i < 16; i++) { | 3006 | printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n"); |
3089 | n = inb(port + 5); | 3007 | |
3090 | if ((n & 0x61) == 0x60) | 3008 | for (i = 0; i < MXSER_BOARDS; i++) { |
3091 | break; | 3009 | struct pci_dev *pdev; |
3092 | if ((n & 1) == 1) | 3010 | |
3093 | (void)inb(port); | 3011 | if (mxser_boards[i].board_type == -1) |
3012 | continue; | ||
3013 | else { | ||
3014 | pdev = mxser_boards[i].pdev; | ||
3015 | free_irq(mxser_boards[i].irq, &mxser_boards[i]); | ||
3016 | if (pdev != NULL) { /* PCI */ | ||
3017 | pci_release_region(pdev, 2); | ||
3018 | pci_release_region(pdev, 3); | ||
3019 | pci_dev_put(pdev); | ||
3020 | } else { | ||
3021 | release_region(mxser_boards[i].ports[0].ioaddr, 8 * mxser_boards[i].nports); | ||
3022 | release_region(mxser_boards[i].vector, 1); | ||
3023 | } | ||
3024 | } | ||
3094 | } | 3025 | } |
3095 | outb(0x00, port + 4); | 3026 | pr_debug("Done.\n"); |
3096 | } | 3027 | } |
3097 | 3028 | ||
3098 | module_init(mxser_module_init); | 3029 | module_init(mxser_module_init); |