aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2005-07-27 06:35:54 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-07-27 06:35:54 -0400
commit241fc4367b3ca5d407b043599ed980304a70b91f (patch)
tree26fca6996c9b3fe89cf86864681adcffc62aac6c
parent70db3d91a5228c98603c55fa06c87184a1f9f6db (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>
-rw-r--r--drivers/serial/8250_pci.c233
-rw-r--r--include/linux/8250_pci.h38
2 files changed, 159 insertions, 112 deletions
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 7ca07651c10c..4e9084edfc7e 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
57struct 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
66struct 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/* 1499struct serial_private *
1532 * Probe one serial board. Unfortunately, there is no rhyme nor reason 1500pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
1533 * to the arrangement of serial ports on a PCI card.
1534 */
1535static int __devinit
1536pciserial_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}
1577EXPORT_SYMBOL_GPL(pciserial_init_ports);
1655 1578
1656static void __devexit pciserial_remove_one(struct pci_dev *dev) 1579void 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}
1602EXPORT_SYMBOL_GPL(pciserial_remove_ports);
1603
1604void 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}
1612EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
1613
1614void 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}
1628EXPORT_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 */
1634static int __devinit
1635pciserial_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); 1695static 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
1685static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) 1706static 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}
diff --git a/include/linux/8250_pci.h b/include/linux/8250_pci.h
index 5f3ab21b339b..192c0ff7a774 100644
--- a/include/linux/8250_pci.h
+++ b/include/linux/8250_pci.h
@@ -1,2 +1,40 @@
1/*
2 * Definitions for PCI support.
3 */
4#define FL_BASE_MASK 0x0007
5#define FL_BASE0 0x0000
6#define FL_BASE1 0x0001
7#define FL_BASE2 0x0002
8#define FL_BASE3 0x0003
9#define FL_BASE4 0x0004
10#define FL_GET_BASE(x) (x & FL_BASE_MASK)
11
12/* Use successive BARs (PCI base address registers),
13 else use offset into some specified BAR */
14#define FL_BASE_BARS 0x0008
15
16/* do not assign an irq */
17#define FL_NOIRQ 0x0080
18
19/* Use the Base address register size to cap number of ports */
20#define FL_REGION_SZ_CAP 0x0100
21
22struct pciserial_board {
23 unsigned int flags;
24 unsigned int num_ports;
25 unsigned int base_baud;
26 unsigned int uart_offset;
27 unsigned int reg_shift;
28 unsigned int first_offset;
29};
30
31struct serial_private;
32
33struct serial_private *
34pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board);
35void pciserial_remove_ports(struct serial_private *priv);
36void pciserial_suspend_ports(struct serial_private *priv);
37void pciserial_resume_ports(struct serial_private *priv);
38
1int pci_siig10x_fn(struct pci_dev *dev, int enable); 39int pci_siig10x_fn(struct pci_dev *dev, int enable);
2int pci_siig20x_fn(struct pci_dev *dev, int enable); 40int pci_siig20x_fn(struct pci_dev *dev, int enable);