diff options
author | gibbs <gibbs@FreeBSD.org> | 1996-01-29 03:13:23 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1996-01-29 03:13:23 +0000 |
commit | 0b627d75b7d924f59d3cc0c0ca10e754ba53854f (patch) | |
tree | 1b6101f6ee35060aacfbf2e0aae2d6e0d2e72010 /sys/dev | |
parent | e94d9bd8af1b0fd9544212c02ae1125ec377a6c3 (diff) | |
download | FreeBSD-src-0b627d75b7d924f59d3cc0c0ca10e754ba53854f.zip FreeBSD-src-0b627d75b7d924f59d3cc0c0ca10e754ba53854f.tar.gz |
Another pass through eisaconf. Ioaddrs and Maddrs are link lists now.
The Bt driver is the only one that actually registers multiple addresses.
Probe output is formatted to 80 columns.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/eisa/eisaconf.c | 342 | ||||
-rw-r--r-- | sys/dev/eisa/eisaconf.h | 37 |
2 files changed, 305 insertions, 74 deletions
diff --git a/sys/dev/eisa/eisaconf.c b/sys/dev/eisa/eisaconf.c index 288c66b..2c583aa 100644 --- a/sys/dev/eisa/eisaconf.c +++ b/sys/dev/eisa/eisaconf.c @@ -1,7 +1,7 @@ /* * EISA bus probe and attach routines * - * Copyright (c) 1995 Justin T. Gibbs. + * Copyright (c) 1995, 1996 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,15 +18,15 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.c,v 1.11 1995/12/10 13:33:49 phk Exp $ + * $Id: eisaconf.c,v 1.12 1996/01/03 06:28:01 gibbs Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/devconf.h> #include <sys/kernel.h> #include <sys/sysctl.h> -#include <sys/conf.h> +#include <sys/conf.h> /* For kdc_isa */ #include <sys/malloc.h> -#include <sys/devconf.h> #include <i386/eisa/eisaconf.h> @@ -77,6 +77,30 @@ static struct eisa_driver mainboard_drv = { DATA_SET (eisadriver_set, mainboard_drv); /* + * Local function declarations and static variables + */ +void eisa_reg_print __P((struct eisa_device *e_dev, char *string, + char *separator)); +static int eisa_add_resvaddr __P((struct resvlist *head, u_long base, + u_long size, int flags)); +static int eisa_reg_resvaddr __P((struct eisa_device *e_dev, + struct resvlist *head, resvaddr_t *resvaddr, + int *reg_count)); + +/* + * Keep some state about what we've printed so far + * to make probe output pretty. + */ +static struct { + int in_registration;/* reg_start has been called */ + int num_interrupts; + int num_ioaddrs; + int num_maddrs; + int column; /* How much we have output so far. */ +#define MAX_COL 80 +} reg_state; + +/* ** probe for EISA devices */ void @@ -112,6 +136,7 @@ eisa_configure() } bzero(dev_node, sizeof(*dev_node)); e_dev = &(dev_node->dev); + e_dev->id = eisa_id; /* * Add an EISA ID based descriptive name incase we don't @@ -131,9 +156,13 @@ eisa_configure() EISA_MFCTR_CHAR2(e_dev->id), EISA_PRODUCT_ID(e_dev->id), EISA_REVISION_ID(e_dev->id)); + e_dev->ioconf.slot = slot; - /* Is iobase defined in any EISA specs? */ - e_dev->ioconf.iobase = eisaBase & 0xff00; + + /* Initialize our lists of reserved addresses */ + LIST_INIT(&(e_dev->ioconf.ioaddrs)); + LIST_INIT(&(e_dev->ioconf.maddrs)); + *eisa_dev_list_tail = dev_node; eisa_dev_list_tail = &dev_node->next; } @@ -199,6 +228,7 @@ eisa_configure() 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. @@ -213,20 +243,25 @@ eisa_configure() */ e_dev->unit = (*e_drv->unit)++; if ((*e_drv->attach)(e_dev) < 0) { - printf("%s0:%d <%s> attach failed\n", + /* 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; e_dev->kdc->kdc_unit = e_dev->unit; } else { /* Announce unattached device */ - printf("%s0:%d <%s> unknown device\n", + printf("%s0:%d <%s=0x%x> unknown device\n", mainboard_drv.name, e_dev->ioconf.slot, - e_dev->full_name); + e_dev->full_name, + e_dev->id); } } } @@ -267,10 +302,57 @@ eisa_reg_start(e_dev) /* * Announce the device. */ - printf("%s%ld: <%s>", - e_dev->driver->name, - e_dev->unit, - e_dev->full_name); + char *string; + + reg_state.in_registration = 1; + reg_state.num_interrupts = 0; + reg_state.num_ioaddrs = 0; + reg_state.num_maddrs = 0; + reg_state.column = 0; + + string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1, + M_TEMP, M_NOWAIT); + if(!string) { + printf("eisa0: cannot malloc device description string\n"); + return; + } + sprintf(string, " <%s>", e_dev->full_name); + eisa_reg_print(e_dev, string, /*separator=*/NULL); + free(string, M_TEMP); +} + +/* + * Output registration information mindfull of screen wrap. + * Output an optional character separator before the string + * if the line does not wrap. + */ +void +eisa_reg_print(e_dev, string, separator) + struct eisa_device *e_dev; + char *string; + char *separator; +{ + int len = strlen(string); + + if( separator ) + len++; + + if(reg_state.column + len > MAX_COL) { + printf("\n"); + reg_state.column = 0; + } + else if( separator ) { + printf("%c", *separator); + reg_state.column++; + } + + if(reg_state.column == 0) + reg_state.column += printf("%s%ld:%s", + e_dev->driver->name, + e_dev->unit, + string); + else + reg_state.column += printf("%s", string); } /* Interrupt and I/O space registration facitlities */ @@ -278,19 +360,30 @@ void eisa_reg_end(e_dev) struct eisa_device *e_dev; { - /* - * The device should have called eisa_registerdev() - * during its probe. So hopefully we can use the kdc - * to weed out ISA/VL devices that use EISA id registers. - */ - if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { - printf(" on isa\n"); - } - else { - printf(" on %s0 slot %d\n", - mainboard_drv.name, - e_dev->ioconf.slot); + if( reg_state.in_registration ) + { + /* + * The device should have called eisa_registerdev() + * during its probe. So hopefully we can use the kdc + * to weed out ISA/VL devices that use EISA id registers. + */ + char string[25]; + + if (e_dev->kdc && (e_dev->kdc->kdc_parent == &kdc_isa0)) { + sprintf(string, " on isa"); + } + else { + sprintf(string, " on %s0 slot %d", + mainboard_drv.name, + e_dev->ioconf.slot); + } + eisa_reg_print(e_dev, string, NULL); + printf("\n"); + reg_state.in_registration = 0; } + else + printf("eisa_reg_end called outside of a " + "registration session\n"); } int @@ -313,6 +406,8 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) { int result; int s; + char string[25]; + char separator = ','; #if NOT_YET /* @@ -324,28 +419,35 @@ eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared) if (haveseen_dev(dev, checkthese)) return 1; #endif - s = splhigh(); - /* - * This should really go to a routine that can optionally - * handle shared interrupts. - */ - result = register_intr(irq, /* isa irq */ - 0, /* deviced?? */ - 0, /* flags? */ - (inthand2_t*) func, /* handler */ - maskptr, /* mask pointer */ - (int)arg); /* handler arg */ - - if (result) { - printf ("eisa_reg_int: result=%d\n", result); + if (reg_state.in_registration) { + s = splhigh(); + /* + * This should really go to a routine that can optionally + * handle shared interrupts. + */ + result = register_intr(irq, /* isa irq */ + 0, /* deviced?? */ + 0, /* flags? */ + (inthand2_t*) func, /* handler */ + maskptr, /* mask pointer */ + (int)arg); /* handler arg */ + + if (result) { + printf ("\neisa_reg_int: result=%d\n", result); + splx(s); + return (result); + }; + update_intr_masks(); splx(s); - return (result); - }; - update_intr_masks(); - splx(s); + } + else + return EPERM; e_dev->ioconf.irq |= 1ul << irq; - printf(" irq %d", irq); + sprintf(string, " irq %d", irq); + eisa_reg_print(e_dev, string, reg_state.num_interrupts ? + &separator : NULL); + reg_state.num_interrupts++; return (0); } @@ -398,31 +500,146 @@ eisa_enable_intr(e_dev, irq) return 0; } +static int +eisa_add_resvaddr(head, base, size, flags) + struct resvlist *head; + u_long base; + u_long size; + int flags; +{ + resvaddr_t *reservation; + + reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t), + M_DEVBUF, M_NOWAIT); + if(!reservation) + return (ENOMEM); + + reservation->addr = base; + reservation->size = size; + reservation->flags = flags; + + if (!head->lh_first) { + LIST_INSERT_HEAD(head, reservation, links); + } + else { + resvaddr_t *node; + for(node = head->lh_first; node; node = node->links.le_next) { + if (node->addr > reservation->addr) { + /* + * List is sorted in increasing + * address order. + */ + LIST_INSERT_BEFORE(node, reservation, links); + break; + } + + if (node->addr == reservation->addr) { + /* + * If the entry we want to add + * matches any already in here, + * fail. + */ + free(reservation, M_DEVBUF); + return (EEXIST); + } + + if (!node->links.le_next) { + LIST_INSERT_AFTER(node, reservation, links); + break; + } + } + } + return (0); +} + int -eisa_add_iospace(e_dev, iobase, iosize) +eisa_add_mspace(e_dev, mbase, msize, flags) struct eisa_device *e_dev; - u_long iobase; - int iosize; + u_long mbase; + u_long msize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. - */ - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - return 0; + return eisa_add_resvaddr(&(e_dev->ioconf.maddrs), mbase, msize, flags); } int -eisa_reg_iospace(e_dev, iobase, iosize) +eisa_add_iospace(e_dev, iobase, iosize, flags) struct eisa_device *e_dev; u_long iobase; - int iosize; + u_long iosize; + int flags; { - /* - * We should develop a scheme for storing the results of - * multiple calls to this function. + return eisa_add_resvaddr(&(e_dev->ioconf.ioaddrs), iobase, iosize, + flags); +} + +static int +eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count) + struct eisa_device *e_dev; + struct resvlist *head; + resvaddr_t *resvaddr; + int *reg_count; +{ + if (reg_state.in_registration) { + resvaddr_t *node; + /* + * Ensure that this resvaddr is actually in the devices' + * reservation list. + */ + for(node = head->lh_first; node; + node = node->links.le_next) { + if (node == resvaddr) { + char buf[35]; + char separator = ','; + char *string = buf; + + if (*reg_count == 0) { + /* First time */ + string += sprintf(string, " at"); + } + + if (node->size == 1 + || (node->flags & RESVADDR_BITMASK)) + sprintf(string, " 0x%lx", node->addr); + else + sprintf(string, " 0x%lx-0x%lx", + node->addr, + node->addr + node->size - 1); + eisa_reg_print(e_dev, buf, + *reg_count ? &separator : NULL); + (*reg_count)++; + return (0); + } + } + return (ENOENT); + } + return EPERM; +} + +int +eisa_reg_mspace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ +#ifdef NOT_YET + /* + * Punt on conflict detection for the moment. + * I want to develop a generic routine to do + * this for all device types. */ + int checkthese = CC_MADDR; + if (haveseen_dev(dev, checkthese)) + return -1; +#endif + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr, + &(reg_state.num_maddrs))); +} + +int +eisa_reg_iospace(e_dev, resvaddr) + struct eisa_device *e_dev; + resvaddr_t *resvaddr; +{ #ifdef NOT_YET /* * Punt on conflict detection for the moment. @@ -433,11 +650,8 @@ eisa_reg_iospace(e_dev, iobase, iosize) if (haveseen_dev(dev, checkthese)) return -1; #endif - e_dev->ioconf.iobase = iobase; - e_dev->ioconf.iosize = iosize; - - printf(" at 0x%lx-0x%lx", iobase, iobase + iosize - 1); - return (0); + return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr, + &(reg_state.num_ioaddrs))); } int diff --git a/sys/dev/eisa/eisaconf.h b/sys/dev/eisa/eisaconf.h index 93cecf3..181c768 100644 --- a/sys/dev/eisa/eisaconf.h +++ b/sys/dev/eisa/eisaconf.h @@ -18,13 +18,16 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: eisaconf.h,v 1.5 1995/11/20 12:41:13 phk Exp $ + * $Id: eisaconf.h,v 1.6 1995/11/21 12:52:49 bde Exp $ */ #ifndef _I386_EISA_EISACONF_H_ #define _I386_EISA_EISACONF_H_ 1 +#include <sys/queue.h> + #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */ +#define EISA_SLOT_SIZE 0x1000 #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ #define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ @@ -35,15 +38,27 @@ extern struct linker_set eisadriver_set; -typedef u_long eisa_id_t; /* Should use u_int32? */ +typedef u_int32_t eisa_id_t; + +typedef struct resvaddr { + u_long addr; /* start address */ + u_long size; /* size of reserved area */ + int flags; +#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 eisa_ioconf { - int slot; - u_long iobase; /* base i/o address */ - int iosize; /* size of i/o space */ - u_short irq; /* interrupt request */ - caddr_t maddr; /* physical i/o memory address on bus (if any)*/ - int msize; /* size of i/o memory */ + int slot; + struct resvlist ioaddrs; /* list of reserved I/O ranges */ + struct resvlist maddrs; /* list of reserved memory ranges */ + u_short irq; /* bitmask of interrupt */ }; struct kern_devconf; @@ -81,8 +96,10 @@ 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, int)); -int eisa_reg_iospace __P((struct eisa_device *, u_long, 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 *, struct kern_devconf *)); |