[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    Re: [PATCH 2.6] DIO driver model
From:       Jochen Friedrich <jochen () scram ! de>
Date:       2004-09-30 22:25:29
Message-ID: Pine.LNX.4.58.0410010019370.3179 () localhost
[Download RAW message or body]

Hi Roman,

here is the updated patch for the driver model of the hp300 DIO bus.

Thanks for your comments!
Jochen

 drivers/dio/Makefile        |    2
 drivers/dio/dio-driver.c    |  163 +++++++++++++++++++++++++++
 drivers/dio/dio-sysfs.c     |   77 +++++++++++++
 drivers/dio/dio.c           |  209 +++++++++++------------------------
 drivers/net/Space.c         |    3
 drivers/net/hplance.c       |  126 +++++++++------------
 drivers/serial/8250_hp300.c |  259 +++++++++++++++++++++-----------------------
 drivers/video/hpfb.c        |  122 +++++++++++---------
 include/linux/dio.h         |  155 +++++++++++++++++++++++---
 9 files changed, 697 insertions(+), 419 deletions(-)

On Wed, 29 Sep 2004, Roman Zippel wrote:

> Hi,
>
> Jochen Friedrich wrote:
>
> >>There seem to be some whitespace problems. Also, please set your indent
> >>size to 8 (following the Linux kernel coding style described in
> >>Documentation/CodingStyle).
> >
> > OK, done. I have it attached this time. Hopefully the whitespace problems
> > are gone now.
>
> One more code style nitpick: Please change the if blocks to:
>
> 	if (...) {
> 		...
> 	} else {
> 		...
> 	}
>
> Otherwise it looks ok, although it might be better to post it once to
> the kernel mailing list, as there there are the people who know better
> the driver model.
["patch" (TEXT/PLAIN)]

Signed-off-by: Jochen Friedrich <jochen@scram.de>

diff -uprN -X dontdiff linux-2.6.orig/drivers/dio/Makefile linux-2.6/drivers/dio/Makefile
--- linux-2.6.orig/drivers/dio/Makefile	2004-09-26 21:11:22.000000000 +0200
+++ linux-2.6/drivers/dio/Makefile	2004-09-22 18:18:04.000000000 +0200
@@ -2,4 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-obj-y := dio.o
+obj-y := dio.o dio-driver.o dio-sysfs.o
diff -uprN -X dontdiff linux-2.6.orig/drivers/dio/dio-driver.c linux-2.6/drivers/dio/dio-driver.c
--- linux-2.6.orig/drivers/dio/dio-driver.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/drivers/dio/dio-driver.c	2004-09-29 08:42:51.000000000 +0200
@@ -0,0 +1,163 @@
+/*
+ *  DIO Driver Services
+ *
+ *  Copyright (C) 2004 Jochen Friedrich
+ *
+ *  Loosely based on drivers/pci/pci-driver.c and drivers/zorro/zorro-driver.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dio.h>
+
+
+	/**
+	 *  dio_match_device - Tell if a DIO device structure has a matching
+	 *                     DIO device id structure
+	 *  @ids: array of DIO device id structures to search in
+	 *  @dev: the DIO device structure to match against
+	 *
+	 *  Used by a driver to check whether a DIO device present in the
+	 *  system is in its list of supported devices. Returns the matching
+	 *  dio_device_id structure or %NULL if there is no match.
+	 */
+
+const struct dio_device_id *
+dio_match_device(const struct dio_device_id *ids,
+		   const struct dio_dev *d)
+{
+	while (ids->id) {
+		if (ids->id == DIO_WILDCARD)
+			return ids;
+		if (DIO_NEEDSSECID(ids->id & 0xff)) {
+			if (ids->id == d->id)
+				return ids;
+		} else {
+			if ((ids->id & 0xff) == (d->id & 0xff))
+				return ids;
+		}
+		ids++;
+	}
+	return NULL;
+}
+
+static int dio_device_probe(struct device *dev)
+{
+	int error = 0;
+	struct dio_driver *drv = to_dio_driver(dev->driver);
+	struct dio_dev *d = to_dio_dev(dev);
+
+	if (!d->driver && drv->probe) {
+		const struct dio_device_id *id;
+
+		id = dio_match_device(drv->id_table, d);
+		if (id)
+			error = drv->probe(d, id);
+		if (error >= 0) {
+			d->driver = drv;
+			error = 0;
+		}
+	}
+	return error;
+}
+
+
+	/**
+	 *  dio_register_driver - register a new DIO driver
+	 *  @drv: the driver structure to register
+	 *
+	 *  Adds the driver structure to the list of registered drivers
+	 *  Returns the number of DIO devices which were claimed by the driver
+	 *  during registration.  The driver remains registered even if the
+	 *  return value is zero.
+	 */
+
+int dio_register_driver(struct dio_driver *drv)
+{
+	int count = 0;
+
+	/* initialize common driver fields */
+	drv->driver.name = drv->name;
+	drv->driver.bus = &dio_bus_type;
+	drv->driver.probe = dio_device_probe;
+
+	/* register with core */
+	count = driver_register(&drv->driver);
+	return count ? count : 1;
+}
+
+
+	/**
+	 *  dio_unregister_driver - unregister a DIO driver
+	 *  @drv: the driver structure to unregister
+	 *
+	 *  Deletes the driver structure from the list of registered DIO drivers,
+	 *  gives it a chance to clean up by calling its remove() function for
+	 *  each device it was responsible for, and marks those devices as
+	 *  driverless.
+	 */
+
+void dio_unregister_driver(struct dio_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+
+
+	/**
+	 *  dio_bus_match - Tell if a DIO device structure has a matching DIO
+	 *                  device id structure
+	 *  @ids: array of DIO device id structures to search in
+	 *  @dev: the DIO device structure to match against
+	 *
+	 *  Used by a driver to check whether a DIO device present in the
+	 *  system is in its list of supported devices. Returns the matching
+	 *  dio_device_id structure or %NULL if there is no match.
+	 */
+
+static int dio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct dio_dev *d = to_dio_dev(dev);
+	struct dio_driver *dio_drv = to_dio_driver(drv);
+	const struct dio_device_id *ids = dio_drv->id_table;
+
+	if (!ids)
+		return 0;
+
+	while (ids->id) {
+		if (ids->id == DIO_WILDCARD)
+			return 1;
+		if (DIO_NEEDSSECID(ids->id & 0xff)) {
+			if (ids->id == d->id)
+				return 1;
+		} else {
+			if ((ids->id & 0xff) == (d->id & 0xff))
+				return 1;
+		}
+		ids++;
+	}
+	return 0;
+}
+
+
+struct bus_type dio_bus_type = {
+	.name	= "dio",
+	.match	= dio_bus_match
+};
+
+
+static int __init dio_driver_init(void)
+{
+	return bus_register(&dio_bus_type);
+}
+
+postcore_initcall(dio_driver_init);
+
+EXPORT_SYMBOL(dio_match_device);
+EXPORT_SYMBOL(dio_register_driver);
+EXPORT_SYMBOL(dio_unregister_driver);
+EXPORT_SYMBOL(dio_dev_driver);
+EXPORT_SYMBOL(dio_bus_type);
diff -uprN -X dontdiff linux-2.6.orig/drivers/dio/dio-sysfs.c linux-2.6/drivers/dio/dio-sysfs.c
--- linux-2.6.orig/drivers/dio/dio-sysfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/drivers/dio/dio-sysfs.c	2004-09-27 19:50:56.000000000 +0200
@@ -0,0 +1,77 @@
+/*
+ *  File Attributes for DIO Devices
+ *
+ *  Copyright (C) 2004 Jochen Friedrich
+ *
+ *  Loosely based on drivers/pci/pci-sysfs.c and drivers/zorro/zorro-sysfs.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/dio.h>
+#include <linux/stat.h>
+
+/* show configuration fields */
+
+static ssize_t dio_show_id(struct device *dev, char *buf)
+{
+	struct dio_dev *d;
+
+	d = to_dio_dev(dev);
+	return sprintf(buf, "0x%02x\n", (d->id & 0xff));
+}
+static DEVICE_ATTR(id, S_IRUGO, dio_show_id, NULL);
+
+static ssize_t dio_show_ipl(struct device *dev, char *buf)
+{
+	struct dio_dev *d;
+
+	d = to_dio_dev(dev);
+	return sprintf(buf, "0x%02x\n", d->ipl);
+}
+static DEVICE_ATTR(ipl, S_IRUGO, dio_show_ipl, NULL);
+
+static ssize_t dio_show_secid(struct device *dev, char *buf)
+{
+	struct dio_dev *d;
+
+	d = to_dio_dev(dev);
+	return sprintf(buf, "0x%02x\n", ((d->id >> 8)& 0xff));
+}
+static DEVICE_ATTR(secid, S_IRUGO, dio_show_secid, NULL);
+
+static ssize_t dio_show_name(struct device *dev, char *buf)
+{
+	struct dio_dev *d;
+
+	d = to_dio_dev(dev);
+	return sprintf(buf, "%s\n", d->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, dio_show_name, NULL);
+
+static ssize_t dio_show_resource(struct device *dev, char *buf)
+{
+	struct dio_dev *d = to_dio_dev(dev);
+
+	return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
+		       dio_resource_start(d), dio_resource_end(d),
+		       dio_resource_flags(d));
+}
+static DEVICE_ATTR(resource, S_IRUGO, dio_show_resource, NULL);
+
+void dio_create_sysfs_dev_files(struct dio_dev *d)
+{
+	struct device *dev = &d->dev;
+
+	/* current configuration's attributes */
+	device_create_file(dev, &dev_attr_id);
+	device_create_file(dev, &dev_attr_ipl);
+	device_create_file(dev, &dev_attr_secid);
+	device_create_file(dev, &dev_attr_name);
+	device_create_file(dev, &dev_attr_resource);
+}
+
diff -uprN -X dontdiff linux-2.6.orig/drivers/dio/dio.c linux-2.6/drivers/dio/dio.c
--- linux-2.6.orig/drivers/dio/dio.c	2004-09-26 21:11:22.000000000 +0200
+++ linux-2.6/drivers/dio/dio.c	2004-09-29 08:44:06.000000000 +0200
@@ -1,5 +1,6 @@
 /* Code to support devices on the DIO and DIO-II bus
  * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Copyright (C) 1994 Jochen Friedrich <jochen@scram.de>
  * 
  * This code has basically these routines at the moment:
  * int dio_find(u_int deviceid)
@@ -23,15 +24,26 @@
  * This file is based on the way the Amiga port handles Zorro II cards, 
  * although we aren't so complicated...
  */
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/dio.h>
 #include <linux/slab.h>                         /* kmalloc() */
-#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>                             /* readb() */
 
+struct dio_bus dio_bus = {
+	.resources = {
+		/* DIO range */
+		{ .name = "DIO mem", .start = 0x00600000, .end = 0x007fffff },
+		/* DIO-II range */
+		{ .name = "DIO-II mem", .start = 0x01000000, .end = 0x1fffffff }
+	},
+	.name = "DIO bus"
+};
+
 /* not a real config option yet! */
 #define CONFIG_DIO_CONSTANTS
 
@@ -99,30 +111,16 @@ static char dio_no_name[] = { 0 };
 
 #endif /* CONFIG_DIO_CONSTANTS */
 
-/* We represent all the DIO boards in the system with a linked list of these structs. */
-struct dioboard
+int __init dio_find(int deviceid)
 {
-        struct dioboard *next;                    /* link to next struct in list */
-        int ipl;                                  /* IPL of this board */
-        int configured;                           /* has this board been configured? */
-        int scode;                                /* select code of this board */
-        int id;                                   /* encoded ID */
-        const char *name;
-};
-
-static struct dioboard *blist = NULL;
-
-static int __init dio_find_slow(int deviceid)
-{
-	/* Called to find a DIO device before the full bus scan has run.  Basically
-	 * only used by the console driver.
+	/* Called to find a DIO device before the full bus scan has run.
+	 * Only used by the console driver.
 	 */
 	int scode, id;
 	u_char prid, secid, i;
 	mm_segment_t fs;
 
-	for (scode = 0; scode < DIO_SCMAX; scode++)
-	{
+	for (scode = 0; scode < DIO_SCMAX; scode++) {
 		void *va;
 		unsigned long pa;
 
@@ -142,8 +140,7 @@ static int __init dio_find_slow(int devi
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 
-                if (get_user(i, (unsigned char *)va + DIO_IDOFF))
-		{
+                if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
 			set_fs(fs);
 			if (scode >= DIOII_SCBASE)
 				iounmap(va);
@@ -153,16 +150,13 @@ static int __init dio_find_slow(int devi
 		set_fs(fs);
 		prid = DIO_ID(va);
 
-                if (DIO_NEEDSSECID(prid))
-                {
+                if (DIO_NEEDSSECID(prid)) {
                         secid = DIO_SECID(va);
                         id = DIO_ENCODE_ID(prid, secid);
-                }
-                else
+                } else
 			id = prid;
 
-		if (id == deviceid)
-		{
+		if (id == deviceid) {
 			if (scode >= DIOII_SCBASE)
 				iounmap(va);
 			return scode;
@@ -172,35 +166,32 @@ static int __init dio_find_slow(int devi
 	return -1;
 }
 
-int dio_find(int deviceid)
-{
-	if (blist)
-	{
-		/* fast way */
-		struct dioboard *b;
-		for (b = blist; b; b = b->next)
-			if (b->id == deviceid && b->configured == 0)
-				return b->scode;
-		return -1;
-	}
-	else
-	{
-		return dio_find_slow(deviceid);
-	}
-}
-
 /* This is the function that scans the DIO space and works out what
  * hardware is actually present.
  */
 static int __init dio_init(void)
 {
 	int scode;
-	struct dioboard *b, *bprev = NULL;
 	mm_segment_t fs;
-	char i;
-   
+	int i;
+	struct dio_dev *dev;
+
+	if (!MACH_IS_HP300)
+		return 0;
+
         printk(KERN_INFO "Scanning for DIO devices...\n");
-        
+
+	/* Initialize the DIO bus */ 
+	INIT_LIST_HEAD(&dio_bus.devices);
+	strcpy(dio_bus.dev.bus_id, "dio");
+	device_register(&dio_bus.dev);
+
+	/* Request all resources */
+	dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
+	for (i = 0; i < dio_bus.num_resources; i++)
+		request_resource(&iomem_resource, &dio_bus.resources[i]);
+
+	/* Register all devices */
         for (scode = 0; scode < DIO_SCMAX; ++scode)
         {
                 u_char prid, secid = 0;        /* primary, secondary ID bytes */
@@ -223,8 +214,7 @@ static int __init dio_init(void)
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 
-                if (get_user(i, (unsigned char *)va + DIO_IDOFF))
-		{
+                if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
 			set_fs(fs);
 			if (scode >= DIOII_SCBASE)
 				iounmap(va);
@@ -234,40 +224,40 @@ static int __init dio_init(void)
 		set_fs(fs);
 
                 /* Found a board, allocate it an entry in the list */
-                b = kmalloc(sizeof(struct dioboard), GFP_KERNEL);
+		dev = kmalloc(sizeof(struct dio_dev), GFP_KERNEL);
+		if (!dev)
+			return 0;
+
+		memset(dev, 0, sizeof(struct dio_dev));
+		dev->bus = &dio_bus;
+		dev->dev.parent = &dio_bus.dev;
+		dev->dev.bus = &dio_bus_type;
+		dev->scode = scode;
+		dev->resource.start = pa;
+		dev->resource.end = pa + DIO_SIZE(scode, va);
+		sprintf(dev->dev.bus_id,"%02x", scode);
 
                 /* read the ID byte(s) and encode if necessary. */
 		prid = DIO_ID(va);
 
-                if (DIO_NEEDSSECID(prid))
-                {
+                if (DIO_NEEDSSECID(prid)) {
                         secid = DIO_SECID(va);
-                        b->id = DIO_ENCODE_ID(prid, secid);
-                }
-                else
-                        b->id = prid;
-
-                b->configured = 0;
-                b->scode = scode;
-                b->ipl = DIO_IPL(va);
-                b->name = dio_getname(b->id);
-                printk(KERN_INFO "select code %3d: ipl %d: ID %02X", b->scode, b->ipl, prid);
+                        dev->id = DIO_ENCODE_ID(prid, secid);
+                } else
+                        dev->id = prid;
+
+                dev->ipl = DIO_IPL(va);
+                strcpy(dev->name,dio_getname(dev->id));
+                printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
                 if (DIO_NEEDSSECID(prid))
                         printk(":%02X", secid);
-                printk(": %s\n", b->name);
+                printk(": %s\n", dev->name);
 
 		if (scode >= DIOII_SCBASE)
 			iounmap(va);
-
-                b->next = NULL;
-
-                if (bprev)
-                        bprev->next = b;
-                else
-                        blist = b;
-                bprev = b;
+		device_register(&dev->dev);
+		dio_create_sysfs_dev_files(dev);
         }
-
 	return 0;
 }
 
@@ -278,77 +268,12 @@ subsys_initcall(dio_init);
  */
 unsigned long dio_scodetophysaddr(int scode)
 {
-        if (scode >= DIOII_SCBASE)
-        {
+        if (scode >= DIOII_SCBASE) {
                 return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
-        }
-        else if (scode > DIO_SCMAX || scode < 0)
+        } else if (scode > DIO_SCMAX || scode < 0)
                 return 0;
         else if (DIO_SCINHOLE(scode))
                 return 0;
 
         return (DIO_BASE + scode * DIO_DEVSIZE);
 }
-
-int dio_scodetoipl(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-
-        if (!b)
-        {
-                printk(KERN_ERR "dio_scodetoipl: bad select code %d\n", scode);
-                return 0;
-        }
-        else
-                return b->ipl;
-}
-
-const char *dio_scodetoname(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-
-        if (!b)
-        {
-                printk(KERN_ERR "dio_scodetoname: bad select code %d\n", scode);
-                return NULL;
-        }
-        else
-                return b->name;
-}
-
-void dio_config_board(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode)
-                        break;
-
-        if (!b) 
-                printk(KERN_ERR "dio_config_board: bad select code %d\n", scode);
-        else if (b->configured)
-                printk(KERN_WARNING "dio_config_board: board at select code %d already configured\n", scode);
-        else
-                b->configured = 1;
-}
-
-void dio_unconfig_board(int scode)
-{
-        struct dioboard *b;
-        for (b = blist; b; b = b->next)
-                if (b->scode == scode) 
-                        break;
-
-        if (!b) 
-                printk(KERN_ERR "dio_unconfig_board: bad select code %d\n", scode);
-        else if (!b->configured)
-                printk(KERN_WARNING "dio_unconfig_board: board at select code %d not configured\n", 
-		       scode);
-        else 
-                b->configured = 0;
-}
diff -uprN -X dontdiff linux-2.6.orig/drivers/net/Space.c linux-2.6/drivers/net/Space.c
--- linux-2.6.orig/drivers/net/Space.c	2004-09-26 21:11:24.000000000 +0200
+++ linux-2.6/drivers/net/Space.c	2004-09-24 23:01:26.000000000 +0200
@@ -284,9 +284,6 @@ static struct devprobe2 m68k_probes[] __
 #ifdef CONFIG_ATARI_PAMSNET	/* Atari PAMsNet Ethernet board */
 	{pamsnet_probe, 0},
 #endif
-#ifdef CONFIG_HPLANCE		/* HP300 internal Ethernet */
-	{hplance_probe, 0},
-#endif
 #ifdef CONFIG_MVME147_NET	/* MVME147 internal Ethernet */
 	{mvme147lance_probe, 0},
 #endif
diff -uprN -X dontdiff linux-2.6.orig/drivers/net/hplance.c linux-2.6/drivers/net/hplance.c
--- linux-2.6.orig/drivers/net/hplance.c	2004-09-26 21:11:24.000000000 +0200
+++ linux-2.6/drivers/net/hplance.c	2004-09-29 08:39:39.000000000 +0200
@@ -40,8 +40,7 @@
 
 /* Our private data structure */
 struct hplance_private {
-  struct lance_private lance;
-  unsigned int scode;
+	struct lance_private lance;
 };
 
 /* function prototypes... This is easy because all the grot is in the
@@ -49,76 +48,71 @@ struct hplance_private {
  * plus board-specific init, open and close actions. 
  * Oh, and we need to tell the generic code how to read and write LANCE registers...
  */
-static void hplance_init(struct net_device *dev, int scode);
-static int hplance_open(struct net_device *dev);
-static int hplance_close(struct net_device *dev);
+static int __devinit hplance_init_one(struct dio_dev *d,
+				const struct dio_device_id *ent);
+static void __devinit hplance_init(struct net_device *dev, 
+				struct dio_dev *d);
+static void __devexit hplance_remove_one(struct dio_dev *d);
 static void hplance_writerap(void *priv, unsigned short value);
 static void hplance_writerdp(void *priv, unsigned short value);
 static unsigned short hplance_readrdp(void *priv);
+static int hplance_open(struct net_device *dev);
+static int hplance_close(struct net_device *dev);
 
-#ifdef MODULE
-static struct hplance_private *root_hplance_dev;
-#endif
+static struct dio_device_id hplance_dio_tbl[] = {
+	{ DIO_ID_LAN },
+	{ 0 }
+};
 
-static void cleanup_card(struct net_device *dev)
-{
-        struct hplance_private *lp = netdev_priv(dev);
-	dio_unconfig_board(lp->scode);
-}
+static struct dio_driver hplance_driver = {
+	.name      = "hplance",
+	.id_table  = hplance_dio_tbl,
+	.probe     = hplance_init_one,
+	.remove    = __devexit_p(hplance_remove_one),
+};
 
 /* Find all the HP Lance boards and initialise them... */
-struct net_device * __init hplance_probe(int unit)
+static int __devinit hplance_init_one(struct dio_dev *d,
+				const struct dio_device_id *ent)
 {
 	struct net_device *dev;
-
-        if (!MACH_IS_HP300)
-                return ERR_PTR(-ENODEV);
+	int err;
 
 	dev = alloc_etherdev(sizeof(struct hplance_private));
 	if (!dev)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
+	if (!request_mem_region(d->resource.start, d->resource.end-d->resource.start, d->name))
+		return -EBUSY;
 
 	SET_MODULE_OWNER(dev);
         
-        /* Isn't DIO nice? */
-        for(;;)
-        {
-                int scode = dio_find(DIO_ID_LAN);
-                                
-                if (scode < 0)
-                        break;
-                
-		dio_config_board(scode);
-                hplance_init(dev, scode);
-		if (!register_netdev(dev)) {
-#ifdef MODULE
-			struct hplance_private *lp = netdev_priv(dev);
-			lp->next_module = root_hplance_dev;
-			root_hplance_dev = lp;
-#endif
-			return dev;
-		}
-		cleanup_card(dev);
-        }
+	hplance_init(dev, d);
+	err = register_netdev(dev);
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+	dio_set_drvdata(d, dev);
+	return 0;
+}
+
+static void __devexit hplance_remove_one(struct dio_dev *d)
+{
+	struct net_device *dev = dio_get_drvdata(d);
+
+	unregister_netdev(dev);
 	free_netdev(dev);
-	return ERR_PTR(-ENODEV);
 }
 
-/* Initialise a single lance board at the given select code */
-static void __init hplance_init(struct net_device *dev, int scode)
+/* Initialise a single lance board at the given DIO device */
+static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
 {
-        const char *name = dio_scodetoname(scode);
-	unsigned long pa = dio_scodetophysaddr(scode);
-        unsigned long va = (pa + DIO_VIRADDRBASE);
+        unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
         struct hplance_private *lp;
         int i;
         
-        printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, name, scode);
+        printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
 
         /* reset the board */
         out_8(va+DIO_IDOFF, 0xff);
@@ -136,8 +130,7 @@ static void __init hplance_init(struct n
         dev->set_multicast_list = &lance_set_multicast;
         dev->dma = 0;
         
-        for (i=0; i<6; i++)
-        {
+        for (i=0; i<6; i++) {
                 /* The NVRAM holds our ethernet address, one nibble per byte,
                  * at bytes NVRAMOFF+1,3,5,7,9...
                  */
@@ -147,12 +140,12 @@ static void __init hplance_init(struct n
         }
         
         lp = netdev_priv(dev);
-        lp->lance.name = (char*)name;                   /* discards const, shut up gcc */
+        lp->lance.name = (char*)d->name;                /* discards const, shut up gcc */
         lp->lance.base = va;
         lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
         lp->lance.lance_init_block = 0;                 /* LANCE addr of same RAM */
         lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
-        lp->lance.irq = dio_scodetoipl(scode);
+        lp->lance.irq = d->ipl;
         lp->lance.writerap = hplance_writerap;
         lp->lance.writerdp = hplance_writerdp;
         lp->lance.readrdp = hplance_readrdp;
@@ -160,7 +153,6 @@ static void __init hplance_init(struct n
         lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
         lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
         lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
-        lp->scode = scode;
 	printk(", irq %d\n", lp->lance.irq);
 }
 
@@ -216,27 +208,17 @@ static int hplance_close(struct net_devi
         return 0;
 }
 
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-int init_module(void)
+int __init hplance_init_module(void)
 {
-	int found = 0;
-	while (!IS_ERR(hplance_probe(-1)))
-		found++;
-	return found ? 0 : -ENODEV;
+	return dio_module_init(&hplance_driver);
 }
 
-void cleanup_module(void)
+void __exit hplance_cleanup_module(void)
 {
-        /* Walk the chain of devices, unregistering them */
-        struct hplance_private *lp;
-        while (root_hplance_dev) {
-                lp = root_hplance_dev->next_module;
-                unregister_netdev(root_lance_dev->dev);
-                cleanup_card(root_lance_dev->dev);
-                free_netdev(root_lance_dev->dev);
-                root_lance_dev = lp;
-        }
+        dio_unregister_driver(&hplance_driver);
 }
 
-#endif /* MODULE */
+module_init(hplance_init_module);
+module_exit(hplance_cleanup_module);
+
+MODULE_LICENSE("GPL");
diff -uprN -X dontdiff linux-2.6.orig/drivers/serial/8250_hp300.c linux-2.6/drivers/serial/8250_hp300.c
--- linux-2.6.orig/drivers/serial/8250_hp300.c	2004-09-26 21:11:26.000000000 +0200
+++ linux-2.6/drivers/serial/8250_hp300.c	2004-09-29 08:40:27.000000000 +0200
@@ -22,17 +22,40 @@
 #warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
 #endif
 
+#ifdef CONFIG_HPAPCI
 struct hp300_port
 {
 	struct hp300_port *next;	/* next port */
-	unsigned long dio_base;		/* start of DIO registers */
-	int scode;                      /* select code of this board */
 	int line;			/* line (tty) number */
 };
 
-extern int hp300_uart_scode;
-
 static struct hp300_port *hp300_ports;
+#endif
+
+#ifdef CONFIG_HPDCA
+
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                const struct dio_device_id *ent);
+static void __devexit hpdca_remove_one(struct dio_dev *d);
+
+static struct dio_device_id hpdca_dio_tbl[] = {
+	{ DIO_ID_DCA0 },
+	{ DIO_ID_DCA0REM },
+	{ DIO_ID_DCA1 },
+	{ DIO_ID_DCA1REM },
+	{ 0 }
+};
+
+static struct dio_driver hpdca_driver = {
+	.name      = "hpdca",
+	.id_table  = hpdca_dio_tbl,
+	.probe     = hpdca_init_one,
+	.remove    = __devexit_p(hpdca_remove_one),
+};
+
+#endif
+
+extern int hp300_uart_scode;
 
 /* Offset to UART registers from base of DCA */
 #define UART_OFFSET	17
@@ -73,7 +96,10 @@ int __init hp300_setup_serial_console(vo
 
 	memset(&port, 0, sizeof(port));
 
-	if (hp300_uart_scode < 0 || hp300_uart_scode > 256)
+	if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
+		return 0;
+
+	if (DIO_SCINHOLE(hp300_uart_scode))
 		return 0;
 
 	scode = hp300_uart_scode;
@@ -84,8 +110,7 @@ int __init hp300_setup_serial_console(vo
 	port.type = PORT_UNKNOWN;
 
 	/* Check for APCI console */
-	if (scode == 256)
-	{
+	if (scode == 256) {
 #ifdef CONFIG_HPAPCI
 		printk(KERN_INFO "Serial console is HP APCI 1\n");
 
@@ -99,8 +124,7 @@ int __init hp300_setup_serial_console(vo
 		return 0;
 #endif
 	}
-	else
-	{
+	else {
 #ifdef CONFIG_HPDCA
 		unsigned long pa = dio_scodetophysaddr(scode);
 		if (!pa) {
@@ -135,47 +159,89 @@ int __init hp300_setup_serial_console(vo
 }
 #endif /* CONFIG_SERIAL_8250_CONSOLE */
 
+#ifdef CONFIG_HPDCA
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                const struct dio_device_id *ent)
+{
+	struct serial_struct serial_req;
+	int line;
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+	if (hp300_uart_scode == d->scode) {
+		/* Already got it. */
+		return 0;
+	}
+#endif
+	memset(&serial_req, 0, sizeof(struct serial_struct));
+
+	/* Memory mapped I/O */
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+	serial_req.irq = d->ipl;
+	serial_req.baud_base = HPDCA_BAUD_BASE;
+	serial_req.iomap_base = (d->resource.start + UART_OFFSET);
+	serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
+	serial_req.iomem_reg_shift = 1;
+	line = register_serial(&serial_req);
+
+	if (line < 0) {
+		printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
+		       " irq %d failed\n", d->scode, serial_req.irq);
+		return -ENOMEM;
+	}
+
+	/* Enable board-interrupts */
+	out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+	dio_set_drvdata(d, (void *)line);
+
+	/* Reset the DCA */
+	out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
+	udelay(100);
+
+	return 0;
+}
+#endif
+
 static int __init hp300_8250_init(void)
 {
 	static int called = 0;
-#ifdef CONFIG_HPDCA
-	int scode;
-#endif
-	int line, num_ports;
+	int num_ports;
+#ifdef CONFIG_HPAPCI
+	int line;
 	unsigned long base;
 	struct serial_struct serial_req;
 	struct hp300_port *port;
-
+	int i;
+#endif
 	if (called)
 		return -ENODEV;
 	called = 1;
-	num_ports = 0;
 
-	if (!MACH_IS_HP300) {
+	if (!MACH_IS_HP300)
 		return -ENODEV;
-	}
 
-#ifdef CONFIG_HPDCA
-	while (1) {
-                /* We detect boards by looking for DIO boards which match a
-                 * given subset of IDs. dio_find() returns the board's scancode.
-                 * The scancode to physaddr mapping is a property of the hardware,
-                 * as is the scancode to IPL (interrupt priority) mapping.
-                 */
-                scode = dio_find(DIO_ID_DCA0);
-                if (scode < 0)
-			scode = dio_find(DIO_ID_DCA0REM);
-                if (scode < 0)
-			scode = dio_find(DIO_ID_DCA1);
-                if (scode < 0)
-			scode = dio_find(DIO_ID_DCA1REM);
-                if (scode < 0)
-			break;		/* no, none at all */
+	num_ports = 0;
 
+#ifdef CONFIG_HPDCA
+	if (dio_module_init(&hpdca_driver) == 0)
+		num_ports++;
+#endif
+#ifdef CONFIG_HPAPCI
+	if (hp300_model < HP_400) {
+		if (!num_ports)
+			return -ENODEV;
+		return 0;
+	}
+	/* These models have the Frodo chip.
+	 * Port 0 is reserved for the Apollo Domain keyboard.
+	 * Port 1 is either the console or the DCA.
+	 */
+	for (i = 1; i < 4; i++) {
+		/* Port 1 is the console on a 425e, on other machines it's mapped to
+		 * DCA.
+		 */
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-		if (hp300_uart_scode == scode) {
-			/* Already got it */
-			dio_config_board(scode);
+		if (i == 1) {
 			continue;
 		}
 #endif
@@ -186,109 +252,33 @@ static int __init hp300_8250_init(void)
 			return -ENOMEM;
 
 		memset(&serial_req, 0, sizeof(struct serial_struct));
-		
-		base = dio_scodetophysaddr(scode);
 
-                /* If we want to tell the DIO code that this board is configured,
-                 * we should do that here.
-                 */
-                dio_config_board(scode);
+		base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
 
 		/* Memory mapped I/O */
 		serial_req.io_type = SERIAL_IO_MEM;
 		serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-		serial_req.irq = dio_scodetoipl(scode);
-		serial_req.baud_base = HPDCA_BAUD_BASE;
-		serial_req.iomap_base = (base + UART_OFFSET);
+		/* XXX - no interrupt support yet */
+		serial_req.irq = 0;
+		serial_req.baud_base = HPAPCI_BAUD_BASE;
+		serial_req.iomap_base = base;
 		serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
-		serial_req.iomem_reg_shift = 1;
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-		if (hp300_uart_scode != scode) {
-#endif
-                /* Reset the DCA */
-                out_8(base + DIO_VIRADDRBASE + DCA_ID, 0xff);
-                udelay(100);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-		}
-#endif
+		serial_req.iomem_reg_shift = 2;
 
 		line = register_serial(&serial_req);
 
 		if (line < 0) {
-			printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
-			       " irq %d failed\n", scode, serial_req.irq);
+			printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
+			       " irq %d failed\n", i, serial_req.irq);
 			kfree(port);
 			continue;
 		}
 
-		/* Enable board-interrupts */
-		out_8(base + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
-
-		port->dio_base = base + DIO_VIRADDRBASE;
-		port->scode = scode;
 		port->line = line;
 		port->next = hp300_ports;
 		hp300_ports = port;
 
 		num_ports++;
-        }
-#endif
-
-#ifdef CONFIG_HPAPCI
-	if (hp300_model >= HP_400)
-	{
-		int i;
-
-		/* These models have the Frodo chip.
-		 * Port 0 is reserved for the Apollo Domain keyboard.
-		 * Port 1 is either the console or the DCA.
-		 */
-		for (i = 1; i < 4; i++) {
-			/* Port 1 is the console on a 425e, on other machines it's mapped to
-			 * DCA.
-			 */
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-			if (i == 1) {
-				continue;
-			}
-#endif
-
-			/* Create new serial device */
-			port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
-			if (!port)
-				return -ENOMEM;
-
-			memset(&serial_req, 0, sizeof(struct serial_struct));
-
-			base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
-
-			/* Memory mapped I/O */
-			serial_req.io_type = SERIAL_IO_MEM;
-			serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
-			/* XXX - no interrupt support yet */
-			serial_req.irq = 0;
-			serial_req.baud_base = HPAPCI_BAUD_BASE;
-			serial_req.iomap_base = base;
-			serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
-			serial_req.iomem_reg_shift = 2;
-
-			line = register_serial(&serial_req);
-
-			if (line < 0) {
-				printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
-				       " irq %d failed\n", i, serial_req.irq);
-				kfree(port);
-				continue;
-			}
-
-			port->dio_base = 0;
-			port->line = line;
-			port->next = hp300_ports;
-			hp300_ports = port;
-
-			num_ports++;
-		}
 	}
 #endif
 
@@ -299,28 +289,37 @@ static int __init hp300_8250_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_HPDCA
+static void __devexit hpdca_remove_one(struct dio_dev *d)
+{
+	int line;
+
+	line = (int) dio_get_drvdata(d);
+	if (d->resource.start) {
+		/* Disable board-interrupts */
+		out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
+	}
+	unregister_serial(line);
+}
+#endif
+
 static void __exit hp300_8250_exit(void)
 {
+#ifdef CONFIG_HPAPCI
 	struct hp300_port *port, *to_free;
 
 	for (port = hp300_ports; port; ) {
 		unregister_serial(port->line);
-
-#ifdef CONFIG_HPDCA
-		if (port->dio_base) {
-			/* Disable board-interrupts */
-			out_8(port->dio_base + DCA_IC, 0);
-
-			dio_unconfig_board(port->scode);
-		}
-#endif
-
 		to_free = port;
 		port = port->next;
 		kfree(to_free);
 	}
 
 	hp300_ports = NULL;
+#endif
+#ifdef CONFIG_HPDCA
+	dio_unregister_driver(&hpdca_driver);
+#endif
 }
 
 module_init(hp300_8250_init);
diff -uprN -X dontdiff linux-2.6.orig/drivers/video/hpfb.c linux-2.6/drivers/video/hpfb.c
--- linux-2.6.orig/drivers/video/hpfb.c	2004-09-26 21:11:27.000000000 +0200
+++ linux-2.6/drivers/video/hpfb.c	2004-09-29 08:41:54.000000000 +0200
@@ -127,14 +127,12 @@ static int hpfb_blank(int blank, struct 
 
 static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
 {
-	if (rr >= 0)
-	{
+	if (rr >= 0) {
 		while (in_8(fb_regs + BUSY) & fb_bitmask)
 			;
 	}
 	out_8(fb_regs + TC_FBEN, fb_bitmask);
-	if (rr >= 0)
-	{
+	if (rr >= 0) {
 		out_8(fb_regs + TC_WEN, fb_bitmask);
 		out_8(fb_regs + WMRR, rr);
 	}
@@ -221,13 +219,11 @@ static int __init hpfb_init_one(unsigned
 
 	fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);
 
-	if (phys_base >= DIOII_BASE)
-	{
+	if (phys_base >= DIOII_BASE) {
 		fb_info.fix.smem_start += phys_base;
 	}
 
-	if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT)
-	{
+	if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
 		/* This is the magic incantation the HP X server uses to make Catseye boards work. */
 		while (in_be16(fb_regs+0x4800) & 1)
 			;
@@ -299,8 +295,7 @@ static int __init hpfb_init_one(unsigned
 
 	fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
 
-	if (register_framebuffer(&fb_info) < 0)
-	{
+	if (register_framebuffer(&fb_info) < 0) {
 		fb_dealloc_cmap(&fb_info.cmap);
 		return 1;
 	}
@@ -322,6 +317,51 @@ static int __init hpfb_init_one(unsigned
 /* 
  * Initialise the framebuffer
  */
+static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
+{
+	unsigned long paddr, vaddr;
+
+	paddr = d->resource.start;
+	if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
+                return -EBUSY;
+
+	if (d->scode >= DIOII_SCBASE) {
+		vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
+	} else {
+		vaddr = paddr + DIO_VIRADDRBASE;
+	}
+	printk(KERN_INFO "Topcat found at DIO select code %d "
+	       "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
+	if (hpfb_init_one(paddr, vaddr)) {
+		if (d->scode >= DIOII_SCBASE)
+			iounmap((void *)vaddr);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __devexit hpfb_remove_one(struct dio_dev *d)
+{
+	unregister_framebuffer(&fb_info);
+	if (d->scode >= DIOII_SCBASE)
+		iounmap((void *)fb_regs);
+        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
+}
+
+static struct dio_device_id hpfb_dio_tbl[] = {
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
+    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
+    { 0 }
+};
+
+static struct dio_driver hpfb_driver = {
+    .name      = "hpfb",
+    .id_table  = hpfb_dio_tbl,
+    .probe     = hpfb_dio_probe,
+    .remove    = __devexit_p(hpfb_remove_one),
+};
 
 int __init hpfb_init(void)
 {
@@ -344,62 +384,32 @@ int __init hpfb_init(void)
 	if (!MACH_IS_HP300)
 		return -ENXIO;
 
+	dio_module_init(&hpfb_driver);
+
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
 	set_fs(fs);
 
-	if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR)))
-	{
+	if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
+		if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
+			return -EBUSY;
 		printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
-		if (hpfb_init_one(INTFBPADDR, INTFBVADDR))
-		{
+		if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
 			return -ENOMEM;
 		}
 	}
-	else
-	{
-		int sc, size;
-		unsigned long paddr, vaddr;
-
-		if ((sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE))) < 0 &&
-		    (sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE))) < 0 &&
-		    (sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE))) < 0 &&
-		    (sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT))) < 0)
-		{
-			return -ENXIO;
-		}
-
-		dio_config_board(sc);
-		paddr = dio_scodetophysaddr(sc);
-
-		if (sc >= DIOII_SCBASE)
-		{
-			/* To find out the real size of the device we first need to map it. */
-			vaddr = (unsigned long)ioremap(paddr, PAGE_SIZE);
-			size = DIO_SIZE(sc, vaddr);
-			iounmap((void *)vaddr);
-			vaddr = (unsigned long)ioremap(paddr, size);
-		}
-		else
-		{
-			vaddr = paddr + DIO_VIRADDRBASE;
-			size = DIO_SIZE(sc, vaddr);
-		}
-		sid = DIO_SECID(vaddr);
-
-		printk(KERN_INFO "Topcat found at DIO select code %d "
-		       "(secondary id %02x)\n", sc, sid);
-		if (hpfb_init_one(paddr, vaddr))
-		{
-			if (sc >= DIOII_SCBASE)
-				iounmap((void *)vaddr);
-			dio_unconfig_board(sc);
-			return -ENOMEM;
-		}
-	}
-
 	return 0;
 }
 
+void __exit hpfb_cleanup_module(void)
+{
+	dio_unregister_driver(&hpfb_driver);
+}
+
+#ifdef MODULE
+module_init(hpfb_init);
+#endif
+module_exit(hpfb_cleanup_module);
+
 MODULE_LICENSE("GPL");
diff -uprN -X dontdiff linux-2.6.orig/include/linux/dio.h linux-2.6/include/linux/dio.h
--- linux-2.6.orig/include/linux/dio.h	2004-09-26 21:11:35.000000000 +0200
+++ linux-2.6/include/linux/dio.h	2004-09-27 19:48:52.000000000 +0200
@@ -3,11 +3,12 @@
  * The general structure of this is vaguely based on how
  * the Amiga port handles Zorro boards.
  * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ * Converted to driver model Jochen Friedrich <jochen@scram.de>
  *
  * The board IDs are from the NetBSD kernel, which for once provided
  * helpful comments...
  *
- * This goes with arch/m68k/hp300/dio.c
+ * This goes with drivers/dio/dio.c
  */
 
 #ifndef _LINUX_DIO_H
@@ -27,18 +28,80 @@
  * so currently we just don't handle DIO-II boards.  It wouldn't be hard to 
  * do with ioremap() though.
  */
+
+#include <linux/device.h>
+
 #ifdef __KERNEL__
 
 #include <asm/hp300hw.h>
 
+typedef __u16 dio_id;
+
+    /*
+     *  DIO devices
+     */
+
+struct dio_dev {
+	struct dio_bus *bus;
+	dio_id id;
+	int scode;
+	struct dio_driver *driver;	/* which driver has allocated this device */
+	struct device dev;		/* Generic device interface */
+	u8 ipl;
+	char name[64];
+	struct resource resource;
+};
+
+#define to_dio_dev(n) container_of(n, struct dio_dev, dev)
+
+    /*
+     *  DIO bus
+     */
+
+struct dio_bus {
+	struct list_head devices;           /* list of devices on this bus */
+	unsigned int num_resources;         /* number of resources */
+	struct resource resources[2];       /* address space routed to this bus */
+	struct device dev;
+	char name[10];
+};
+
+extern struct dio_bus dio_bus;      /* Single DIO bus */
+extern struct bus_type dio_bus_type;
+
+    /*
+     *  DIO device IDs
+     */
+
+struct dio_device_id {
+	dio_id id;                    /* Device ID or DIO_WILDCARD */
+	unsigned long driver_data;    /* Data private to the driver */
+};
+
+    /*
+     *  DIO device drivers
+     */
+
+struct dio_driver {
+	struct list_head node;
+	char *name;
+	const struct dio_device_id *id_table;     /* NULL if wants all devices */
+	int (*probe)(struct dio_dev *z, const struct dio_device_id *id);
+/* New device inserted */
+	void (*remove)(struct dio_dev *z);        /* Device removed (NULL if not a hot-plug capable driver) */
+	struct device_driver driver;
+};
+
+#define to_dio_driver(drv)    container_of(drv, struct dio_driver, driver)
+
 /* DIO/DIO-II boards all have the following 8bit registers.
  * These are offsets from the base of the device.
  */
-#define DIO_IDOFF     0x01                        /* primary device ID */
-#define DIO_IPLOFF    0x03                        /* interrupt priority level */
-#define DIO_SECIDOFF  0x15                        /* secondary device ID */
-#define DIOII_SIZEOFF 0x101                       /* device size, DIO-II only */
-#define DIO_VIRADDRBASE 0xf0000000UL              /* vir addr where IOspace is mapped */
+#define DIO_IDOFF     0x01             /* primary device ID */
+#define DIO_IPLOFF    0x03             /* interrupt priority level */
+#define DIO_SECIDOFF  0x15             /* secondary device ID */
+#define DIOII_SIZEOFF 0x101            /* device size, DIO-II only */
+#define DIO_VIRADDRBASE 0xf0000000UL   /* vir addr where IOspace is mapped */
 
 #define DIO_BASE                0x600000        /* start of DIO space */
 #define DIO_END                 0x1000000       /* end of DIO space */
@@ -79,6 +142,7 @@
 #define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) | ((int)pr & 0xff))
 /* macro to determine whether a given primary ID requires a secondary ID byte */
 #define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+#define DIO_WILDCARD 0xff
 
 /* Now a whole slew of macros giving device IDs and descriptive strings: */
 #define DIO_ID_DCA0     0x02 /* 98644A serial */
@@ -99,14 +163,14 @@
 #define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
 #define DIO_ID_NHPIB    0x01 /* 98624A HP-IB (normal ie slow) */
 #define DIO_DESC_NHPIB "98624A HPIB"
-#define DIO_ID_SCSI0    0x07 /* 98625A SCSI */
-#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI0    0x07 /* 98265A SCSI */
+#define DIO_DESC_SCSI0 "98265A SCSI0"
 #define DIO_ID_SCSI1    0x27 /* ditto */
-#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_DESC_SCSI1 "98265A SCSI1"
 #define DIO_ID_SCSI2    0x47 /* ditto */
-#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_DESC_SCSI2 "98265A SCSI2"
 #define DIO_ID_SCSI3    0x67 /* ditto */
-#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_DESC_SCSI3 "98265A SCSI3"
 #define DIO_ID_FBUFFER  0x39 /* framebuffer: flavour is distinguished by secondary ID */
 #define DIO_DESC_FBUFFER "bitmapped display"
 /* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
@@ -177,11 +241,72 @@
 
 extern int dio_find(int deviceid);
 extern unsigned long dio_scodetophysaddr(int scode);
-extern int dio_scodetoipl(int scode);
-extern const char *dio_scodetoname(int scode);
-extern void dio_config_board(int scode);
-extern void dio_unconfig_board(int scode);
+extern void dio_create_sysfs_dev_files(struct dio_dev *);
+
+/* New-style probing */
+extern int dio_register_driver(struct dio_driver *);
+extern void dio_unregister_driver(struct dio_driver *);
+extern const struct dio_device_id *dio_match_device(const struct dio_device_id *ids, const struct dio_dev *z);
+static inline struct dio_driver *dio_dev_driver(const struct dio_dev *d)
+{
+    return d->driver;
+}
+
+#define dio_resource_start(d) ((d)->resource.start)
+#define dio_resource_end(d)   ((d)->resource.end)
+#define dio_resource_len(d)   ((d)->resource.end-(z)->resource.start+1)
+#define dio_resource_flags(d) ((d)->resource.flags)
+
+#define dio_request_device(d, name) \
+    request_mem_region(dio_resource_start(d), dio_resource_len(d), name)
+#define dio_release_device(d) \
+    release_mem_region(dio_resource_start(d), dio_resource_len(d))
+
+/* Similar to the helpers above, these manipulate per-dio_dev
+ * driver-specific data.  They are really just a wrapper around
+ * the generic device structure functions of these calls.
+ */
+static inline void *dio_get_drvdata (struct dio_dev *d)
+{
+	return dev_get_drvdata(&d->dev);
+}
+
+static inline void dio_set_drvdata (struct dio_dev *d, void *data)
+{
+	dev_set_drvdata(&d->dev, data);
+}
+
+/*
+ * A helper function which helps ensure correct dio_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+static inline int dio_module_init(struct dio_driver *drv)
+{
+	int rc = dio_register_driver(drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* iff CONFIG_HOTPLUG and built into kernel, we should
+	 * leave the driver around for future hotplug events.
+	 * For the module case, a hotplug daemon of some sort
+	 * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+	if (rc == 0)
+		return 0;
+#else
+	if (rc == 0)
+		rc = -ENODEV;
+#endif
+
+	/* if we get here, we need to clean up DIO driver instance
+	 * and return some sort of error */
+	dio_unregister_driver(drv);
 
+	return rc;
+}
 
 #endif /* __KERNEL__ */
 #endif /* ndef _LINUX_DIO_H */

-
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/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic