diff options
Diffstat (limited to 'drivers/char/isicom.c')
-rw-r--r-- | drivers/char/isicom.c | 350 |
1 files changed, 123 insertions, 227 deletions
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 913be23e0a24..5a747e685993 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -172,12 +172,14 @@ static struct pci_driver isicom_driver = { | |||
172 | static int prev_card = 3; /* start servicing isi_card[0] */ | 172 | static int prev_card = 3; /* start servicing isi_card[0] */ |
173 | static struct tty_driver *isicom_normal; | 173 | static struct tty_driver *isicom_normal; |
174 | 174 | ||
175 | static struct timer_list tx; | 175 | static DECLARE_COMPLETION(isi_timerdone); |
176 | static char re_schedule = 1; | 176 | static char re_schedule = 1; |
177 | 177 | ||
178 | static void isicom_tx(unsigned long _data); | 178 | static void isicom_tx(unsigned long _data); |
179 | static void isicom_start(struct tty_struct *tty); | 179 | static void isicom_start(struct tty_struct *tty); |
180 | 180 | ||
181 | static DEFINE_TIMER(tx, isicom_tx, 0, 0); | ||
182 | |||
181 | /* baud index mappings from linux defns to isi */ | 183 | /* baud index mappings from linux defns to isi */ |
182 | 184 | ||
183 | static signed char linuxb_to_isib[] = { | 185 | static signed char linuxb_to_isib[] = { |
@@ -193,9 +195,9 @@ struct isi_board { | |||
193 | unsigned short shift_count; | 195 | unsigned short shift_count; |
194 | struct isi_port * ports; | 196 | struct isi_port * ports; |
195 | signed char count; | 197 | signed char count; |
196 | unsigned char isa; | ||
197 | spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ | 198 | spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ |
198 | unsigned long flags; | 199 | unsigned long flags; |
200 | unsigned int index; | ||
199 | }; | 201 | }; |
200 | 202 | ||
201 | struct isi_port { | 203 | struct isi_port { |
@@ -514,25 +516,19 @@ static void isicom_tx(unsigned long _data) | |||
514 | /* schedule another tx for hopefully in about 10ms */ | 516 | /* schedule another tx for hopefully in about 10ms */ |
515 | sched_again: | 517 | sched_again: |
516 | if (!re_schedule) { | 518 | if (!re_schedule) { |
517 | re_schedule = 2; | 519 | complete(&isi_timerdone); |
518 | return; | 520 | return; |
519 | } | 521 | } |
520 | 522 | ||
521 | init_timer(&tx); | 523 | mod_timer(&tx, jiffies + msecs_to_jiffies(10)); |
522 | tx.expires = jiffies + HZ/100; | ||
523 | tx.data = 0; | ||
524 | tx.function = isicom_tx; | ||
525 | add_timer(&tx); | ||
526 | |||
527 | return; | ||
528 | } | 524 | } |
529 | 525 | ||
530 | /* Interrupt handlers */ | 526 | /* Interrupt handlers */ |
531 | 527 | ||
532 | 528 | ||
533 | static void isicom_bottomhalf(void *data) | 529 | static void isicom_bottomhalf(struct work_struct *work) |
534 | { | 530 | { |
535 | struct isi_port *port = (struct isi_port *) data; | 531 | struct isi_port *port = container_of(work, struct isi_port, bh_tqueue); |
536 | struct tty_struct *tty = port->tty; | 532 | struct tty_struct *tty = port->tty; |
537 | 533 | ||
538 | if (!tty) | 534 | if (!tty) |
@@ -546,7 +542,7 @@ static void isicom_bottomhalf(void *data) | |||
546 | * Main interrupt handler routine | 542 | * Main interrupt handler routine |
547 | */ | 543 | */ |
548 | 544 | ||
549 | static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 545 | static irqreturn_t isicom_interrupt(int irq, void *dev_id) |
550 | { | 546 | { |
551 | struct isi_board *card = dev_id; | 547 | struct isi_board *card = dev_id; |
552 | struct isi_port *port; | 548 | struct isi_port *port; |
@@ -562,14 +558,12 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
562 | base = card->base; | 558 | base = card->base; |
563 | spin_lock(&card->card_lock); | 559 | spin_lock(&card->card_lock); |
564 | 560 | ||
565 | if (card->isa == NO) { | 561 | /* |
566 | /* | 562 | * disable any interrupts from the PCI card and lower the |
567 | * disable any interrupts from the PCI card and lower the | 563 | * interrupt line |
568 | * interrupt line | 564 | */ |
569 | */ | 565 | outw(0x8000, base+0x04); |
570 | outw(0x8000, base+0x04); | 566 | ClearInterrupt(base); |
571 | ClearInterrupt(base); | ||
572 | } | ||
573 | 567 | ||
574 | inw(base); /* get the dummy word out */ | 568 | inw(base); /* get the dummy word out */ |
575 | header = inw(base); | 569 | header = inw(base); |
@@ -579,19 +573,13 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
579 | if (channel + 1 > card->port_count) { | 573 | if (channel + 1 > card->port_count) { |
580 | printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): " | 574 | printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): " |
581 | "%d(channel) > port_count.\n", base, channel+1); | 575 | "%d(channel) > port_count.\n", base, channel+1); |
582 | if (card->isa) | 576 | outw(0x0000, base+0x04); /* enable interrupts */ |
583 | ClearInterrupt(base); | ||
584 | else | ||
585 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
586 | spin_unlock(&card->card_lock); | 577 | spin_unlock(&card->card_lock); |
587 | return IRQ_HANDLED; | 578 | return IRQ_HANDLED; |
588 | } | 579 | } |
589 | port = card->ports + channel; | 580 | port = card->ports + channel; |
590 | if (!(port->flags & ASYNC_INITIALIZED)) { | 581 | if (!(port->flags & ASYNC_INITIALIZED)) { |
591 | if (card->isa) | 582 | outw(0x0000, base+0x04); /* enable interrupts */ |
592 | ClearInterrupt(base); | ||
593 | else | ||
594 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
595 | return IRQ_HANDLED; | 583 | return IRQ_HANDLED; |
596 | } | 584 | } |
597 | 585 | ||
@@ -604,10 +592,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
604 | } | 592 | } |
605 | if (byte_count & 0x01) | 593 | if (byte_count & 0x01) |
606 | inw(base); | 594 | inw(base); |
607 | if (card->isa == YES) | 595 | outw(0x0000, base+0x04); /* enable interrupts */ |
608 | ClearInterrupt(base); | ||
609 | else | ||
610 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
611 | spin_unlock(&card->card_lock); | 596 | spin_unlock(&card->card_lock); |
612 | return IRQ_HANDLED; | 597 | return IRQ_HANDLED; |
613 | } | 598 | } |
@@ -708,10 +693,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
708 | } | 693 | } |
709 | tty_flip_buffer_push(tty); | 694 | tty_flip_buffer_push(tty); |
710 | } | 695 | } |
711 | if (card->isa == YES) | 696 | outw(0x0000, base+0x04); /* enable interrupts */ |
712 | ClearInterrupt(base); | ||
713 | else | ||
714 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
715 | 697 | ||
716 | return IRQ_HANDLED; | 698 | return IRQ_HANDLED; |
717 | } | 699 | } |
@@ -964,8 +946,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) | |||
964 | { | 946 | { |
965 | struct isi_port *port; | 947 | struct isi_port *port; |
966 | struct isi_board *card; | 948 | struct isi_board *card; |
967 | unsigned int line, board; | 949 | unsigned int board; |
968 | int error; | 950 | int error, line; |
969 | 951 | ||
970 | line = tty->index; | 952 | line = tty->index; |
971 | if (line < 0 || line > PORT_COUNT-1) | 953 | if (line < 0 || line > PORT_COUNT-1) |
@@ -1062,11 +1044,12 @@ static void isicom_shutdown_port(struct isi_port *port) | |||
1062 | static void isicom_close(struct tty_struct *tty, struct file *filp) | 1044 | static void isicom_close(struct tty_struct *tty, struct file *filp) |
1063 | { | 1045 | { |
1064 | struct isi_port *port = tty->driver_data; | 1046 | struct isi_port *port = tty->driver_data; |
1065 | struct isi_board *card = port->card; | 1047 | struct isi_board *card; |
1066 | unsigned long flags; | 1048 | unsigned long flags; |
1067 | 1049 | ||
1068 | if (!port) | 1050 | if (!port) |
1069 | return; | 1051 | return; |
1052 | card = port->card; | ||
1070 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) | 1053 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) |
1071 | return; | 1054 | return; |
1072 | 1055 | ||
@@ -1398,7 +1381,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, | |||
1398 | 1381 | ||
1399 | /* set_termios et all */ | 1382 | /* set_termios et all */ |
1400 | static void isicom_set_termios(struct tty_struct *tty, | 1383 | static void isicom_set_termios(struct tty_struct *tty, |
1401 | struct termios *old_termios) | 1384 | struct ktermios *old_termios) |
1402 | { | 1385 | { |
1403 | struct isi_port *port = tty->driver_data; | 1386 | struct isi_port *port = tty->driver_data; |
1404 | 1387 | ||
@@ -1473,9 +1456,9 @@ static void isicom_start(struct tty_struct *tty) | |||
1473 | } | 1456 | } |
1474 | 1457 | ||
1475 | /* hangup et all */ | 1458 | /* hangup et all */ |
1476 | static void do_isicom_hangup(void *data) | 1459 | static void do_isicom_hangup(struct work_struct *work) |
1477 | { | 1460 | { |
1478 | struct isi_port *port = data; | 1461 | struct isi_port *port = container_of(work, struct isi_port, hangup_tq); |
1479 | struct tty_struct *tty; | 1462 | struct tty_struct *tty; |
1480 | 1463 | ||
1481 | tty = port->tty; | 1464 | tty = port->tty; |
@@ -1519,38 +1502,7 @@ static void isicom_flush_buffer(struct tty_struct *tty) | |||
1519 | * Driver init and deinit functions | 1502 | * Driver init and deinit functions |
1520 | */ | 1503 | */ |
1521 | 1504 | ||
1522 | static int __devinit isicom_register_ioregion(struct pci_dev *pdev, | 1505 | static const struct tty_operations isicom_ops = { |
1523 | const unsigned int index) | ||
1524 | { | ||
1525 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1526 | |||
1527 | if (!board->base) | ||
1528 | return -EINVAL; | ||
1529 | |||
1530 | if (!request_region(board->base, 16, ISICOM_NAME)) { | ||
1531 | dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d " | ||
1532 | "will be disabled.\n", board->base, board->base + 15, | ||
1533 | index + 1); | ||
1534 | return -EBUSY; | ||
1535 | } | ||
1536 | |||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static void isicom_unregister_ioregion(struct pci_dev *pdev) | ||
1541 | { | ||
1542 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1543 | |||
1544 | if (!board->base) | ||
1545 | return; | ||
1546 | |||
1547 | release_region(board->base, 16); | ||
1548 | dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx released.\n", | ||
1549 | board->base, board->base + 15); | ||
1550 | board->base = 0; | ||
1551 | } | ||
1552 | |||
1553 | static struct tty_operations isicom_ops = { | ||
1554 | .open = isicom_open, | 1506 | .open = isicom_open, |
1555 | .close = isicom_close, | 1507 | .close = isicom_close, |
1556 | .write = isicom_write, | 1508 | .write = isicom_write, |
@@ -1570,70 +1522,6 @@ static struct tty_operations isicom_ops = { | |||
1570 | .tiocmset = isicom_tiocmset, | 1522 | .tiocmset = isicom_tiocmset, |
1571 | }; | 1523 | }; |
1572 | 1524 | ||
1573 | static int __devinit isicom_register_tty_driver(void) | ||
1574 | { | ||
1575 | int error = -ENOMEM; | ||
1576 | |||
1577 | /* tty driver structure initialization */ | ||
1578 | isicom_normal = alloc_tty_driver(PORT_COUNT); | ||
1579 | if (!isicom_normal) | ||
1580 | goto end; | ||
1581 | |||
1582 | isicom_normal->owner = THIS_MODULE; | ||
1583 | isicom_normal->name = "ttyM"; | ||
1584 | isicom_normal->major = ISICOM_NMAJOR; | ||
1585 | isicom_normal->minor_start = 0; | ||
1586 | isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; | ||
1587 | isicom_normal->subtype = SERIAL_TYPE_NORMAL; | ||
1588 | isicom_normal->init_termios = tty_std_termios; | ||
1589 | isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | | ||
1590 | CLOCAL; | ||
1591 | isicom_normal->flags = TTY_DRIVER_REAL_RAW; | ||
1592 | tty_set_operations(isicom_normal, &isicom_ops); | ||
1593 | |||
1594 | if ((error = tty_register_driver(isicom_normal))) { | ||
1595 | pr_dbg("Couldn't register the dialin driver, error=%d\n", | ||
1596 | error); | ||
1597 | put_tty_driver(isicom_normal); | ||
1598 | } | ||
1599 | end: | ||
1600 | return error; | ||
1601 | } | ||
1602 | |||
1603 | static void isicom_unregister_tty_driver(void) | ||
1604 | { | ||
1605 | int error; | ||
1606 | |||
1607 | if ((error = tty_unregister_driver(isicom_normal))) | ||
1608 | pr_dbg("couldn't unregister normal driver, error=%d.\n", error); | ||
1609 | |||
1610 | put_tty_driver(isicom_normal); | ||
1611 | } | ||
1612 | |||
1613 | static int __devinit isicom_register_isr(struct pci_dev *pdev, | ||
1614 | const unsigned int index) | ||
1615 | { | ||
1616 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1617 | unsigned long irqflags = IRQF_DISABLED; | ||
1618 | int retval = -EINVAL; | ||
1619 | |||
1620 | if (!board->base) | ||
1621 | goto end; | ||
1622 | |||
1623 | if (board->isa == NO) | ||
1624 | irqflags |= IRQF_SHARED; | ||
1625 | |||
1626 | retval = request_irq(board->irq, isicom_interrupt, irqflags, | ||
1627 | ISICOM_NAME, board); | ||
1628 | if (retval < 0) | ||
1629 | dev_warn(&pdev->dev, "Could not install handler at Irq %d. " | ||
1630 | "Card%d will be disabled.\n", board->irq, index + 1); | ||
1631 | else | ||
1632 | retval = 0; | ||
1633 | end: | ||
1634 | return retval; | ||
1635 | } | ||
1636 | |||
1637 | static int __devinit reset_card(struct pci_dev *pdev, | 1525 | static int __devinit reset_card(struct pci_dev *pdev, |
1638 | const unsigned int card, unsigned int *signature) | 1526 | const unsigned int card, unsigned int *signature) |
1639 | { | 1527 | { |
@@ -1655,36 +1543,23 @@ static int __devinit reset_card(struct pci_dev *pdev, | |||
1655 | 1543 | ||
1656 | *signature = inw(base + 0x4) & 0xff; | 1544 | *signature = inw(base + 0x4) & 0xff; |
1657 | 1545 | ||
1658 | if (board->isa == YES) { | 1546 | portcount = inw(base + 0x2); |
1659 | if (!(inw(base + 0xe) & 0x1) || (inw(base + 0x2))) { | 1547 | if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) && |
1660 | dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n", | 1548 | (portcount != 4) && (portcount != 8))) { |
1661 | inw(base + 0x2), inw(base + 0xe)); | 1549 | dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n", |
1662 | dev_err(&pdev->dev, "ISILoad:ISA Card%d reset failure " | 1550 | inw(base + 0x2), inw(base + 0xe)); |
1663 | "(Possible bad I/O Port Address 0x%lx).\n", | 1551 | dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure " |
1664 | card + 1, base); | 1552 | "(Possible bad I/O Port Address 0x%lx).\n", |
1665 | retval = -EIO; | 1553 | card + 1, base); |
1666 | goto end; | 1554 | retval = -EIO; |
1667 | } | 1555 | goto end; |
1668 | } else { | ||
1669 | portcount = inw(base + 0x2); | ||
1670 | if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) && | ||
1671 | (portcount != 4) && (portcount != 8))) { | ||
1672 | dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n", | ||
1673 | inw(base + 0x2), inw(base + 0xe)); | ||
1674 | dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure " | ||
1675 | "(Possible bad I/O Port Address 0x%lx).\n", | ||
1676 | card + 1, base); | ||
1677 | retval = -EIO; | ||
1678 | goto end; | ||
1679 | } | ||
1680 | } | 1556 | } |
1681 | 1557 | ||
1682 | switch (*signature) { | 1558 | switch (*signature) { |
1683 | case 0xa5: | 1559 | case 0xa5: |
1684 | case 0xbb: | 1560 | case 0xbb: |
1685 | case 0xdd: | 1561 | case 0xdd: |
1686 | board->port_count = (board->isa == NO && portcount == 4) ? 4 : | 1562 | board->port_count = (portcount == 4) ? 4 : 8; |
1687 | 8; | ||
1688 | board->shift_count = 12; | 1563 | board->shift_count = 12; |
1689 | break; | 1564 | break; |
1690 | case 0xcc: | 1565 | case 0xcc: |
@@ -1756,9 +1631,12 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1756 | if (retval) | 1631 | if (retval) |
1757 | goto end; | 1632 | goto end; |
1758 | 1633 | ||
1634 | retval = -EIO; | ||
1635 | |||
1759 | for (frame = (struct stframe *)fw->data; | 1636 | for (frame = (struct stframe *)fw->data; |
1760 | frame < (struct stframe *)(fw->data + fw->size); | 1637 | frame < (struct stframe *)(fw->data + fw->size); |
1761 | frame++) { | 1638 | frame = (struct stframe *)((u8 *)(frame + 1) + |
1639 | frame->count)) { | ||
1762 | if (WaitTillCardIsFree(base)) | 1640 | if (WaitTillCardIsFree(base)) |
1763 | goto errrelfw; | 1641 | goto errrelfw; |
1764 | 1642 | ||
@@ -1797,23 +1675,12 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1797 | } | 1675 | } |
1798 | } | 1676 | } |
1799 | 1677 | ||
1800 | retval = -EIO; | ||
1801 | |||
1802 | if (WaitTillCardIsFree(base)) | ||
1803 | goto errrelfw; | ||
1804 | |||
1805 | outw(0xf2, base); | ||
1806 | outw(0x800, base); | ||
1807 | outw(0x0, base); | ||
1808 | outw(0x0, base); | ||
1809 | InterruptTheCard(base); | ||
1810 | outw(0x0, base + 0x4); /* for ISI4608 cards */ | ||
1811 | |||
1812 | /* XXX: should we test it by reading it back and comparing with original like | 1678 | /* XXX: should we test it by reading it back and comparing with original like |
1813 | * in load firmware package? */ | 1679 | * in load firmware package? */ |
1814 | for (frame = (struct stframe*)fw->data; | 1680 | for (frame = (struct stframe *)fw->data; |
1815 | frame < (struct stframe*)(fw->data + fw->size); | 1681 | frame < (struct stframe *)(fw->data + fw->size); |
1816 | frame++) { | 1682 | frame = (struct stframe *)((u8 *)(frame + 1) + |
1683 | frame->count)) { | ||
1817 | if (WaitTillCardIsFree(base)) | 1684 | if (WaitTillCardIsFree(base)) |
1818 | goto errrelfw; | 1685 | goto errrelfw; |
1819 | 1686 | ||
@@ -1838,6 +1705,11 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1838 | } | 1705 | } |
1839 | 1706 | ||
1840 | data = kmalloc(word_count * 2, GFP_KERNEL); | 1707 | data = kmalloc(word_count * 2, GFP_KERNEL); |
1708 | if (data == NULL) { | ||
1709 | dev_err(&pdev->dev, "Card%d, firmware upload " | ||
1710 | "failed, not enough memory\n", index + 1); | ||
1711 | goto errrelfw; | ||
1712 | } | ||
1841 | inw(base); | 1713 | inw(base); |
1842 | insw(base, data, word_count); | 1714 | insw(base, data, word_count); |
1843 | InterruptTheCard(base); | 1715 | InterruptTheCard(base); |
@@ -1863,6 +1735,17 @@ static int __devinit load_firmware(struct pci_dev *pdev, | |||
1863 | } | 1735 | } |
1864 | } | 1736 | } |
1865 | 1737 | ||
1738 | /* xfer ctrl */ | ||
1739 | if (WaitTillCardIsFree(base)) | ||
1740 | goto errrelfw; | ||
1741 | |||
1742 | outw(0xf2, base); | ||
1743 | outw(0x800, base); | ||
1744 | outw(0x0, base); | ||
1745 | outw(0x0, base); | ||
1746 | InterruptTheCard(base); | ||
1747 | outw(0x0, base + 0x4); /* for ISI4608 cards */ | ||
1748 | |||
1866 | board->status |= FIRMWARE_LOADED; | 1749 | board->status |= FIRMWARE_LOADED; |
1867 | retval = 0; | 1750 | retval = 0; |
1868 | 1751 | ||
@@ -1875,8 +1758,6 @@ end: | |||
1875 | /* | 1758 | /* |
1876 | * Insmod can set static symbols so keep these static | 1759 | * Insmod can set static symbols so keep these static |
1877 | */ | 1760 | */ |
1878 | static int io[4]; | ||
1879 | static int irq[4]; | ||
1880 | static int card; | 1761 | static int card; |
1881 | 1762 | ||
1882 | static int __devinit isicom_probe(struct pci_dev *pdev, | 1763 | static int __devinit isicom_probe(struct pci_dev *pdev, |
@@ -1902,20 +1783,29 @@ static int __devinit isicom_probe(struct pci_dev *pdev, | |||
1902 | break; | 1783 | break; |
1903 | } | 1784 | } |
1904 | 1785 | ||
1786 | board->index = index; | ||
1905 | board->base = ioaddr; | 1787 | board->base = ioaddr; |
1906 | board->irq = pciirq; | 1788 | board->irq = pciirq; |
1907 | board->isa = NO; | ||
1908 | card++; | 1789 | card++; |
1909 | 1790 | ||
1910 | pci_set_drvdata(pdev, board); | 1791 | pci_set_drvdata(pdev, board); |
1911 | 1792 | ||
1912 | retval = isicom_register_ioregion(pdev, index); | 1793 | retval = pci_request_region(pdev, 3, ISICOM_NAME); |
1913 | if (retval < 0) | 1794 | if (retval) { |
1795 | dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d " | ||
1796 | "will be disabled.\n", board->base, board->base + 15, | ||
1797 | index + 1); | ||
1798 | retval = -EBUSY; | ||
1914 | goto err; | 1799 | goto err; |
1800 | } | ||
1915 | 1801 | ||
1916 | retval = isicom_register_isr(pdev, index); | 1802 | retval = request_irq(board->irq, isicom_interrupt, |
1917 | if (retval < 0) | 1803 | IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board); |
1804 | if (retval < 0) { | ||
1805 | dev_err(&pdev->dev, "Could not install handler at Irq %d. " | ||
1806 | "Card%d will be disabled.\n", board->irq, index + 1); | ||
1918 | goto errunrr; | 1807 | goto errunrr; |
1808 | } | ||
1919 | 1809 | ||
1920 | retval = reset_card(pdev, index, &signature); | 1810 | retval = reset_card(pdev, index, &signature); |
1921 | if (retval < 0) | 1811 | if (retval < 0) |
@@ -1925,12 +1815,16 @@ static int __devinit isicom_probe(struct pci_dev *pdev, | |||
1925 | if (retval < 0) | 1815 | if (retval < 0) |
1926 | goto errunri; | 1816 | goto errunri; |
1927 | 1817 | ||
1818 | for (index = 0; index < board->port_count; index++) | ||
1819 | tty_register_device(isicom_normal, board->index * 16 + index, | ||
1820 | &pdev->dev); | ||
1821 | |||
1928 | return 0; | 1822 | return 0; |
1929 | 1823 | ||
1930 | errunri: | 1824 | errunri: |
1931 | free_irq(board->irq, board); | 1825 | free_irq(board->irq, board); |
1932 | errunrr: | 1826 | errunrr: |
1933 | isicom_unregister_ioregion(pdev); | 1827 | pci_release_region(pdev, 3); |
1934 | err: | 1828 | err: |
1935 | board->base = 0; | 1829 | board->base = 0; |
1936 | return retval; | 1830 | return retval; |
@@ -1939,18 +1833,21 @@ err: | |||
1939 | static void __devexit isicom_remove(struct pci_dev *pdev) | 1833 | static void __devexit isicom_remove(struct pci_dev *pdev) |
1940 | { | 1834 | { |
1941 | struct isi_board *board = pci_get_drvdata(pdev); | 1835 | struct isi_board *board = pci_get_drvdata(pdev); |
1836 | unsigned int i; | ||
1837 | |||
1838 | for (i = 0; i < board->port_count; i++) | ||
1839 | tty_unregister_device(isicom_normal, board->index * 16 + i); | ||
1942 | 1840 | ||
1943 | free_irq(board->irq, board); | 1841 | free_irq(board->irq, board); |
1944 | isicom_unregister_ioregion(pdev); | 1842 | pci_release_region(pdev, 3); |
1945 | } | 1843 | } |
1946 | 1844 | ||
1947 | static int __devinit isicom_setup(void) | 1845 | static int __init isicom_init(void) |
1948 | { | 1846 | { |
1949 | int retval, idx, channel; | 1847 | int retval, idx, channel; |
1950 | struct isi_port *port; | 1848 | struct isi_port *port; |
1951 | 1849 | ||
1952 | card = 0; | 1850 | card = 0; |
1953 | memset(isi_ports, 0, sizeof(isi_ports)); | ||
1954 | 1851 | ||
1955 | for(idx = 0; idx < BOARD_COUNT; idx++) { | 1852 | for(idx = 0; idx < BOARD_COUNT; idx++) { |
1956 | port = &isi_ports[idx * 16]; | 1853 | port = &isi_ports[idx * 16]; |
@@ -1962,8 +1859,8 @@ static int __devinit isicom_setup(void) | |||
1962 | port->channel = channel; | 1859 | port->channel = channel; |
1963 | port->close_delay = 50 * HZ/100; | 1860 | port->close_delay = 50 * HZ/100; |
1964 | port->closing_wait = 3000 * HZ/100; | 1861 | port->closing_wait = 3000 * HZ/100; |
1965 | INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); | 1862 | INIT_WORK(&port->hangup_tq, do_isicom_hangup); |
1966 | INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port); | 1863 | INIT_WORK(&port->bh_tqueue, isicom_bottomhalf); |
1967 | port->status = 0; | 1864 | port->status = 0; |
1968 | init_waitqueue_head(&port->open_wait); | 1865 | init_waitqueue_head(&port->open_wait); |
1969 | init_waitqueue_head(&port->close_wait); | 1866 | init_waitqueue_head(&port->close_wait); |
@@ -1971,66 +1868,65 @@ static int __devinit isicom_setup(void) | |||
1971 | } | 1868 | } |
1972 | isi_card[idx].base = 0; | 1869 | isi_card[idx].base = 0; |
1973 | isi_card[idx].irq = 0; | 1870 | isi_card[idx].irq = 0; |
1974 | |||
1975 | if (!io[idx]) | ||
1976 | continue; | ||
1977 | |||
1978 | if (irq[idx] == 2 || irq[idx] == 3 || irq[idx] == 4 || | ||
1979 | irq[idx] == 5 || irq[idx] == 7 || | ||
1980 | irq[idx] == 10 || irq[idx] == 11 || | ||
1981 | irq[idx] == 12 || irq[idx] == 15) { | ||
1982 | printk(KERN_ERR "ISICOM: ISA not supported yet.\n"); | ||
1983 | retval = -EINVAL; | ||
1984 | goto error; | ||
1985 | } else | ||
1986 | printk(KERN_ERR "ISICOM: Irq %d unsupported. " | ||
1987 | "Disabling Card%d...\n", irq[idx], idx + 1); | ||
1988 | } | 1871 | } |
1989 | 1872 | ||
1990 | retval = isicom_register_tty_driver(); | 1873 | /* tty driver structure initialization */ |
1991 | if (retval < 0) | 1874 | isicom_normal = alloc_tty_driver(PORT_COUNT); |
1875 | if (!isicom_normal) { | ||
1876 | retval = -ENOMEM; | ||
1992 | goto error; | 1877 | goto error; |
1878 | } | ||
1879 | |||
1880 | isicom_normal->owner = THIS_MODULE; | ||
1881 | isicom_normal->name = "ttyM"; | ||
1882 | isicom_normal->major = ISICOM_NMAJOR; | ||
1883 | isicom_normal->minor_start = 0; | ||
1884 | isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; | ||
1885 | isicom_normal->subtype = SERIAL_TYPE_NORMAL; | ||
1886 | isicom_normal->init_termios = tty_std_termios; | ||
1887 | isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | | ||
1888 | CLOCAL; | ||
1889 | isicom_normal->flags = TTY_DRIVER_REAL_RAW | | ||
1890 | TTY_DRIVER_DYNAMIC_DEV; | ||
1891 | tty_set_operations(isicom_normal, &isicom_ops); | ||
1892 | |||
1893 | retval = tty_register_driver(isicom_normal); | ||
1894 | if (retval) { | ||
1895 | pr_dbg("Couldn't register the dialin driver\n"); | ||
1896 | goto err_puttty; | ||
1897 | } | ||
1993 | 1898 | ||
1994 | retval = pci_register_driver(&isicom_driver); | 1899 | retval = pci_register_driver(&isicom_driver); |
1995 | if (retval < 0) { | 1900 | if (retval < 0) { |
1996 | printk(KERN_ERR "ISICOM: Unable to register pci driver.\n"); | 1901 | printk(KERN_ERR "ISICOM: Unable to register pci driver.\n"); |
1997 | goto errtty; | 1902 | goto err_unrtty; |
1998 | } | 1903 | } |
1999 | 1904 | ||
2000 | init_timer(&tx); | 1905 | mod_timer(&tx, jiffies + 1); |
2001 | tx.expires = jiffies + 1; | ||
2002 | tx.data = 0; | ||
2003 | tx.function = isicom_tx; | ||
2004 | re_schedule = 1; | ||
2005 | add_timer(&tx); | ||
2006 | 1906 | ||
2007 | return 0; | 1907 | return 0; |
2008 | errtty: | 1908 | err_unrtty: |
2009 | isicom_unregister_tty_driver(); | 1909 | tty_unregister_driver(isicom_normal); |
1910 | err_puttty: | ||
1911 | put_tty_driver(isicom_normal); | ||
2010 | error: | 1912 | error: |
2011 | return retval; | 1913 | return retval; |
2012 | } | 1914 | } |
2013 | 1915 | ||
2014 | static void __exit isicom_exit(void) | 1916 | static void __exit isicom_exit(void) |
2015 | { | 1917 | { |
2016 | unsigned int index = 0; | ||
2017 | |||
2018 | re_schedule = 0; | 1918 | re_schedule = 0; |
2019 | 1919 | ||
2020 | while (re_schedule != 2 && index++ < 100) | 1920 | wait_for_completion_timeout(&isi_timerdone, HZ); |
2021 | msleep(10); | ||
2022 | 1921 | ||
2023 | pci_unregister_driver(&isicom_driver); | 1922 | pci_unregister_driver(&isicom_driver); |
2024 | isicom_unregister_tty_driver(); | 1923 | tty_unregister_driver(isicom_normal); |
1924 | put_tty_driver(isicom_normal); | ||
2025 | } | 1925 | } |
2026 | 1926 | ||
2027 | module_init(isicom_setup); | 1927 | module_init(isicom_init); |
2028 | module_exit(isicom_exit); | 1928 | module_exit(isicom_exit); |
2029 | 1929 | ||
2030 | MODULE_AUTHOR("MultiTech"); | 1930 | MODULE_AUTHOR("MultiTech"); |
2031 | MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); | 1931 | MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); |
2032 | MODULE_LICENSE("GPL"); | 1932 | MODULE_LICENSE("GPL"); |
2033 | module_param_array(io, int, NULL, 0); | ||
2034 | MODULE_PARM_DESC(io, "I/O ports for the cards"); | ||
2035 | module_param_array(irq, int, NULL, 0); | ||
2036 | MODULE_PARM_DESC(irq, "Interrupts for the cards"); | ||