diff options
author | peter <peter@FreeBSD.org> | 1999-04-18 15:50:35 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-04-18 15:50:35 +0000 |
commit | d31d6be6f69b97664f49ea66dc3e371f78b96da7 (patch) | |
tree | 1e02bc4ef3b26a4288796ff2f42370aa037dfed9 /sys/dev/eisa | |
parent | dfb16d4177a39907c05c263200214aca2caaa824 (diff) | |
download | FreeBSD-src-d31d6be6f69b97664f49ea66dc3e371f78b96da7.zip FreeBSD-src-d31d6be6f69b97664f49ea66dc3e371f78b96da7.tar.gz |
Implement an EISA new-bus framework. The old driver probe mechanism
had a quirk that made a shim rather hard to implement properly and it was
just easier to convert the drivers in one go. The changes to the
buslogic driver go beyond just this - the whole driver was new-bus'ed
including pci and isa. I have only tested the EISA part of this so far.
Submitted by: Doug Rabson <dfr@nlsystems.com>
Diffstat (limited to 'sys/dev/eisa')
-rw-r--r-- | sys/dev/eisa/eisaconf.c | 490 | ||||
-rw-r--r-- | sys/dev/eisa/eisaconf.h | 101 |
2 files changed, 357 insertions, 234 deletions
diff --git a/sys/dev/eisa/eisaconf.c b/sys/dev/eisa/eisaconf.c index e1eee61..d7781d9 100644 --- a/sys/dev/eisa/eisaconf.c +++ b/sys/dev/eisa/eisaconf.c @@ -28,55 +28,64 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: eisaconf.c,v 1.36 1998/12/04 22:54:46 archie Exp $ + * $Id: eisaconf.c,v 1.37 1999/01/14 06:22:03 jdp Exp $ */ #include "opt_eisa.h" #include <sys/param.h> #include <sys/systm.h> -#include <sys/linker_set.h> +#include <sys/queue.h> #include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> #include <machine/limits.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> #include <i386/eisa/eisaconf.h> #include <sys/interrupt.h> -struct eisa_device_node{ - struct eisa_device dev; - struct eisa_device_node *next; +typedef struct resvaddr { + u_long addr; /* start address */ + u_long size; /* size of reserved area */ + int flags; + struct resource *res; /* resource manager handle */ + LIST_ENTRY(resvaddr) links; /* List links */ +} resvaddr_t; + +LIST_HEAD(resvlist, resvaddr); + +struct irq_node { + int irq_no; + void *idesc; + TAILQ_ENTRY(irq_node) links; }; -/* - * This should probably be a list of "struct device" once it exists. - * A struct device will incorperate ioconf and driver entry point data - * regardless of how its attached to the system (via unions) as well - * as more generic information that all device types should support (unit - * number, if its installed, etc). - */ -static struct eisa_device_node *eisa_dev_list; -static struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list; -static u_long eisa_unit; - -static struct eisa_driver mainboard_drv = { - "eisa", - NULL, - NULL, - NULL, - &eisa_unit - }; +TAILQ_HEAD(irqlist, irq_node); + +struct eisa_ioconf { + int slot; + struct resvlist ioaddrs; /* list of reserved I/O ranges */ + struct resvlist maddrs; /* list of reserved memory ranges */ + struct irqlist irqs; /* list of reserved irqs */ +}; + +/* To be replaced by the "super device" generic device structure... */ +struct eisa_device { + eisa_id_t id; + struct eisa_ioconf ioconf; +}; -/* - * Add the mainboard_drv to the eisa driver linkerset so that it is - * defined even if no EISA drivers are linked into the kernel. - */ -DATA_SET (eisadriver_set, mainboard_drv); /* * Local function declarations and static variables */ +#if 0 static void eisa_reg_print __P((struct eisa_device *e_dev, char *string, char *separator)); static int eisa_add_resvaddr __P((struct eisa_device *e_dev, @@ -85,7 +94,9 @@ static int eisa_add_resvaddr __P((struct eisa_device *e_dev, static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, struct resvlist *head, resvaddr_t *resvaddr, int *reg_count)); +#endif +#if 0 /* * Keep some state about what we've printed so far * to make probe output pretty. @@ -98,29 +109,77 @@ static struct { int column; /* How much we have output so far. */ #define MAX_COL 80 } reg_state; +#endif /* Global variable, so UserConfig can change it. */ #ifndef EISA_SLOTS #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ #endif int num_eisa_slots = EISA_SLOTS; + +static devclass_t eisa_devclass; + +static int +mainboard_probe(device_t dev) +{ + char *idstring; + eisa_id_t id = eisa_get_id(dev); + + if (eisa_get_slot(dev) != 0) + return (ENXIO); + + idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1, + M_DEVBUF, M_NOWAIT); + if (idstring == NULL) { + panic("Eisa probe unable to malloc"); + } + sprintf(idstring, "%c%c%c%x%x (System Board)", + EISA_MFCTR_CHAR0(id), + EISA_MFCTR_CHAR1(id), + EISA_MFCTR_CHAR2(id), + EISA_PRODUCT_ID(id), + EISA_REVISION_ID(id)); + device_set_desc(dev, idstring); + + return (0); +} + +static int +mainboard_attach(device_t dev) +{ + return (0); +} + +static device_method_t mainboard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, mainboard_probe), + DEVMETHOD(device_attach, mainboard_attach), + + { 0, 0 } +}; + +static driver_t mainboard_driver = { + "mainboard", + mainboard_methods, + DRIVER_TYPE_MISC, + 1, +}; + +static devclass_t mainboard_devclass; + +DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0); /* ** probe for EISA devices */ -void -eisa_configure() +static int +eisa_probe(device_t dev) { int i,slot; - struct eisa_device_node *dev_node; - struct eisa_driver **e_drvp; - struct eisa_driver *e_drv; struct eisa_device *e_dev; int eisaBase = 0xc80; eisa_id_t eisa_id; - e_drvp = (struct eisa_driver**)eisadriver_set.ls_items; - for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) { int id_size = sizeof(eisa_id); eisa_id = 0; @@ -132,19 +191,16 @@ eisa_configure() continue; /* no EISA card in slot */ /* Prepare an eisa_device_node for this slot */ - dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node), - M_DEVBUF, M_NOWAIT); - if (!dev_node) { - printf("eisa0: cannot malloc eisa_device_node"); + e_dev = (struct eisa_device *)malloc(sizeof(*e_dev), + M_DEVBUF, M_NOWAIT); + if (!e_dev) { + printf("eisa0: cannot malloc eisa_device"); break; /* Try to attach what we have already */ } - bzero(dev_node, sizeof(*dev_node)); - e_dev = &(dev_node->dev); + bzero(e_dev, sizeof(*e_dev)); e_dev->id = eisa_id; - e_dev->full_name = "Unattached Device"; - e_dev->ioconf.slot = slot; /* Initialize our lists of reserved addresses */ @@ -152,134 +208,202 @@ eisa_configure() LIST_INIT(&(e_dev->ioconf.maddrs)); TAILQ_INIT(&(e_dev->ioconf.irqs)); - *eisa_dev_list_tail = dev_node; - eisa_dev_list_tail = &dev_node->next; + device_add_child(dev, NULL, -1, e_dev); } - dev_node = eisa_dev_list; + return 0; +} - /* - * "Attach" the system board - */ +static void +eisa_print_child(device_t dev, device_t child) +{ + /* XXX print resource descriptions? */ + printf(" at slot %d", eisa_get_slot(child)); + printf(" on %s", device_get_nameunit(dev)); +} - /* The first will be the motherboard in a true EISA system */ - if (dev_node && (dev_node->dev.ioconf.slot == 0)) { - char *idstring; - - e_dev = &dev_node->dev; - e_dev->driver = &mainboard_drv; - e_dev->unit = (*e_dev->driver->unit)++; - idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1, - M_DEVBUF, M_NOWAIT); - if (idstring == NULL) { - panic("Eisa probe unable to malloc"); - } - sprintf(idstring, "%c%c%c%x%x (System Board)", - EISA_MFCTR_CHAR0(e_dev->id), - EISA_MFCTR_CHAR1(e_dev->id), - EISA_MFCTR_CHAR2(e_dev->id), - EISA_PRODUCT_ID(e_dev->id), - EISA_REVISION_ID(e_dev->id)); - e_dev->full_name = idstring; - - printf("%s%ld: <%s>\n", - e_dev->driver->name, - e_dev->unit, - e_dev->full_name); - - /* Should set the iosize, but I don't have a spec handy */ - printf("Probing for devices on the EISA bus\n"); - dev_node = dev_node->next; - } +static int +eisa_find_irq(struct eisa_device *e_dev, int rid) +{ + int i; + struct irq_node *irq; - if (!eisa_dev_list) { - /* - * No devices. - */ - return; - } - /* - * See what devices we recognize. - */ - while((e_drv = *e_drvp++)) { - if (e_drv->probe) - (*e_drv->probe)(); + for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs); + i < rid && irq; + i++, irq = TAILQ_NEXT(irq, links)) + ; + + if (irq) + return irq->irq_no; + else + return -1; +} + +static struct resvaddr * +eisa_find_maddr(struct eisa_device *e_dev, int rid) +{ + int i; + struct resvaddr *resv; + + for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs); + i < rid && resv; + i++, resv = LIST_NEXT(resv, links)) + ; + + return resv; +} + +static struct resvaddr * +eisa_find_ioaddr(struct eisa_device *e_dev, int rid) +{ + int i; + struct resvaddr *resv; + + for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs); + i < rid && resv; + i++, resv = LIST_NEXT(resv, links)) + ; + + return resv; +} + +static int +eisa_read_ivar(device_t dev, device_t child, int which, u_long *result) +{ + struct eisa_device *e_dev = device_get_ivars(child); + + switch (which) { + case EISA_IVAR_SLOT: + *result = e_dev->ioconf.slot; + break; + + case EISA_IVAR_ID: + *result = e_dev->id; + break; + + case EISA_IVAR_IRQ: + /* XXX only first irq */ + *result = eisa_find_irq(e_dev, 0); + break; + + default: + return (ENOENT); } - /* - * Attach the devices we found in slot order - */ - for (; dev_node; dev_node=dev_node->next) { - e_dev = &dev_node->dev; - e_drv = e_dev->driver; - - if (e_drv) { - /* - * Determine the proper unit number for this device. - * Here we should look in the device table generated - * by config to see if this type of device is enabled - * either generically or for this particular address - * as well as determine if a reserved unit number - * should be used. We should also ensure that the - * "next availible unit number" skips over "wired" unit - * numbers. This will be done after config is fixed or - * some other configuration method is chosen. - */ - e_dev->unit = (*e_drv->unit)++; - if ((*e_drv->attach)(e_dev) < 0) { - /* Ensure registration has ended */ - reg_state.in_registration = 0; - printf("\n%s0:%d <%s> attach failed\n", - mainboard_drv.name, - e_dev->ioconf.slot, - e_dev->full_name); - continue; - } - /* Ensure registration has ended */ - reg_state.in_registration = 0; + return (0); +} + +static int +eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + return (EINVAL); +} + +static struct resource * +eisa_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + int isdefault; + struct eisa_device *e_dev = device_get_ivars(child); + struct resource *rv, **rvp = 0; + + isdefault = (device_get_parent(child) == dev + && start == 0UL && end == ~0UL && count == 1); + + switch (type) { + case SYS_RES_IRQ: + if (isdefault) { + int irq = eisa_find_irq(e_dev, *rid); + if (irq == -1) + return 0; + start = end = irq; + count = 1; + } + break; + + case SYS_RES_MEMORY: + if (isdefault) { + struct resvaddr *resv; + + resv = eisa_find_maddr(e_dev, *rid); + if (!resv) + return 0; + + start = resv->addr; + end = resv->size - 1; + count = resv->size; + rvp = &resv->res; } - else { - /* Announce unattached device */ - printf("%s0:%d <%c%c%c%x%x=0x%x> unknown device\n", - mainboard_drv.name, - e_dev->ioconf.slot, - EISA_MFCTR_CHAR0(e_dev->id), - EISA_MFCTR_CHAR1(e_dev->id), - EISA_MFCTR_CHAR2(e_dev->id), - EISA_PRODUCT_ID(e_dev->id), - EISA_REVISION_ID(e_dev->id), - e_dev->id); + break; + + case SYS_RES_IOPORT: + if (isdefault) { + struct resvaddr *resv; + + resv = eisa_find_ioaddr(e_dev, *rid); + if (!resv) + return 0; + + start = resv->addr; + end = resv->size - 1; + count = resv->size; + rvp = &resv->res; } + break; + + default: + return 0; } + + rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags); + if (rvp) + *rvp = rv; + + return rv; } -struct eisa_device * -eisa_match_dev(e_dev, match_func) - struct eisa_device *e_dev; - const char* (*match_func)(eisa_id_t); +static int +eisa_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) { - struct eisa_device_node *e_node = eisa_dev_list; + int rv; + struct eisa_device *e_dev = device_get_ivars(child); + struct resvaddr *resv = 0; + + switch (type) { + case SYS_RES_IRQ: + if (eisa_find_irq(e_dev, rid) == -1) + return EINVAL; + break; - if (e_dev) { - /* Start our search from the last successful match */ - e_node = ((struct eisa_device_node *)e_dev)->next; + case SYS_RES_MEMORY: + if (device_get_parent(child) == dev) + resv = eisa_find_maddr(e_dev, rid); + break; + + + case SYS_RES_IOPORT: + if (device_get_parent(child) == dev) + resv = eisa_find_ioaddr(e_dev, rid); + break; + + default: + return (ENOENT); } - for(; e_node; e_node = e_node->next) { - const char *result; - if (e_node->dev.driver) { - /* Already claimed */ - continue; - } - result = (*match_func)(e_node->dev.id); - if (result) { - e_node->dev.full_name = result; - return (&(e_node->dev)); - } + rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r); + + if (rv == 0) { + if (resv) + resv->res = 0; } - return NULL; + + return rv; } +#if 0 + /* Interrupt and I/O space registration facitlities */ void eisa_reg_start(e_dev) @@ -362,11 +486,14 @@ eisa_reg_end(e_dev) "registration session\n"); } +#endif /* 0 */ + int -eisa_add_intr(e_dev, irq) - struct eisa_device *e_dev; +eisa_add_intr(dev, irq) + device_t dev; int irq; { + struct eisa_device *e_dev = device_get_ivars(dev); struct irq_node *irq_info; irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF, @@ -380,6 +507,8 @@ eisa_add_intr(e_dev, irq) return 0; } +#if 0 + int eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) struct eisa_device *e_dev; @@ -494,6 +623,8 @@ eisa_enable_intr(e_dev, irq) return (result); } +#endif /* 0 */ + static int eisa_add_resvaddr(e_dev, head, base, size, flags) struct eisa_device *e_dev; @@ -548,27 +679,31 @@ eisa_add_resvaddr(e_dev, head, base, size, flags) } int -eisa_add_mspace(e_dev, mbase, msize, flags) - struct eisa_device *e_dev; +eisa_add_mspace(dev, mbase, msize, flags) + device_t dev; u_long mbase; u_long msize; int flags; { + struct eisa_device *e_dev = device_get_ivars(dev); return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize, flags); } int -eisa_add_iospace(e_dev, iobase, iosize, flags) - struct eisa_device *e_dev; +eisa_add_iospace(dev, iobase, iosize, flags) + device_t dev; u_long iobase; u_long iosize; int flags; { + struct eisa_device *e_dev = device_get_ivars(dev); return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase, iosize, flags); } +#if 0 + static int eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) struct eisa_device *e_dev; @@ -650,12 +785,35 @@ eisa_reg_iospace(e_dev, resvaddr) &(reg_state.num_ioaddrs))); } -int -eisa_registerdev(e_dev, driver) - struct eisa_device *e_dev; - struct eisa_driver *driver; -{ - e_dev->driver = driver; /* Driver now owns this device */ - return (0); -} +#endif + +static device_method_t eisa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, eisa_probe), + DEVMETHOD(device_attach, bus_generic_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, eisa_print_child), + DEVMETHOD(bus_read_ivar, eisa_read_ivar), + DEVMETHOD(bus_write_ivar, eisa_write_ivar), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_alloc_resource, eisa_alloc_resource), + DEVMETHOD(bus_release_resource, eisa_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t eisa_driver = { + "eisa", + eisa_methods, + DRIVER_TYPE_MISC, + 1, /* no softc */ +}; + +DRIVER_MODULE(eisa, isab, eisa_driver, eisa_devclass, 0, 0); diff --git a/sys/dev/eisa/eisaconf.h b/sys/dev/eisa/eisaconf.h index 2b2ff2d..cb950c8 100644 --- a/sys/dev/eisa/eisaconf.h +++ b/sys/dev/eisa/eisaconf.h @@ -28,14 +28,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: eisaconf.h,v 1.16 1997/03/13 18:04:05 joerg Exp $ + * $Id: eisaconf.h,v 1.17 1997/09/21 21:35:23 gibbs Exp $ */ #ifndef _I386_EISA_EISACONF_H_ #define _I386_EISA_EISACONF_H_ 1 -#include <sys/queue.h> - #define EISA_SLOT_SIZE 0x1000 #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ @@ -45,79 +43,46 @@ #define EISA_PRODUCT_ID(ID) (short)((ID>>4) & 0xFFF) /* Bits 4-15 */ #define EISA_REVISION_ID(ID) (u_char)(ID & 0x0F) /* Bits 0-3 */ -extern struct linker_set eisadriver_set; extern int num_eisa_slots; typedef u_int32_t eisa_id_t; -typedef struct resvaddr { - u_long addr; /* start address */ - u_long size; /* size of reserved area */ - int flags; +enum eisa_device_ivars { + EISA_IVAR_SLOT, + EISA_IVAR_ID, + EISA_IVAR_IRQ +}; + +/* + * Simplified accessors for isa devices + */ +#define EISA_ACCESSOR(A, B, T) \ + \ +static __inline T eisa_get_ ## A(device_t dev) \ +{ \ + uintptr_t v; \ + BUS_READ_IVAR(device_get_parent(dev), dev, EISA_IVAR_ ## B, &v); \ + return (T) v; \ +} \ + \ +static __inline void eisa_set_ ## A(device_t dev, T t) \ +{ \ + u_long v = (u_long) t; \ + BUS_WRITE_IVAR(device_get_parent(dev), dev, EISA_IVAR_ ## B, v); \ +} + +EISA_ACCESSOR(slot, SLOT, int) +EISA_ACCESSOR(id, ID, eisa_id_t) +EISA_ACCESSOR(irq, IRQ, eisa_id_t) + +int eisa_add_intr __P((device_t, int)); + #define RESVADDR_NONE 0x00 #define RESVADDR_BITMASK 0x01 /* size is a mask of reserved * bits at addr */ #define RESVADDR_RELOCATABLE 0x02 - LIST_ENTRY(resvaddr) links; /* List links */ -} resvaddr_t; - -LIST_HEAD(resvlist, resvaddr); - -struct irq_node { - int irq_no; - void *idesc; - TAILQ_ENTRY(irq_node) links; -}; - -TAILQ_HEAD(irqlist, irq_node); - -struct eisa_ioconf { - int slot; - struct resvlist ioaddrs; /* list of reserved I/O ranges */ - struct resvlist maddrs; /* list of reserved memory ranges */ - struct irqlist irqs; /* list of reserved irqs */ -}; - -struct eisa_device; - -struct eisa_driver { - char* name; /* device name */ - int (*probe) __P((void)); - /* test whether device is present */ - int (*attach) __P((struct eisa_device *)); - /* setup driver for a device */ - int (*shutdown) __P((int)); - /* Return the device to a safe - * state before shutdown - */ - u_long *unit; /* Next available unit */ -}; - -/* To be replaced by the "super device" generic device structure... */ -struct eisa_device { - eisa_id_t id; - u_long unit; - const char* full_name; /* for use in the probe message */ - struct eisa_ioconf ioconf; - struct eisa_driver* driver; -}; - -void eisa_configure __P((void)); -struct eisa_device *eisa_match_dev __P((struct eisa_device *, - const char * (*)(eisa_id_t))); - -void eisa_reg_start __P((struct eisa_device *)); -void eisa_reg_end __P((struct eisa_device *)); -int eisa_add_intr __P((struct eisa_device *, int)); -int eisa_reg_intr __P((struct eisa_device *, int, void (*)(void *), - void *, u_int *, int)); -int eisa_release_intr __P((struct eisa_device *, int, void (*)(void *))); -int eisa_enable_intr __P((struct eisa_device *, int)); -int eisa_add_iospace __P((struct eisa_device *, u_long, u_long, int)); -int eisa_reg_iospace __P((struct eisa_device *, resvaddr_t *)); -int eisa_add_mspace __P((struct eisa_device *, u_long, u_long, int)); -int eisa_reg_mspace __P((struct eisa_device *, resvaddr_t *)); -int eisa_registerdev __P((struct eisa_device *, struct eisa_driver *)); +int eisa_add_iospace __P((device_t, u_long, u_long, int)); +int eisa_add_mspace __P((device_t, u_long, u_long, int)); #endif /* _I386_EISA_EISACONF_H_ */ |