提交 241fc436 编写于 作者: R Russell King 提交者: Russell King

[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: NRussell King <rmk+kernel@arm.linux.org.uk>
上级 70db3d91
...@@ -33,38 +33,6 @@ ...@@ -33,38 +33,6 @@
#undef SERIAL_DEBUG_PCI #undef SERIAL_DEBUG_PCI
/*
* Definitions for PCI support.
*/
#define FL_BASE_MASK 0x0007
#define FL_BASE0 0x0000
#define FL_BASE1 0x0001
#define FL_BASE2 0x0002
#define FL_BASE3 0x0003
#define FL_BASE4 0x0004
#define FL_GET_BASE(x) (x & FL_BASE_MASK)
/* Use successive BARs (PCI base address registers),
else use offset into some specified BAR */
#define FL_BASE_BARS 0x0008
/* do not assign an irq */
#define FL_NOIRQ 0x0080
/* Use the Base address register size to cap number of ports */
#define FL_REGION_SZ_CAP 0x0100
struct pciserial_board {
unsigned int flags;
unsigned int num_ports;
unsigned int base_baud;
unsigned int uart_offset;
unsigned int reg_shift;
unsigned int first_offset;
};
struct serial_private;
/* /*
* init function returns: * init function returns:
* > 0 - number of ports * > 0 - number of ports
...@@ -1528,60 +1496,14 @@ serial_pci_matches(struct pciserial_board *board, ...@@ -1528,60 +1496,14 @@ serial_pci_matches(struct pciserial_board *board,
board->first_offset == guessed->first_offset; board->first_offset == guessed->first_offset;
} }
/* struct serial_private *
* Probe one serial board. Unfortunately, there is no rhyme nor reason pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
* to the arrangement of serial ports on a PCI card.
*/
static int __devinit
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{ {
struct uart_port serial_port; struct uart_port serial_port;
struct serial_private *priv; struct serial_private *priv;
struct pciserial_board *board, tmp;
struct pci_serial_quirk *quirk; struct pci_serial_quirk *quirk;
int rc, nr_ports, i; int rc, nr_ports, i;
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
ent->driver_data);
return -EINVAL;
}
board = &pci_boards[ent->driver_data];
rc = pci_enable_device(dev);
if (rc)
return rc;
if (ent->driver_data == pbn_default) {
/*
* Use a copy of the pci_board entry for this;
* avoid changing entries in the table.
*/
memcpy(&tmp, board, sizeof(struct pciserial_board));
board = &tmp;
/*
* We matched one of our class entries. Try to
* determine the parameters of this board.
*/
rc = serial_pci_guess_board(dev, board);
if (rc)
goto disable;
} else {
/*
* We matched an explicit entry. If we are able to
* detect this boards settings with our heuristic,
* then we no longer need this entry.
*/
memcpy(&tmp, &pci_boards[pbn_default],
sizeof(struct pciserial_board));
rc = serial_pci_guess_board(dev, &tmp);
if (rc == 0 && serial_pci_matches(board, &tmp))
moan_device("Redundant entry in serial pci_table.",
dev);
}
nr_ports = board->num_ports; nr_ports = board->num_ports;
/* /*
...@@ -1598,8 +1520,10 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -1598,8 +1520,10 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
*/ */
if (quirk->init) { if (quirk->init) {
rc = quirk->init(dev); rc = quirk->init(dev);
if (rc < 0) if (rc < 0) {
goto disable; priv = ERR_PTR(rc);
goto err_out;
}
if (rc) if (rc)
nr_ports = rc; nr_ports = rc;
} }
...@@ -1608,8 +1532,8 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) ...@@ -1608,8 +1532,8 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
sizeof(unsigned int) * nr_ports, sizeof(unsigned int) * nr_ports,
GFP_KERNEL); GFP_KERNEL);
if (!priv) { if (!priv) {
rc = -ENOMEM; priv = ERR_PTR(-ENOMEM);
goto deinit; goto err_deinit;
} }
memset(priv, 0, sizeof(struct serial_private) + 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,7 +1541,6 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
priv->dev = dev; priv->dev = dev;
priv->quirk = quirk; priv->quirk = quirk;
pci_set_drvdata(dev, priv);
memset(&serial_port, 0, sizeof(struct uart_port)); memset(&serial_port, 0, sizeof(struct uart_port));
serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; 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,24 +1566,21 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
priv->nr = i; priv->nr = i;
return 0; return priv;
deinit: err_deinit:
if (quirk->exit) if (quirk->exit)
quirk->exit(dev); quirk->exit(dev);
disable: err_out:
pci_disable_device(dev); return priv;
return rc;
} }
EXPORT_SYMBOL_GPL(pciserial_init_ports);
static void __devexit pciserial_remove_one(struct pci_dev *dev) void pciserial_remove_ports(struct serial_private *priv)
{ {
struct serial_private *priv = pci_get_drvdata(dev);
struct pci_serial_quirk *quirk; struct pci_serial_quirk *quirk;
int i; int i;
pci_set_drvdata(dev, NULL);
for (i = 0; i < priv->nr; i++) for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]); serial8250_unregister_port(priv->line[i]);
...@@ -1673,25 +1593,123 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev) ...@@ -1673,25 +1593,123 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
/* /*
* Find the exit quirks. * Find the exit quirks.
*/ */
quirk = find_quirk(dev); quirk = find_quirk(priv->dev);
if (quirk->exit) if (quirk->exit)
quirk->exit(dev); quirk->exit(priv->dev);
kfree(priv);
}
EXPORT_SYMBOL_GPL(pciserial_remove_ports);
void pciserial_suspend_ports(struct serial_private *priv)
{
int i;
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
}
EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
void pciserial_resume_ports(struct serial_private *priv)
{
int i;
/*
* Ensure that the board is correctly configured.
*/
if (priv->quirk->init)
priv->quirk->init(priv->dev);
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_resume_port(priv->line[i]);
}
EXPORT_SYMBOL_GPL(pciserial_resume_ports);
/*
* Probe one serial board. Unfortunately, there is no rhyme nor reason
* to the arrangement of serial ports on a PCI card.
*/
static int __devinit
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct serial_private *priv;
struct pciserial_board *board, tmp;
int rc;
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n",
ent->driver_data);
return -EINVAL;
}
board = &pci_boards[ent->driver_data];
rc = pci_enable_device(dev);
if (rc)
return rc;
if (ent->driver_data == pbn_default) {
/*
* Use a copy of the pci_board entry for this;
* avoid changing entries in the table.
*/
memcpy(&tmp, board, sizeof(struct pciserial_board));
board = &tmp;
/*
* We matched one of our class entries. Try to
* determine the parameters of this board.
*/
rc = serial_pci_guess_board(dev, board);
if (rc)
goto disable;
} else {
/*
* We matched an explicit entry. If we are able to
* detect this boards settings with our heuristic,
* then we no longer need this entry.
*/
memcpy(&tmp, &pci_boards[pbn_default],
sizeof(struct pciserial_board));
rc = serial_pci_guess_board(dev, &tmp);
if (rc == 0 && serial_pci_matches(board, &tmp))
moan_device("Redundant entry in serial pci_table.",
dev);
}
priv = pciserial_init_ports(dev, board);
if (!IS_ERR(priv)) {
pci_set_drvdata(dev, priv);
return 0;
}
rc = PTR_ERR(priv);
disable:
pci_disable_device(dev); pci_disable_device(dev);
return rc;
}
kfree(priv); static void __devexit pciserial_remove_one(struct pci_dev *dev)
{
struct serial_private *priv = pci_get_drvdata(dev);
pci_set_drvdata(dev, NULL);
pciserial_remove_ports(priv);
pci_disable_device(dev);
} }
static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
{ {
struct serial_private *priv = pci_get_drvdata(dev); struct serial_private *priv = pci_get_drvdata(dev);
if (priv) { if (priv)
int i; pciserial_suspend_ports(priv);
for (i = 0; i < priv->nr; i++)
serial8250_suspend_port(priv->line[i]);
}
pci_save_state(dev); pci_save_state(dev);
pci_set_power_state(dev, pci_choose_state(dev, state)); pci_set_power_state(dev, pci_choose_state(dev, state));
return 0; return 0;
...@@ -1705,21 +1723,12 @@ static int pciserial_resume_one(struct pci_dev *dev) ...@@ -1705,21 +1723,12 @@ static int pciserial_resume_one(struct pci_dev *dev)
pci_restore_state(dev); pci_restore_state(dev);
if (priv) { if (priv) {
int i;
/* /*
* The device may have been disabled. Re-enable it. * The device may have been disabled. Re-enable it.
*/ */
pci_enable_device(dev); pci_enable_device(dev);
/* pciserial_resume_ports(priv);
* Ensure that the board is correctly configured.
*/
if (priv->quirk->init)
priv->quirk->init(dev);
for (i = 0; i < priv->nr; i++)
serial8250_resume_port(priv->line[i]);
} }
return 0; return 0;
} }
......
/*
* Definitions for PCI support.
*/
#define FL_BASE_MASK 0x0007
#define FL_BASE0 0x0000
#define FL_BASE1 0x0001
#define FL_BASE2 0x0002
#define FL_BASE3 0x0003
#define FL_BASE4 0x0004
#define FL_GET_BASE(x) (x & FL_BASE_MASK)
/* Use successive BARs (PCI base address registers),
else use offset into some specified BAR */
#define FL_BASE_BARS 0x0008
/* do not assign an irq */
#define FL_NOIRQ 0x0080
/* Use the Base address register size to cap number of ports */
#define FL_REGION_SZ_CAP 0x0100
struct pciserial_board {
unsigned int flags;
unsigned int num_ports;
unsigned int base_baud;
unsigned int uart_offset;
unsigned int reg_shift;
unsigned int first_offset;
};
struct serial_private;
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board);
void pciserial_remove_ports(struct serial_private *priv);
void pciserial_suspend_ports(struct serial_private *priv);
void pciserial_resume_ports(struct serial_private *priv);
int pci_siig10x_fn(struct pci_dev *dev, int enable); int pci_siig10x_fn(struct pci_dev *dev, int enable);
int pci_siig20x_fn(struct pci_dev *dev, int enable); int pci_siig20x_fn(struct pci_dev *dev, int enable);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册