> > So a complete API would be
> > 
> > 	pci_request_{irq,io,mmio}
> > 	pci_release_{irq,io,mmio}
> > 	pci_enable_{irq,io,mmio}
> > 	pci_assign_{irq,io,mmio}
> > 
> > but normally a driver would just use pci_request/release_*() + maybe
> > pci_assign_irq(), which will take care of the appropriate assign/enable
> > internally.
> 
> 
> That seems like a decent enough API, pending a bit of driver conversion 
> to see how well it works out in practice.  So I'm ok with it (with the 
> pci_enable_device proviso, above)
Okay, so here's a patch which actually compiles and works here.
TODO:
o move the pci_set_power_state() before calling pci_driver::probe()
  add pci_disable_device() after pci_driver::remove()
o fix other archs.
Currently, each arch has a
	pcibios_enable_device()
	
function, which now needs to be split into
	pcibios_assign_irq()
	pcibios_enable_irq()
IO/MMIO is all taken care of by the generic code currently. (Possibly we 
need to add callbacks into arch-specific code there)
Apart from breaking each arch but i386/x86_64, the patch is ready, at 
least from my point of view ;)
--Kai
Pull from http://linux-isdn.bkbits.net/linux-2.5.pci
(Merging changesets omitted for clarity)
-----------------------------------------------------------------------------
ChangeSet@1.491, 2002-06-15 14:04:46-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Set pci_dev->driver before calling ::probe()
  
  That's just preparation so that we can use pci_dev->driver inside
  the probe() routine, e.g. for driver->name.
 ----------------------------------------------------------------------------
 pci-driver.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)
-----------------------------------------------------------------------------
ChangeSet@1.492, 2002-06-15 15:19:22-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce pci_assign_irq() and pci_enable_irq()
  
  The functions assign and route an IRQ on a PCI device, a bit inline
  docu is available in drivers/pci/pci.c
  
  Internally they call back into the arch specific
  pcibios_assign/enable_irq(), which means everything but i386/x86_64
  gets broken by this change (should be easy to fix, though).
  
  Rename the function pointer pcibios_enable_irq to pcibios_enable_irq_func
  to not clash with these functions.
 ----------------------------------------------------------------------------
 arch/i386/pci/acpi.c     |    2 -
 arch/i386/pci/common.c   |   18 +++++++++++++++-
 arch/i386/pci/irq.c      |   10 +++++----
 arch/i386/pci/pci.h      |    3 --
 arch/x86_64/pci/acpi.c   |    2 -
 arch/x86_64/pci/common.c |    5 ++++
 arch/x86_64/pci/irq.c    |   10 +++++----
 arch/x86_64/pci/pci.h    |    3 --
 drivers/pci/pci.c        |   50 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h      |    2 +
 10 files changed, 90 insertions(+), 15 deletions(-)
-----------------------------------------------------------------------------
ChangeSet@1.493, 2002-06-15 16:35:23-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce wrapper to set/clear PCI command bits
  
  It'd be worth it even if we wouldn't make yet more use of it in
  the next patch.
 ----------------------------------------------------------------------------
 pci.c |   61 ++++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 32 insertions(+), 29 deletions(-)
-----------------------------------------------------------------------------
ChangeSet@1.494, 2002-06-15 16:38:20-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce pci_assign/enable_io/mmio functions
  
  The main use of those will be internal to
  pci_request/release_io/mmio. However, we export them, since
  there'll always be hardware which needs special hacks...
 ----------------------------------------------------------------------------
 drivers/pci/pci.c   |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/pci.h |    7 ++
 2 files changed, 128 insertions(+), 2 deletions(-)
-----------------------------------------------------------------------------
ChangeSet@1.495, 2002-06-15 17:23:10-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Add pci_request_* and pci_release_* API
  
  Docu is available inline. When switching a driver to this API,
  calling pci_enable_device() is not necessary anymore, the needed
  resources will be activated at pci_request_* time.
  
  In particular, that means if your driver only uses MMIO, IO resources
  on your card won't be assigned and enabled (it's possible that the
  BIOS did that, though).
 ----------------------------------------------------------------------------
 drivers/pci/pci.c   |  187 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h |    9 ++
 2 files changed, 196 insertions(+)
-----------------------------------------------------------------------------
ChangeSet@1.496, 2002-06-15 17:31:38-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Convert two sample drivers to new interface
  
  eepro100 and ymfpci still work fine on my laptop after the change,
  even when zeroing out their BARs during boot.
 ----------------------------------------------------------------------------
 drivers/net/eepro100.c |   83 +++++++++++++++++++++----------------------------
 sound/oss/ymfpci.c     |   45 ++++++++++----------------
 2 files changed, 54 insertions(+), 74 deletions(-)
=============================================================================
unified diffs follow for reference
=============================================================================
-----------------------------------------------------------------------------
ChangeSet@1.491, 2002-06-15 14:04:46-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Set pci_dev->driver before calling ::probe()
  
  That's just preparation so that we can use pci_dev->driver inside
  the probe() routine, e.g. for driver->name.
  ---------------------------------------------------------------------------
diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
--- a/drivers/pci/pci-driver.c	Sat Jun 15 17:59:18 2002
+++ b/drivers/pci/pci-driver.c	Sat Jun 15 17:59:18 2002
@@ -48,12 +48,14 @@
 		const struct pci_device_id *id;
 
 		id = pci_match_device(drv->id_table, pci_dev);
-		if (id)
-			error = drv->probe(pci_dev, id);
-		if (error >= 0) {
+		if (id) {
 			pci_dev->driver = drv;
-			error = 0;
+			error = drv->probe(pci_dev, id);
 		}
+		if (error < 0)
+			pci_dev->driver = NULL;
+		else 
+			error = 0;
 	}
 	return error;
 }
-----------------------------------------------------------------------------
ChangeSet@1.492, 2002-06-15 15:19:22-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce pci_assign_irq() and pci_enable_irq()
  
  The functions assign and route an IRQ on a PCI device, a bit inline
  docu is available in drivers/pci/pci.c
  
  Internally they call back into the arch specific
  pcibios_assign/enable_irq(), which means everything but i386/x86_64
  gets broken by this change (should be easy to fix, though).
  
  Rename the function pointer pcibios_enable_irq to pcibios_enable_irq_func
  to not clash with these functions.
  ---------------------------------------------------------------------------
diff -Nru a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
--- a/arch/i386/pci/acpi.c	Sat Jun 15 17:59:19 2002
+++ b/arch/i386/pci/acpi.c	Sat Jun 15 17:59:19 2002
@@ -13,7 +13,7 @@
 			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
 			printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
 			pcibios_scanned++;
-			pcibios_enable_irq = acpi_pci_irq_enable;
+			pcibios_enable_irq_func = acpi_pci_irq_enable;
 		} else
 			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
 
diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c
--- a/arch/i386/pci/common.c	Sat Jun 15 17:59:19 2002
+++ b/arch/i386/pci/common.c	Sat Jun 15 17:59:19 2002
@@ -209,5 +209,21 @@
 	if ((err = pcibios_enable_resources(dev)) < 0)
 		return err;
 
-	return pcibios_enable_irq(dev);
+	return pcibios_enable_irq_func(dev);
+}
+
+int pcibios_assign_irq(struct pci_dev *dev)
+{
+	return pcibios_enable_irq_func(dev);
+}
+
+/*
+ * We've done all the work in pcibios_assign_irq already. 
+ * We may want to change this later to activate the actual routing at this 
+ * point, though.
+ * It's only ever called after a successful pcibios_assign_irq()
+ */
+int pcibios_enable_irq(struct pci_dev *dev)
+{
+	return 0;
 }
diff -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
--- a/arch/i386/pci/irq.c	Sat Jun 15 17:59:19 2002
+++ b/arch/i386/pci/irq.c	Sat Jun 15 17:59:19 2002
@@ -44,7 +44,7 @@
 	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
 };
 
-int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
+int (*pcibios_enable_irq_func)(struct pci_dev *dev);
 
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
@@ -684,11 +684,13 @@
 	return 1;
 }
 
+static int pirq_enable_irq(struct pci_dev *dev);
+
 static int __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
 
-	if (pcibios_enable_irq)
+	if (pcibios_enable_irq_func)
 		return 0;
 
 	pirq_table = pirq_find_routing_table();
@@ -711,7 +713,7 @@
 			pirq_table = NULL;
 	}
 
-	pcibios_enable_irq = pirq_enable_irq;
+	pcibios_enable_irq_func = pirq_enable_irq;
 
 	pcibios_fixup_irqs();
 	return 0;
@@ -794,7 +796,7 @@
 	pirq_penalty[irq] += 100;
 }
 
-int pirq_enable_irq(struct pci_dev *dev)
+static int pirq_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
diff -Nru a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
--- a/arch/i386/pci/pci.h	Sat Jun 15 17:59:19 2002
+++ b/arch/i386/pci/pci.h	Sat Jun 15 17:59:19 2002
@@ -70,6 +70,5 @@
 extern spinlock_t pci_config_lock;
 
 void pcibios_fixup_irqs(void);
-int pirq_enable_irq(struct pci_dev *dev);
 
-extern int (*pcibios_enable_irq)(struct pci_dev *dev);
+extern int (*pcibios_enable_irq_func)(struct pci_dev *dev);
diff -Nru a/arch/x86_64/pci/acpi.c b/arch/x86_64/pci/acpi.c
--- a/arch/x86_64/pci/acpi.c	Sat Jun 15 17:59:19 2002
+++ b/arch/x86_64/pci/acpi.c	Sat Jun 15 17:59:19 2002
@@ -13,7 +13,7 @@
 			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
 			printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
 			pcibios_scanned++;
-			pcibios_enable_irq = acpi_pci_irq_enable;
+			pcibios_enable_irq_func = acpi_pci_irq_enable;
 		} else
 			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
 
diff -Nru a/arch/x86_64/pci/common.c b/arch/x86_64/pci/common.c
--- a/arch/x86_64/pci/common.c	Sat Jun 15 17:59:19 2002
+++ b/arch/x86_64/pci/common.c	Sat Jun 15 17:59:19 2002
@@ -194,3 +194,8 @@
 
 	return pcibios_enable_irq(dev);
 }
+
+int pcibios_enable_irq(struct pci_dev *dev)
+{
+	return pcibios_enable_irq_func(dev);
+}
diff -Nru a/arch/x86_64/pci/irq.c b/arch/x86_64/pci/irq.c
--- a/arch/x86_64/pci/irq.c	Sat Jun 15 17:59:19 2002
+++ b/arch/x86_64/pci/irq.c	Sat Jun 15 17:59:19 2002
@@ -44,7 +44,7 @@
 	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new);
 };
 
-int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
+int (*pcibios_enable_irq_func)(struct pci_dev *dev);
 
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
@@ -528,11 +528,13 @@
 	return 1;
 }
 
+static int pirq_enable_irq(struct pci_dev *dev);
+
 static int __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
 
-	if (pcibios_enable_irq)
+	if (pcibios_enable_irq_func)
 		return 0;
 
 	pirq_table = pirq_find_routing_table();
@@ -551,7 +553,7 @@
 			pirq_table = NULL;
 	}
 
-	pcibios_enable_irq = pirq_enable_irq;
+	pcibios_enable_irq_func = pirq_enable_irq;
 
 	pcibios_fixup_irqs();
 	return 0;
@@ -634,7 +636,7 @@
 	pirq_penalty[irq] += 100;
 }
 
-int pirq_enable_irq(struct pci_dev *dev)
+static int pirq_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
diff -Nru a/arch/x86_64/pci/pci.h b/arch/x86_64/pci/pci.h
--- a/arch/x86_64/pci/pci.h	Sat Jun 15 17:59:19 2002
+++ b/arch/x86_64/pci/pci.h	Sat Jun 15 17:59:19 2002
@@ -68,6 +68,5 @@
 extern spinlock_t pci_config_lock;
 
 void pcibios_fixup_irqs(void);
-int pirq_enable_irq(struct pci_dev *dev);
 
-extern int (*pcibios_enable_irq)(struct pci_dev *dev);
+extern int (*pcibios_enable_irq_func)(struct pci_dev *dev);
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Jun 15 17:59:19 2002
+++ b/drivers/pci/pci.c	Sat Jun 15 17:59:19 2002
@@ -555,6 +555,56 @@
 	return 0;
 }
 
+/**
+ * pci_assign_irq - Assign an IRQ to a PCI device
+ * @dev: PCI device
+ *
+ *  Figure out the the routing from the IRQ pin to an actual IRQ 
+ *  vector on the processor.
+ *  Make sure the device is in D0 state (woken up).
+ *  Returns an IRQ number (only supposed to be use for printk() or 
+ *  similar), or a negative error code.
+ */
+int
+pci_assign_irq(struct pci_dev *dev)
+{
+	int retval;
+
+	pci_set_power_state(dev, 0);
+
+	retval = pcibios_assign_irq(dev);
+	if (retval < 0)
+		return retval;
+
+	return dev->irq;
+}
+
+/**
+ * pci_enable_irq - Enable an IRQ on a PCI device
+ * @dev: PCI device
+ *
+ *  Route an IRQ pin to an actual IRQ vector on the processor.
+ *  Make sure the device is in D0 state (woken up).
+ *  Returns an IRQ number (only supposed to be use for printk() or 
+ *  similar), or a negative error code.
+ */
+int
+pci_enable_irq(struct pci_dev *dev)
+{
+	int retval;
+
+	retval = pci_assign_irq(dev);
+	if (retval < 0)
+		return retval;
+
+	retval = pcibios_enable_irq(dev);
+	if (retval < 0)
+		return retval;
+
+	return dev->irq;
+}
+
+
 static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sat Jun 15 17:59:19 2002
+++ b/include/linux/pci.h	Sat Jun 15 17:59:19 2002
@@ -500,6 +500,8 @@
 
 void pcibios_fixup_bus(struct pci_bus *);
 int pcibios_enable_device(struct pci_dev *);
+int pcibios_assign_irq(struct pci_dev *dev);
+int pcibios_enable_irq(struct pci_dev *dev);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
-----------------------------------------------------------------------------
ChangeSet@1.493, 2002-06-15 16:35:23-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce wrapper to set/clear PCI command bits
  
  It'd be worth it even if we wouldn't make yet more use of it in
  the next patch.
  ---------------------------------------------------------------------------
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Jun 15 17:59:20 2002
+++ b/drivers/pci/pci.c	Sat Jun 15 17:59:20 2002
@@ -239,6 +239,34 @@
 	return 0;
 }
 
+static void
+pci_set_command(struct pci_dev *dev, u16 mask)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if ((cmd | mask) != cmd) {
+		printk(KERN_DEBUG "PCI: Enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, cmd, cmd | mask);
+		pci_write_config_word(dev, PCI_COMMAND, cmd | mask);
+	}
+}
+
+static void
+pci_clear_command(struct pci_dev *dev, u16 mask)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if ((cmd & ~mask) != cmd) {
+		printk(KERN_DEBUG "PCI: Disabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, cmd, cmd & ~mask);
+		pci_write_config_word(dev, PCI_COMMAND, cmd & ~mask);
+	}
+}
+
 /**
  * pci_enable_device - Initialize device before it's used by a driver.
  * @dev: PCI device to be initialized
@@ -268,13 +296,7 @@
 void
 pci_disable_device(struct pci_dev *dev)
 {
-	u16 pci_command;
-
-	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
-	if (pci_command & PCI_COMMAND_MASTER) {
-		pci_command &= ~PCI_COMMAND_MASTER;
-		pci_write_config_word(dev, PCI_COMMAND, pci_command);
-	}
+	pci_clear_command(dev, PCI_COMMAND_MASTER);
 }
 
 /**
@@ -426,14 +448,7 @@
 void
 pci_set_master(struct pci_dev *dev)
 {
-	u16 cmd;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	if (! (cmd & PCI_COMMAND_MASTER)) {
-		DBG("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
-		cmd |= PCI_COMMAND_MASTER;
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
+	pci_set_command(dev, PCI_COMMAND_MASTER);
 	pcibios_set_master(dev);
 }
 
@@ -494,7 +509,6 @@
 pci_set_mwi(struct pci_dev *dev)
 {
 	int rc;
-	u16 cmd;
 
 #ifdef HAVE_ARCH_PCI_MWI
 	rc = pcibios_prep_mwi(dev);
@@ -505,12 +519,7 @@
 	if (rc)
 		return rc;
 
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	if (! (cmd & PCI_COMMAND_INVALIDATE)) {
-		DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name);
-		cmd |= PCI_COMMAND_INVALIDATE;
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
+	pci_set_command(dev, PCI_COMMAND_INVALIDATE);
 	
 	return 0;
 }
@@ -524,13 +533,7 @@
 void
 pci_clear_mwi(struct pci_dev *dev)
 {
-	u16 cmd;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	if (cmd & PCI_COMMAND_INVALIDATE) {
-		cmd &= ~PCI_COMMAND_INVALIDATE;
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
+	pci_clear_command(dev, PCI_COMMAND_INVALIDATE);
 }
 
 int
-----------------------------------------------------------------------------
ChangeSet@1.494, 2002-06-15 16:38:20-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Introduce pci_assign/enable_io/mmio functions
  
  The main use of those will be internal to
  pci_request/release_io/mmio. However, we export them, since
  there'll always be hardware which needs special hacks...
  ---------------------------------------------------------------------------
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Jun 15 17:59:22 2002
+++ b/drivers/pci/pci.c	Sat Jun 15 17:59:22 2002
@@ -280,6 +280,13 @@
 {
 	int err;
 
+	/* FIXME: this should be turned into
+	 *   pci_enable_irq(dev);
+	 *   pci_enable_mmio(dev);
+	 *   pci_enable_io(dev);
+	 * after splitting the per arch pcibios_enable_device()
+	 * into the appropriate parts
+	 */
 	pci_set_power_state(dev, 0);
 	if ((err = pcibios_enable_device(dev)) < 0)
 		return err;
@@ -562,9 +569,9 @@
  * pci_assign_irq - Assign an IRQ to a PCI device
  * @dev: PCI device
  *
+ *  Make sure the device is in D0 state (woken up).
  *  Figure out the the routing from the IRQ pin to an actual IRQ 
  *  vector on the processor.
- *  Make sure the device is in D0 state (woken up).
  *  Returns an IRQ number (only supposed to be use for printk() or 
  *  similar), or a negative error code.
  */
@@ -586,8 +593,8 @@
  * pci_enable_irq - Enable an IRQ on a PCI device
  * @dev: PCI device
  *
- *  Route an IRQ pin to an actual IRQ vector on the processor.
  *  Make sure the device is in D0 state (woken up).
+ *  Route an IRQ pin to an actual IRQ vector on the processor.
  *  Returns an IRQ number (only supposed to be use for printk() or 
  *  similar), or a negative error code.
  */
@@ -607,6 +614,111 @@
 	return dev->irq;
 }
 
+static int
+pci_assign_resources(struct pci_dev *dev, unsigned long flags)
+{
+	int nr, retval = 0;
+	struct resource *r;
+
+	pci_set_power_state(dev, 0);
+
+	for (nr = 0; nr < PCI_ROM_RESOURCE; nr++) {
+		r = &dev->resource[nr];
+
+		/* Skip if other type */
+		if ((r->flags ^ flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;
+
+		/* If unassigned, try to assign */
+		if (!r->start && r->end) {
+			retval = pci_assign_resource(dev, nr);
+			if (retval < 0)
+				break;
+		}
+	}
+	return retval;
+}
+
+/**
+ * pci_assign_mmio - Assign MMIO resources on a PCI device
+ * @dev: PCI device
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned MMIO resources for
+ *  the PCI device.
+ *  Returns 0 on success, or a negative error code.
+ */
+int
+pci_assign_mmio(struct pci_dev *dev)
+{
+	return pci_assign_resources(dev, IORESOURCE_MEM);
+}
+
+/**
+ * pci_assign_io - Assign IO resources on a PCI device
+ * @dev: PCI device
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned IO resources for
+ *  the PCI device.
+ *  Returns 0 on success, or a negative error code.
+ */
+int
+pci_assign_io(struct pci_dev *dev)
+{
+	return pci_assign_resources(dev, IORESOURCE_IO);
+}
+
+static int
+pci_enable_resources(struct pci_dev *dev, unsigned long flags)
+{
+	int retval;
+
+	retval = pci_assign_resources(dev, flags);
+	if (retval < 0)
+		return retval;
+
+	if (flags & IORESOURCE_IO)
+		pci_set_command(dev, PCI_COMMAND_IO);
+	if (flags & IORESOURCE_MEM)
+		pci_set_command(dev, PCI_COMMAND_MEMORY);
+
+	return 0;
+}
+
+/**
+ * pci_enable_mmio - Enable IO resources on a PCI device
+ * @dev: PCI device
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned IO resources for
+ *  the PCI device.
+ *  Enable MMIO in the PCI COMMAND config word
+ *  Returns 0 on success, or a negative error code.
+ */
+int
+pci_enable_mmio(struct pci_dev *dev)
+{
+	return pci_enable_resources(dev, IORESOURCE_MEM);
+}
+
+/**
+ * pci_enable_io - Enable IO resources on a PCI device
+ * @dev: PCI device
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned IO resources for
+ *  the PCI device.
+ *  Enable IO in the PCI COMMAND config word
+ *  Returns 0 on success, or a negative error code.
+ */
+int
+pci_enable_io(struct pci_dev *dev)
+{
+	return pci_enable_resources(dev, IORESOURCE_IO);
+}
+
+
 
 static int __devinit pci_init(void)
 {
@@ -654,6 +766,13 @@
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
 EXPORT_SYMBOL(pci_enable_wake);
+
+EXPORT_SYMBOL(pci_assign_irq);
+EXPORT_SYMBOL(pci_assign_mmio);
+EXPORT_SYMBOL(pci_assign_io);
+EXPORT_SYMBOL(pci_enable_irq);
+EXPORT_SYMBOL(pci_enable_mmio);
+EXPORT_SYMBOL(pci_enable_io);
 
 /* Obsolete functions */
 
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sat Jun 15 17:59:22 2002
+++ b/include/linux/pci.h	Sat Jun 15 17:59:22 2002
@@ -576,6 +576,13 @@
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
+int pci_assign_irq(struct pci_dev *dev);
+int pci_enable_irq(struct pci_dev *dev);
+int pci_assign_mmio(struct pci_dev *dev);
+int pci_assign_io(struct pci_dev *dev);
+int pci_enable_mmio(struct pci_dev *dev);
+int pci_enable_io(struct pci_dev *dev);
+
 /* Power management related routines */
 int pci_save_state(struct pci_dev *dev, u32 *buffer);
 int pci_restore_state(struct pci_dev *dev, u32 *buffer);
-----------------------------------------------------------------------------
ChangeSet@1.495, 2002-06-15 17:23:10-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Add pci_request_* and pci_release_* API
  
  Docu is available inline. When switching a driver to this API,
  calling pci_enable_device() is not necessary anymore, the needed
  resources will be activated at pci_request_* time.
  
  In particular, that means if your driver only uses MMIO, IO resources
  on your card won't be assigned and enabled (it's possible that the
  BIOS did that, though).
  ---------------------------------------------------------------------------
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Jun 15 17:59:23 2002
+++ b/drivers/pci/pci.c	Sat Jun 15 17:59:23 2002
@@ -614,6 +614,57 @@
 	return dev->irq;
 }
 
+/**
+ * pci_request_irq - Register an interrupt handler for a PCI device
+ * @dev: PCI device
+ * @handler: Function to be called when the IRQ occurs
+ * @irqflags: Interrupt type flags
+ * @dev_id: A cookie passed back to the handler function
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Route an IRQ pin to an actual IRQ vector on the processor.
+ *  Register a handler for this IRQ vector.
+ *  Returns an IRQ number (only supposed to be use for printk() or 
+ *  similar), or a negative error code.
+ */
+int
+pci_request_irq(struct pci_dev *dev,
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long flags, void *dev_id)
+{
+	int retval;
+
+	BUG_ON(!(flags & SA_SHIRQ));
+
+	retval = pcibios_assign_irq(dev);
+	if (retval < 0)
+		return retval;
+
+	retval = request_irq(dev->irq, handler, flags, dev->slot_name, dev_id);
+	if (retval < 0)
+		return retval;
+	
+	retval = pcibios_enable_irq(dev);
+	if (retval < 0)
+		free_irq(dev->irq, dev_id);
+
+	return retval;
+}
+
+/**
+ * pci_release_irq - Unregister an interrupt handler for a PCI device
+ * @dev: PCI device
+ * @dev_id: Same cookie you passed when calling pci_request_irq()
+ *
+ *  Unregister an IRQ handler previously registered with
+ *  pci_request_irq().
+ */
+void
+pci_release_irq(struct pci_dev *dev, void *dev_id)
+{
+	free_irq(dev->irq, dev_id);
+}
+
 static int
 pci_assign_resources(struct pci_dev *dev, unsigned long flags)
 {
@@ -718,7 +769,136 @@
 	return pci_enable_resources(dev, IORESOURCE_IO);
 }
 
+static unsigned long
+pci_request_resources(struct pci_dev *pdev, unsigned int nr,
+		      unsigned long flags, struct resource *root)
+{
+	struct pci_driver *drv = pci_dev_driver(pdev);
+	char *drv_name = drv ? drv->name : "unknown";
+	struct resource *res;
+
+	BUG_ON(nr >= PCI_ROM_RESOURCE);
+
+	/* Make sure we have the right type (IO/MMIO) */
+	if ((pci_resource_flags(pdev, nr) ^ flags) & 
+	    (IORESOURCE_IO | IORESOURCE_MEM))
+		goto err;
+
+	/* Assign and enable all resources of this type */
+	pci_enable_resources(pdev, flags);
+
+	res = __request_region(root, pci_resource_start(pdev, nr), 
+			       pci_resource_len(pdev, nr), drv_name);
+	if (!res)
+		goto err;
+
+	return res->start;
+
+ err:
+	/* Print extensive info so that drivers don't have to do it
+	   themselves */
+	printk(KERN_INFO
+		   "%s: failed to get %s(%d) for %s, %#lx-%#lx flags %#lx.\n",
+		   pdev->slot_name, (flags == IORESOURCE_IO ? "IO" : "MMIO"),
+		   nr, drv_name,
+		   pci_resource_start(pdev, nr),
+		   pci_resource_flags(pdev, nr),
+		   pci_resource_end(pdev, nr));
 
+	return 0;
+}
+
+/**
+ * pci_request_mmio - Register a MMIO region on a PCI device
+ * @dev: PCI device
+ * @nr:  The index of the Base Address Register (BAR)
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned MMIO resources for
+ *  the PCI device.
+ *  Enable MMIO in the PCI COMMAND config word
+ *  Register the requested MMIO region with the kernel
+ *  resource management.
+ *  Map the MMIO region.
+ *  Returns a cookie to be used with the MMIO functions
+ *  (readb, writeb, ...), or NULL on error.
+ *  In case of failure it also printk's extensive information
+ *  about what went wrong (so you don't need to do that in your
+ *  driver)
+ */
+void *
+pci_request_mmio(struct pci_dev *pdev, unsigned int nr)
+{
+	unsigned long base;
+	void *addr;
+
+	base = pci_request_resources(pdev, nr, IORESOURCE_MEM, &iomem_resource);
+	if (!base)
+		return 0;
+
+	addr = ioremap(base, pci_resource_len(pdev, nr));
+	if (!addr)
+		release_region(base, pci_resource_len(pdev, nr));
+
+	return addr;
+}
+
+/**
+ * pci_request_io - Register an IO region on a PCI device
+ * @dev: PCI device
+ * @nr:  The index of the Base Address Register (BAR)
+ *
+ *  Make sure the device is in D0 state (woken up).
+ *  Assign all as of yet unassigned IO resources for
+ *  the PCI device.
+ *  Enable IO in the PCI COMMAND config word
+ *  Register the requested IO region with the kernel
+ *  resource management.
+ *  Returns an IO port to be used with the IO functions
+ *  (inb, outb, ...), or 0 on error.
+ *  In case of failure it also printk's extensive information
+ *  about what went wrong (so you don't need to do that in your
+ *  driver)
+ */
+unsigned long
+pci_request_io(struct pci_dev *dev, unsigned int nr)
+{
+	return pci_request_resources(dev, nr, IORESOURCE_IO, &ioport_resource);
+}
+
+/**
+ * pci_release_mmio - Release an MMIO region on a PCI device
+ * @dev:  PCI device
+ * @nr:   The index of the Base Address Register (BAR)
+ * @addr: The cookie returned from pci_request_mmio()
+ *
+ *  Unmaps and unregisters a MMIO region previously
+ *  registered by pci_request_mmio().
+ */
+void
+pci_release_mmio(struct pci_dev *dev, unsigned int nr, void *addr)
+{
+	iounmap(addr);
+	__release_region(&iomem_resource,
+			 pci_resource_start(dev, nr), 
+			 pci_resource_len(dev, nr));
+}
+
+/**
+ * pci_release_io - Release an IO region on a PCI device
+ * @dev:  PCI device
+ * @nr:   The index of the Base Address Register (BAR)
+ *
+ *  Unregisters an IO region previously registered by 
+ *  pci_request_io().
+ */
+void
+pci_release_io(struct pci_dev *dev, unsigned int nr)
+{
+	__release_region(&ioport_resource,
+			 pci_resource_start(dev, nr), 
+			 pci_resource_len(dev, nr));
+}
 
 static int __devinit pci_init(void)
 {
@@ -766,6 +946,13 @@
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
 EXPORT_SYMBOL(pci_enable_wake);
+
+EXPORT_SYMBOL(pci_request_irq);
+EXPORT_SYMBOL(pci_request_mmio);
+EXPORT_SYMBOL(pci_request_io);
+EXPORT_SYMBOL(pci_release_irq);
+EXPORT_SYMBOL(pci_release_mmio);
+EXPORT_SYMBOL(pci_release_io);
 
 EXPORT_SYMBOL(pci_assign_irq);
 EXPORT_SYMBOL(pci_assign_mmio);
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sat Jun 15 17:59:23 2002
+++ b/include/linux/pci.h	Sat Jun 15 17:59:23 2002
@@ -576,6 +576,15 @@
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
+int pci_request_irq(struct pci_dev *dev,
+		    void (*handler)(int, void *, struct pt_regs *),
+		    unsigned long flags, void *dev_id);
+void *pci_request_mmio(struct pci_dev *pdev, unsigned int nr);
+unsigned long pci_request_io(struct pci_dev *dev, unsigned int nr);
+void pci_release_irq(struct pci_dev *dev, void *dev_id);
+void pci_release_mmio(struct pci_dev *dev, unsigned int nr, void *addr);
+void pci_release_io(struct pci_dev *dev, unsigned int nr);
+
 int pci_assign_irq(struct pci_dev *dev);
 int pci_enable_irq(struct pci_dev *dev);
 int pci_assign_mmio(struct pci_dev *dev);
-----------------------------------------------------------------------------
ChangeSet@1.496, 2002-06-15 17:31:38-05:00, kai@tp1.ruhr-uni-bochum.de
  PCI: Convert two sample drivers to new interface
  
  eepro100 and ymfpci still work fine on my laptop after the change,
  even when zeroing out their BARs during boot.
  ---------------------------------------------------------------------------
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Sat Jun 15 17:59:24 2002
+++ b/drivers/net/eepro100.c	Sat Jun 15 17:59:24 2002
@@ -558,6 +558,7 @@
 static int __devinit eepro100_init_one (struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
+	u16 cmd;
 	unsigned long ioaddr;
 	int irq;
 	int acpi_idle_state = 0, pm;
@@ -567,65 +568,55 @@
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
-	/* save power state before pci_enable_device overwrites it */
+	/* save power state before pci_request_* overwrites it */
 	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
 	if (pm) {
 		u16 pwr_command;
 		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	}
-
-	if (pci_enable_device(pdev))
-		goto err_out_free_mmio_region;
-
-	pci_set_master(pdev);
-
-	if (!request_region(pci_resource_start(pdev, 1),
-			pci_resource_len(pdev, 1), "eepro100")) {
-		printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+	irq = pci_assign_irq(pdev);
+	if (irq < 0)
 		goto err_out_none;
-	}
-	if (!request_mem_region(pci_resource_start(pdev, 0),
-			pci_resource_len(pdev, 0), "eepro100")) {
-		printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
-		goto err_out_free_pio_region;
-	}
 
-	irq = pdev->irq;
 #ifdef USE_IO
-	ioaddr = pci_resource_start(pdev, 1);
+	ioaddr = pci_request_io(pdev, 1);
+	if (!ioaddr)
+		goto err_out_none;
+
 	if (speedo_debug > 2)
-		printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+		printk("Found Intel i82557 PCI Speedo at I/O %#lx IRQ %d.\n",
 			   ioaddr, irq);
 #else
-	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
-									pci_resource_len(pdev, 0));
-	if (!ioaddr) {
-		printk (KERN_ERR "eepro100: cannot remap MMIO region %lx @ %lx\n",
-				pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
-		goto err_out_free_mmio_region;
-	}
+	/* Even if using MMIO, the hardware won't work 
+	   unless IO is enabled, too */
+	if (pci_enable_io(pdev) < 0)
+		goto err_out_none;
+
+	ioaddr = (unsigned long) pci_request_mmio(pdev, 0);
+	if (!ioaddr)
+		goto err_out_none;
+
 	if (speedo_debug > 2)
-		printk("Found Intel i82557 PCI Speedo, MMIO at %#lx, IRQ %d.\n",
+		printk("Found Intel i82557 PCI Speedo, MMIO at %#lx IRQ %d.\n",
 			   pci_resource_start(pdev, 0), irq);
 #endif
-
+	pci_set_master(pdev);
 
 	if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0)
 		cards_found++;
 	else
-		goto err_out_iounmap;
+		goto err_out_disable;
 
 	return 0;
 
-err_out_iounmap: ;
-#ifndef USE_IO
-	iounmap ((void *)ioaddr);
+ err_out_disable:
+	pci_disable_device(pdev);
+#ifdef USE_IO
+	pci_release_io(pdev, 1);
+#else
+	pci_release_mmio(pdev, 0, (void *)ioaddr);
 #endif
-err_out_free_mmio_region:
-	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-err_out_free_pio_region:
-	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
 err_out_none:
 	return -ENODEV;
 }
@@ -803,7 +794,6 @@
 	pci_set_drvdata (pdev, dev);
 
 	dev->base_addr = ioaddr;
-	dev->irq = pdev->irq;
 
 	sp = dev->priv;
 	sp->pdev = pdev;
@@ -924,7 +914,7 @@
 	int retval;
 
 	if (speedo_debug > 1)
-		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
+		printk(KERN_DEBUG "%s: speedo_open()\n", dev->name);
 
 	MOD_INC_USE_COUNT;
 
@@ -939,11 +929,12 @@
 	sp->in_interrupt = 0;
 
 	/* .. we can safely take handler calls during init. */
-	retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev);
-	if (retval) {
+	retval = pci_request_irq(sp->pdev, &speedo_interrupt, SA_SHIRQ, dev);
+	if (retval < 0) {
 		MOD_DEC_USE_COUNT;
 		return retval;
 	}
+	dev->irq = retval;
 
 	dev->if_port = sp->default_port;
 
@@ -1834,7 +1825,7 @@
 	/* Shutting down the chip nicely fails to disable flow control. So.. */
 	outl(PortPartialReset, ioaddr + SCBPort);
 
-	free_irq(dev->irq, dev);
+	pci_release_irq(sp->pdev, dev);
 
 	/* Print a few items for debugging. */
 	if (speedo_debug > 3)
@@ -2253,11 +2244,10 @@
 	
 	unregister_netdev(dev);
 
-	release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
-	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-
-#ifndef USE_IO
-	iounmap((char *)dev->base_addr);
+#ifdef USE_IO
+	pci_release_io(pdev, 1);
+#else
+	pci_release_mmio(pdev, 0, (void *) dev->base_addr);
 #endif
 
 	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
@@ -2348,7 +2338,6 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -Nru a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
--- a/sound/oss/ymfpci.c	Sat Jun 15 17:59:24 2002
+++ b/sound/oss/ymfpci.c	Sat Jun 15 17:59:24 2002
@@ -2496,16 +2496,15 @@
 static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
 	u16 ctrl;
-	unsigned long base;
 	ymfpci_t *codec;
+	int irq, err;
 
-	int err;
-
+#if 0
 	if ((err = pci_enable_device(pcidev)) != 0) {
 		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
 		return err;
 	}
-	base = pci_resource_start(pcidev, 0);
+#endif
 
 	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "ymfpci: no core\n");
@@ -2520,25 +2519,16 @@
 	codec->pci = pcidev;
 
 	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-
-	if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
-		printk(KERN_ERR "ymfpci: unable to request mem region\n");
+	
+	codec->reg_area_virt = pci_request_mmio(pcidev, 0);
+	if (!codec->reg_area_virt)
 		goto out_free;
-	}
-
-	if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
-		printk(KERN_ERR "ymfpci: unable to map registers\n");
-		goto out_release_region;
-	}
 
 	pci_set_master(pcidev);
 
-	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
-	    (char *)ent->driver_data, base, pcidev->irq);
-
 	ymfpci_aclink_reset(pcidev);
 	if (ymfpci_codec_ready(codec, 0, 1) < 0)
-		goto out_unmap;
+		goto out_release_mmio;
 
 #ifdef CONFIG_SOUND_YMFPCI_LEGACY
 	if (assigned == 0) {
@@ -2556,16 +2546,16 @@
 		goto out_disable_dsp;
 	ymf_memload(codec);
 
-	if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {
-		printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
-		    pcidev->irq);
+	irq = pci_request_irq(pcidev, ymf_interrupt, SA_SHIRQ, codec);
+	if (irq < 0) {
+		printk(KERN_ERR "ymfpci: unable to request IRQ %d\n", irq);
 		goto out_memfree;
 	}
 
 	/* register /dev/dsp */
 	if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
 		printk(KERN_ERR "ymfpci: unable to register dsp\n");
-		goto out_free_irq;
+		goto out_release_irq;
 	}
 
 	/*
@@ -2591,6 +2581,9 @@
 	}
 #endif /* CONFIG_SOUND_YMFPCI_LEGACY */
 
+	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
+	       (char *)ent->driver_data, pci_resource_start(pcidev, 0), irq);
+
 	/* put it into driver list */
 	list_add_tail(&codec->ymf_devs, &ymf_devs);
 	pci_set_drvdata(pcidev, codec);
@@ -2599,8 +2592,8 @@
 
  out_unregister_sound_dsp:
 	unregister_sound_dsp(codec->dev_audio);
- out_free_irq:
-	free_irq(pcidev->irq, codec);
+ out_release_irq:
+	pci_release_irq(pcidev, codec);
  out_memfree:
 	ymfpci_memfree(codec);
  out_disable_dsp:
@@ -2608,10 +2601,8 @@
 	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
 	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
 	ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- out_unmap:
-	iounmap(codec->reg_area_virt);
- out_release_region:
-	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
+ out_release_mmio:
+	pci_release_mmio(pcidev, 0, codec->reg_area_virt);
  out_free:
 	kfree(codec);
 	return -ENODEV;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/