diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-07-27 06:35:54 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-07-27 06:35:54 -0400 |
commit | 241fc4367b3ca5d407b043599ed980304a70b91f (patch) | |
tree | 26fca6996c9b3fe89cf86864681adcffc62aac6c /drivers/serial | |
parent | 70db3d91a5228c98603c55fa06c87184a1f9f6db (diff) |
[SERIAL] Expose 8250_pci setup/removal/suspend/resume functions
Re-jig the setup/removal/suspend/resume of 8250 pci ports so that they
know slightly less about how they're attached to a PCI device. Expose
this as the new interface for registering PCI serial ports, as well as
the pciserial_board structure and associated flag definitions.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250_pci.c | 233 |
1 files changed, 121 insertions, 112 deletions
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 7ca07651c10..4e9084edfc7 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c | |||
@@ -34,38 +34,6 @@ | |||
34 | #undef SERIAL_DEBUG_PCI | 34 | #undef SERIAL_DEBUG_PCI |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Definitions for PCI support. | ||
38 | */ | ||
39 | #define FL_BASE_MASK 0x0007 | ||
40 | #define FL_BASE0 0x0000 | ||
41 | #define FL_BASE1 0x0001 | ||
42 | #define FL_BASE2 0x0002 | ||
43 | #define FL_BASE3 0x0003 | ||
44 | #define FL_BASE4 0x0004 | ||
45 | #define FL_GET_BASE(x) (x & FL_BASE_MASK) | ||
46 | |||
47 | /* Use successive BARs (PCI base address registers), | ||
48 | else use offset into some specified BAR */ | ||
49 | #define FL_BASE_BARS 0x0008 | ||
50 | |||
51 | /* do not assign an irq */ | ||
52 | #define FL_NOIRQ 0x0080 | ||
53 | |||
54 | /* Use the Base address register size to cap number of ports */ | ||
55 | #define FL_REGION_SZ_CAP 0x0100 | ||
56 | |||
57 | struct pciserial_board { | ||
58 | unsigned int flags; | ||
59 | unsigned int num_ports; | ||
60 | unsigned int base_baud; | ||
61 | unsigned int uart_offset; | ||
62 | unsigned int reg_shift; | ||
63 | unsigned int first_offset; | ||
64 | }; | ||
65 | |||
66 | struct serial_private; | ||
67 | |||
68 | /* | ||
69 | * init function returns: | 37 | * init function returns: |
70 | * > 0 - number of ports | 38 | * > 0 - number of ports |
71 | * = 0 - use board->num_ports | 39 | * = 0 - use board->num_ports |
@@ -1528,60 +1496,14 @@ serial_pci_matches(struct pciserial_board *board, | |||
1528 | board->first_offset == guessed->first_offset; | 1496 | board->first_offset == guessed->first_offset; |
1529 | } | 1497 | } |
1530 | 1498 | ||
1531 | /* | 1499 | struct serial_private * |
1532 | * Probe one serial board. Unfortunately, there is no rhyme nor reason | 1500 | pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) |
1533 | * to the arrangement of serial ports on a PCI card. | ||
1534 | */ | ||
1535 | static int __devinit | ||
1536 | pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | ||
1537 | { | 1501 | { |
1538 | struct uart_port serial_port; | 1502 | struct uart_port serial_port; |
1539 | struct serial_private *priv; | 1503 | struct serial_private *priv; |
1540 | struct pciserial_board *board, tmp; | ||
1541 | struct pci_serial_quirk *quirk; | 1504 | struct pci_serial_quirk *quirk; |
1542 | int rc, nr_ports, i; | 1505 | int rc, nr_ports, i; |
1543 | 1506 | ||
1544 | if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { | ||
1545 | printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", | ||
1546 | ent->driver_data); | ||
1547 | return -EINVAL; | ||
1548 | } | ||
1549 | |||
1550 | board = &pci_boards[ent->driver_data]; | ||
1551 | |||
1552 | rc = pci_enable_device(dev); | ||
1553 | if (rc) | ||
1554 | return rc; | ||
1555 | |||
1556 | if (ent->driver_data == pbn_default) { | ||
1557 | /* | ||
1558 | * Use a copy of the pci_board entry for this; | ||
1559 | * avoid changing entries in the table. | ||
1560 | */ | ||
1561 | memcpy(&tmp, board, sizeof(struct pciserial_board)); | ||
1562 | board = &tmp; | ||
1563 | |||
1564 | /* | ||
1565 | * We matched one of our class entries. Try to | ||
1566 | * determine the parameters of this board. | ||
1567 | */ | ||
1568 | rc = serial_pci_guess_board(dev, board); | ||
1569 | if (rc) | ||
1570 | goto disable; | ||
1571 | } else { | ||
1572 | /* | ||
1573 | * We matched an explicit entry. If we are able to | ||
1574 | * detect this boards settings with our heuristic, | ||
1575 | * then we no longer need this entry. | ||
1576 | */ | ||
1577 | memcpy(&tmp, &pci_boards[pbn_default], | ||
1578 | sizeof(struct pciserial_board)); | ||
1579 | rc = serial_pci_guess_board(dev, &tmp); | ||
1580 | if (rc == 0 && serial_pci_matches(board, &tmp)) | ||
1581 | moan_device("Redundant entry in serial pci_table.", | ||
1582 | dev); | ||
1583 | } | ||
1584 | |||
1585 | nr_ports = board->num_ports; | 1507 | nr_ports = board->num_ports; |
1586 | 1508 | ||
1587 | /* | 1509 | /* |
@@ -1598,8 +1520,10 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | |||
1598 | */ | 1520 | */ |
1599 | if (quirk->init) { | 1521 | if (quirk->init) { |
1600 | rc = quirk->init(dev); | 1522 | rc = quirk->init(dev); |
1601 | if (rc < 0) | 1523 | if (rc < 0) { |
1602 | goto disable; | 1524 | priv = ERR_PTR(rc); |
1525 | goto err_out; | ||
1526 | } | ||
1603 | if (rc) | 1527 | if (rc) |
1604 | nr_ports = rc; | 1528 | nr_ports = rc; |
1605 | } | 1529 | } |
@@ -1608,8 +1532,8 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | |||
1608 | sizeof(unsigned int) * nr_ports, | 1532 | sizeof(unsigned int) * nr_ports, |
1609 | GFP_KERNEL); | 1533 | GFP_KERNEL); |
1610 | if (!priv) { | 1534 | if (!priv) { |
1611 | rc = -ENOMEM; | 1535 | priv = ERR_PTR(-ENOMEM); |
1612 | goto deinit; | 1536 | goto err_deinit; |
1613 | } | 1537 | } |
1614 | 1538 | ||
1615 | memset(priv, 0, sizeof(struct serial_private) + | 1539 | memset(priv, 0, sizeof(struct serial_private) + |
@@ -1617,7 +1541,6 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | |||
1617 | 1541 | ||
1618 | priv->dev = dev; | 1542 | priv->dev = dev; |
1619 | priv->quirk = quirk; | 1543 | priv->quirk = quirk; |
1620 | pci_set_drvdata(dev, priv); | ||
1621 | 1544 | ||
1622 | memset(&serial_port, 0, sizeof(struct uart_port)); | 1545 | memset(&serial_port, 0, sizeof(struct uart_port)); |
1623 | serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; | 1546 | serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; |
@@ -1643,24 +1566,21 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | |||
1643 | 1566 | ||
1644 | priv->nr = i; | 1567 | priv->nr = i; |
1645 | 1568 | ||
1646 | return 0; | 1569 | return priv; |
1647 | 1570 | ||
1648 | deinit: | 1571 | err_deinit: |
1649 | if (quirk->exit) | 1572 | if (quirk->exit) |
1650 | quirk->exit(dev); | 1573 | quirk->exit(dev); |
1651 | disable: | 1574 | err_out: |
1652 | pci_disable_device(dev); | 1575 | return priv; |
1653 | return rc; | ||
1654 | } | 1576 | } |
1577 | EXPORT_SYMBOL_GPL(pciserial_init_ports); | ||
1655 | 1578 | ||
1656 | static void __devexit pciserial_remove_one(struct pci_dev *dev) | 1579 | void pciserial_remove_ports(struct serial_private *priv) |
1657 | { | 1580 | { |
1658 | struct serial_private *priv = pci_get_drvdata(dev); | ||
1659 | struct pci_serial_quirk *quirk; | 1581 | struct pci_serial_quirk *quirk; |
1660 | int i; | 1582 | int i; |
1661 | 1583 | ||
1662 | pci_set_drvdata(dev, NULL); | ||
1663 | |||
1664 | for (i = 0; i < priv->nr; i++) | 1584 | for (i = 0; i < priv->nr; i++) |
1665 | serial8250_unregister_port(priv->line[i]); | 1585 | serial8250_unregister_port(priv->line[i]); |
1666 | 1586 | ||
@@ -1673,25 +1593,123 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev) | |||
1673 | /* | 1593 | /* |
1674 | * Find the exit quirks. | 1594 | * Find the exit quirks. |
1675 | */ | 1595 | */ |
1676 | quirk = find_quirk(dev); | 1596 | quirk = find_quirk(priv->dev); |
1677 | if (quirk->exit) | 1597 | if (quirk->exit) |
1678 | quirk->exit(dev); | 1598 | quirk->exit(priv->dev); |
1599 | |||
1600 | kfree(priv); | ||
1601 | } | ||
1602 | EXPORT_SYMBOL_GPL(pciserial_remove_ports); | ||
1603 | |||
1604 | void pciserial_suspend_ports(struct serial_private *priv) | ||
1605 | { | ||
1606 | int i; | ||
1607 | |||
1608 | for (i = 0; i < priv->nr; i++) | ||
1609 | if (priv->line[i] >= 0) | ||
1610 | serial8250_suspend_port(priv->line[i]); | ||
1611 | } | ||
1612 | EXPORT_SYMBOL_GPL(pciserial_suspend_ports); | ||
1613 | |||
1614 | void pciserial_resume_ports(struct serial_private *priv) | ||
1615 | { | ||
1616 | int i; | ||
1617 | |||
1618 | /* | ||
1619 | * Ensure that the board is correctly configured. | ||
1620 | */ | ||
1621 | if (priv->quirk->init) | ||
1622 | priv->quirk->init(priv->dev); | ||
1623 | |||
1624 | for (i = 0; i < priv->nr; i++) | ||
1625 | if (priv->line[i] >= 0) | ||
1626 | serial8250_resume_port(priv->line[i]); | ||
1627 | } | ||
1628 | EXPORT_SYMBOL_GPL(pciserial_resume_ports); | ||
1629 | |||
1630 | /* | ||
1631 | * Probe one serial board. Unfortunately, there is no rhyme nor reason | ||
1632 | * to the arrangement of serial ports on a PCI card. | ||
1633 | */ | ||
1634 | static int __devinit | ||
1635 | pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) | ||
1636 | { | ||
1637 | struct serial_private *priv; | ||
1638 | struct pciserial_board *board, tmp; | ||
1639 | int rc; | ||
1640 | |||
1641 | if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { | ||
1642 | printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", | ||
1643 | ent->driver_data); | ||
1644 | return -EINVAL; | ||
1645 | } | ||
1646 | |||
1647 | board = &pci_boards[ent->driver_data]; | ||
1648 | |||
1649 | rc = pci_enable_device(dev); | ||
1650 | if (rc) | ||
1651 | return rc; | ||
1652 | |||
1653 | if (ent->driver_data == pbn_default) { | ||
1654 | /* | ||
1655 | * Use a copy of the pci_board entry for this; | ||
1656 | * avoid changing entries in the table. | ||
1657 | */ | ||
1658 | memcpy(&tmp, board, sizeof(struct pciserial_board)); | ||
1659 | board = &tmp; | ||
1660 | |||
1661 | /* | ||
1662 | * We matched one of our class entries. Try to | ||
1663 | * determine the parameters of this board. | ||
1664 | */ | ||
1665 | rc = serial_pci_guess_board(dev, board); | ||
1666 | if (rc) | ||
1667 | goto disable; | ||
1668 | } else { | ||
1669 | /* | ||
1670 | * We matched an explicit entry. If we are able to | ||
1671 | * detect this boards settings with our heuristic, | ||
1672 | * then we no longer need this entry. | ||
1673 | */ | ||
1674 | memcpy(&tmp, &pci_boards[pbn_default], | ||
1675 | sizeof(struct pciserial_board)); | ||
1676 | rc = serial_pci_guess_board(dev, &tmp); | ||
1677 | if (rc == 0 && serial_pci_matches(board, &tmp)) | ||
1678 | moan_device("Redundant entry in serial pci_table.", | ||
1679 | dev); | ||
1680 | } | ||
1681 | |||
1682 | priv = pciserial_init_ports(dev, board); | ||
1683 | if (!IS_ERR(priv)) { | ||
1684 | pci_set_drvdata(dev, priv); | ||
1685 | return 0; | ||
1686 | } | ||
1687 | |||
1688 | rc = PTR_ERR(priv); | ||
1679 | 1689 | ||
1690 | disable: | ||
1680 | pci_disable_device(dev); | 1691 | pci_disable_device(dev); |
1692 | return rc; | ||
1693 | } | ||
1681 | 1694 | ||
1682 | kfree(priv); | 1695 | static void __devexit pciserial_remove_one(struct pci_dev *dev) |
1696 | { | ||
1697 | struct serial_private *priv = pci_get_drvdata(dev); | ||
1698 | |||
1699 | pci_set_drvdata(dev, NULL); | ||
1700 | |||
1701 | pciserial_remove_ports(priv); | ||
1702 | |||
1703 | pci_disable_device(dev); | ||
1683 | } | 1704 | } |
1684 | 1705 | ||
1685 | static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) | 1706 | static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) |
1686 | { | 1707 | { |
1687 | struct serial_private *priv = pci_get_drvdata(dev); | 1708 | struct serial_private *priv = pci_get_drvdata(dev); |
1688 | 1709 | ||
1689 | if (priv) { | 1710 | if (priv) |
1690 | int i; | 1711 | pciserial_suspend_ports(priv); |
1691 | 1712 | ||
1692 | for (i = 0; i < priv->nr; i++) | ||
1693 | serial8250_suspend_port(priv->line[i]); | ||
1694 | } | ||
1695 | pci_save_state(dev); | 1713 | pci_save_state(dev); |
1696 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 1714 | pci_set_power_state(dev, pci_choose_state(dev, state)); |
1697 | return 0; | 1715 | return 0; |
@@ -1705,21 +1723,12 @@ static int pciserial_resume_one(struct pci_dev *dev) | |||
1705 | pci_restore_state(dev); | 1723 | pci_restore_state(dev); |
1706 | 1724 | ||
1707 | if (priv) { | 1725 | if (priv) { |
1708 | int i; | ||
1709 | |||
1710 | /* | 1726 | /* |
1711 | * The device may have been disabled. Re-enable it. | 1727 | * The device may have been disabled. Re-enable it. |
1712 | */ | 1728 | */ |
1713 | pci_enable_device(dev); | 1729 | pci_enable_device(dev); |
1714 | 1730 | ||
1715 | /* | 1731 | pciserial_resume_ports(priv); |
1716 | * Ensure that the board is correctly configured. | ||
1717 | */ | ||
1718 | if (priv->quirk->init) | ||
1719 | priv->quirk->init(dev); | ||
1720 | |||
1721 | for (i = 0; i < priv->nr; i++) | ||
1722 | serial8250_resume_port(priv->line[i]); | ||
1723 | } | 1732 | } |
1724 | return 0; | 1733 | return 0; |
1725 | } | 1734 | } |