Plug and Play support.

This commit is contained in:
christos 1997-01-16 22:00:57 +00:00
parent 5714664cf5
commit cf455412fc
7 changed files with 2097 additions and 0 deletions

View File

@ -0,0 +1,22 @@
# $NetBSD: files.isapnp,v 1.1 1997/01/16 22:00:57 christos Exp $
#
# Config.new file and device description for machine-independent ISAPnP code.
# Included by ports that need it.
# XXX: We don't use locators currenly...
device isapnp {[port = -1], [size = 0],
[iomem = -1], [iosiz = 0],
[irq = -1], [drq = -1]}
attach isapnp at isa
file dev/isapnp/isapnp.c isapnp
file dev/isapnp/isapnpdebug.c isapnp
file dev/isapnp/isapnpres.c isapnp
#
# ISAPnP Sound hardware
#
# SoundBlaster family
attach sb at isapnp with sb_isapnp
file dev/isapnp/sb_isapnp.c sb_isapnp

819
sys/dev/isapnp/isapnp.c Normal file
View File

@ -0,0 +1,819 @@
/* $NetBSD: isapnp.c,v 1.1 1997/01/16 22:00:59 christos Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ISA PnP bus autoconfiguration.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/isa/isavar.h>
#include <dev/isapnp/isapnpreg.h>
#include <dev/isapnp/isapnpvar.h>
static void isapnp_init __P((struct isapnp_softc *));
static __inline u_char isapnp_shift_bit __P((struct isapnp_softc *));
static int isapnp_findcard __P((struct isapnp_softc *));
static void isapnp_free_region __P((bus_space_tag_t, struct isapnp_region *));
static int isapnp_alloc_region __P((bus_space_tag_t, struct isapnp_region *));
static int isapnp_alloc_pin __P((struct isapnp_pin *));
static int isapnp_testconfig __P((bus_space_tag_t, bus_space_tag_t,
struct isapnp_attach_args *, int));
static struct isapnp_attach_args *isapnp_bestconfig __P((struct isapnp_softc *,
struct isapnp_attach_args **));
static void isapnp_print_region __P((const char *, struct isapnp_region *,
size_t));
static void isapnp_configure __P((struct isapnp_softc *,
const struct isapnp_attach_args *));
static void isapnp_print_pin __P((const char *, struct isapnp_pin *, size_t));
static int isapnp_print __P((void *, const char *));
static int isapnp_submatch __P((struct device *, void *, void *));
static int isapnp_find __P((struct isapnp_softc *));
static int isapnp_match __P((struct device *, void *, void *));
static void isapnp_attach __P((struct device *, struct device *, void *));
struct cfattach isapnp_ca = {
sizeof(struct isapnp_softc), isapnp_match, isapnp_attach
};
struct cfdriver isapnp_cd = {
NULL, "isapnp", DV_DULL
};
/* isapnp_init():
* Write the PNP initiation key to wake up the cards...
*/
static void
isapnp_init(sc)
struct isapnp_softc *sc;
{
int i;
u_char v = ISAPNP_LFSR_INIT;
/* First write 0's twice to enter the Wait for Key state */
ISAPNP_WRITE_ADDR(sc, 0);
ISAPNP_WRITE_ADDR(sc, 0);
/* Send the 32 byte sequence to awake the logic */
for (i = 0; i < 32; i++) {
ISAPNP_WRITE_ADDR(sc, v);
v = ISAPNP_LFSR_NEXT(v);
}
}
/* isapnp_shift_bit():
* Read a bit at a time from the config card.
*/
static __inline u_char
isapnp_shift_bit(sc)
struct isapnp_softc *sc;
{
u_char c1, c2;
DELAY(250);
c1 = ISAPNP_READ_DATA(sc);
DELAY(250);
c2 = ISAPNP_READ_DATA(sc);
if (c1 == 0x55 && c2 == 0xAA)
return 0x80;
else
return 0;
}
/* isapnp_findcard():
* Attempt to read the vendor/serial/checksum for a card
* If a card is found [the checksum matches], assign the
* next card number to it and return 1
*/
static int
isapnp_findcard(sc)
struct isapnp_softc *sc;
{
u_char v = ISAPNP_LFSR_INIT, csum = 0, w;
int i, b;
if (sc->sc_ncards == ISAPNP_MAX_CARDS) {
printf("%s: Too many pnp cards\n", sc->sc_dev.dv_xname);
return 0;
}
/* Set the read port */
isapnp_write_reg(sc, ISAPNP_WAKE, 0);
isapnp_write_reg(sc, ISAPNP_SET_RD_PORT, sc->sc_read_port >> 2);
sc->sc_read_port |= 3;
DELAY(1000);
ISAPNP_WRITE_ADDR(sc, ISAPNP_SERIAL_ISOLATION);
DELAY(1000);
/* Read the 8 bytes of the Vendor ID and Serial Number */
for(i = 0; i < 8; i++) {
/* Read each bit separately */
for (w = 0, b = 0; b < 8; b++) {
u_char neg = isapnp_shift_bit(sc);
w >>= 1;
w |= neg;
v = ISAPNP_LFSR_NEXT(v) ^ neg;
}
sc->sc_id[sc->sc_ncards][i] = w;
}
/* Read the remaining checksum byte */
for (b = 0; b < 8; b++) {
u_char neg = isapnp_shift_bit(sc);
csum >>= 1;
csum |= neg;
sc->sc_id[sc->sc_ncards][9] = w;
}
if (csum == v) {
sc->sc_ncards++;
isapnp_write_reg(sc, ISAPNP_CARD_SELECT_NUM, sc->sc_ncards);
return 1;
}
return 0;
}
/* isapnp_free_region():
* Free a region
*/
static void
isapnp_free_region(t, r)
bus_space_tag_t t;
struct isapnp_region *r;
{
bus_space_unmap(t, r->h, r->length);
}
/* isapnp_alloc_region():
* Allocate a single region if possible
*/
static int
isapnp_alloc_region(t, r)
bus_space_tag_t t;
struct isapnp_region *r;
{
int error = 0;
for (r->base = r->minbase; r->base <= r->maxbase; r->base += r->align) {
error = bus_space_map(t, r->base, r->length, 0, &r->h);
if (error == 0)
return 0;
}
return error;
}
/* isapnp_alloc_pin():
* Allocate an irq/drq
* XXX: No resource conflict checks!
*/
static int
isapnp_alloc_pin(i)
struct isapnp_pin *i;
{
int b;
if (i->bits == 0)
i->num = 0;
else
for (b = 0; b < 16; b++)
if (i->bits & (1 << b))
i->num = b;
return 0;
}
/* isapnp_testconfig():
* Test/Allocate the regions used
*/
static int
isapnp_testconfig(iot, memt, ipa, alloc)
bus_space_tag_t iot, memt;
struct isapnp_attach_args *ipa;
int alloc;
{
int nio = 0, nmem = 0, nmem32 = 0, nirq = 0, ndrq = 0;
int error = 0;
#ifdef DEBUG_ISAPNP
isapnp_print_attach(ipa);
#endif
for (; nio < ipa->ipa_nio; nio++) {
error = isapnp_alloc_region(iot, &ipa->ipa_io[nio]);
if (error)
goto bad;
}
for (; nmem < ipa->ipa_nmem; nmem++) {
error = isapnp_alloc_region(memt, &ipa->ipa_mem[nmem]);
if (error)
goto bad;
}
for (; nmem32 < ipa->ipa_nmem32; nmem32++) {
error = isapnp_alloc_region(memt, &ipa->ipa_mem32[nmem32]);
if (error)
goto bad;
}
for (; nirq < ipa->ipa_nirq; nirq++) {
error = isapnp_alloc_pin(&ipa->ipa_irq[nirq]);
if (error)
goto bad;
}
for (; ndrq < ipa->ipa_ndrq; ndrq++) {
error = isapnp_alloc_pin(&ipa->ipa_drq[ndrq]);
if (error)
goto bad;
}
if (alloc)
return error;
bad:
#ifdef notyet
for (ndrq--; ndrq >= 0; ndrq--)
isapnp_free_pin(&ipa->ipa_drq[ndrq]);
for (nirq--; nirq >= 0; nirq--)
isapnp_free_pin(&ipa->ipa_irq[nirq]);
#endif
for (nmem32--; nmem32 >= 0; nmem32--)
isapnp_free_region(memt, &ipa->ipa_mem32[nmem32]);
for (nmem--; nmem >= 0; nmem--)
isapnp_free_region(memt, &ipa->ipa_mem[nmem]);
for (nio--; nio >= 0; nio--)
isapnp_free_region(iot, &ipa->ipa_io[nio]);
return error;
}
/* isapnp_config():
* Test/Allocate the regions used
*/
int
isapnp_config(iot, memt, ipa)
bus_space_tag_t iot, memt;
struct isapnp_attach_args *ipa;
{
return isapnp_testconfig(iot, memt, ipa, 1);
}
/* isapnp_unconfig():
* Free the regions used
*/
void
isapnp_unconfig(iot, memt, ipa)
bus_space_tag_t iot, memt;
struct isapnp_attach_args *ipa;
{
int i;
#ifdef notyet
for (i = 0; i < ipa->ipa_ndrq; i++)
isapnp_free_pin(&ipa->ipa_drq[i]);
for (i = 0; i < ipa->ipa_nirq; i++)
isapnp_free_pin(&ipa->ipa_irq[i]);
#endif
for (i = 0; i < ipa->ipa_nmem32; i++)
isapnp_free_region(memt, &ipa->ipa_mem32[i]);
for (i = 0; i < ipa->ipa_nmem; i++)
isapnp_free_region(memt, &ipa->ipa_mem[i]);
for (i = 0; i < ipa->ipa_nio; i++)
isapnp_free_region(iot, &ipa->ipa_io[i]);
}
/* isapnp_bestconfig():
* Return the best configuration for each logical device, remove and
* free all other configurations.
*/
static struct isapnp_attach_args *
isapnp_bestconfig(sc, ipa)
struct isapnp_softc *sc;
struct isapnp_attach_args **ipa;
{
struct isapnp_attach_args *c, *best, *f = *ipa;
int error;
for (;;) {
if (f == NULL)
return NULL;
#define SAMEDEV(a, b) (strcmp((a)->ipa_devlogic, (b)->ipa_devlogic) == 0)
/* Find the best config */
for (best = c = f; c != NULL; c = c->ipa_next) {
if (!SAMEDEV(c, f))
continue;
if (c->ipa_pref < best->ipa_pref)
best = c;
}
/* Test the best config */
error = isapnp_testconfig(sc->sc_iot, sc->sc_memt, best, 0);
/* Remove this config from the list */
if (best == f)
f = f->ipa_next;
else {
for (c = f; c->ipa_next != best; c = c->ipa_next)
continue;
c->ipa_next = best->ipa_next;
}
if (error) {
best->ipa_pref = ISAPNP_DEP_CONFLICTING;
for (c = f; c != NULL; c = c->ipa_next)
if (c != best && SAMEDEV(c, best))
break;
/* Last config for this logical device is conflicting */
if (c == NULL) {
*ipa = f;
return best;
}
ISAPNP_FREE(best);
continue;
}
else {
/* Remove all other configs for this device */
struct isapnp_attach_args *l = NULL, *n = NULL, *d;
for (c = f; c; ) {
if (c == best)
continue;
d = c->ipa_next;
if (SAMEDEV(c, best))
ISAPNP_FREE(c);
else {
if (n)
n->ipa_next = c;
else
l = c;
n = c;
c->ipa_next = NULL;
}
c = d;
}
f = l;
}
*ipa = f;
return best;
}
}
/* isapnp_id_to_vendor():
* Convert a pnp ``compressed ascii'' vendor id to a string
*/
char *
isapnp_id_to_vendor(v, id)
char *v;
const u_char *id;
{
static const char hex[] = "0123456789ABCDEF";
char *p = v;
*p++ = 'A' + (id[0] >> 2) - 1;
*p++ = 'A' + ((id[0] & 3) << 3) + (id[1] >> 5) - 1;
*p++ = 'A' + (id[1] & 0x1f) - 1;
*p++ = hex[id[2] >> 4];
*p++ = hex[id[2] & 0x0f];
*p++ = hex[id[3] >> 4];
*p++ = hex[id[3] & 0x0f];
*p = '\0';
return v;
}
/* isapnp_print_region():
* Print a region allocation
*/
static void
isapnp_print_region(str, r, n)
const char *str;
struct isapnp_region *r;
size_t n;
{
size_t i;
if (n == 0)
return;
printf(" %s ", str);
for (i = 0; i < n; i++, r++) {
printf("0x%x", r->base);
if (r->length)
printf("/%d", r->length);
if (i != n - 1)
printf(",");
}
}
/* isapnp_print_pin():
* Print an irq/drq assignment
*/
static void
isapnp_print_pin(str, p, n)
const char *str;
struct isapnp_pin *p;
size_t n;
{
size_t i;
if (n == 0)
return;
printf(" %s ", str);
for (i = 0; i < n; i++, p++) {
printf("%d", p->num);
if (i != n - 1)
printf(",");
}
}
/* isapnp_print():
* Print the configuration line for an ISA PnP card.
*/
static int
isapnp_print(aux, str)
void *aux;
const char *str;
{
struct isapnp_attach_args *ipa = aux;
if (str != NULL)
printf("%s: <%s, %s, %s>",
str, ipa->ipa_devident, ipa->ipa_devlogic,
ipa->ipa_devclass);
isapnp_print_region("port", ipa->ipa_io, ipa->ipa_nio);
isapnp_print_region("mem", ipa->ipa_mem, ipa->ipa_nmem);
isapnp_print_region("mem32", ipa->ipa_mem32, ipa->ipa_nmem32);
isapnp_print_pin("irq", ipa->ipa_irq, ipa->ipa_nirq);
isapnp_print_pin("drq", ipa->ipa_drq, ipa->ipa_ndrq);
return UNCONF;
}
/* isapnp_submatch():
* Probe the card...
*/
static int
isapnp_submatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct cfdata *cf = match;
return ((*cf->cf_attach->ca_match)(parent, match, aux));
}
/* isapnp_find():
* Probe and add cards
*/
static int
isapnp_find(sc)
struct isapnp_softc *sc;
{
int p;
isapnp_init(sc);
isapnp_write_reg(sc, ISAPNP_CONFIG_CONTROL, ISAPNP_CC_RESET_DRV);
DELAY(2000);
isapnp_init(sc);
DELAY(2000);
for (p = ISAPNP_RDDATA_MIN; p <= ISAPNP_RDDATA_MAX; p += 4) {
sc->sc_read_port = p;
if (isapnp_map_readport(sc))
continue;
DPRINTF(("%s: Trying port %x\n", sc->sc_dev.dv_xname, p));
if (isapnp_findcard(sc))
break;
isapnp_unmap_readport(sc);
}
if (p > ISAPNP_RDDATA_MAX) {
sc->sc_read_port = 0;
return 0;
}
while (isapnp_findcard(sc))
continue;
return 1;
}
/* isapnp_configure():
* Configure a PnP card
* XXX: The memory configuration code is wrong. We need to check the
* range/length bit an do appropriate sets.
*/
static void
isapnp_configure(sc, ipa)
struct isapnp_softc *sc;
const struct isapnp_attach_args *ipa;
{
int i;
static u_char isapnp_mem_range[] = ISAPNP_MEM_DESC;
static u_char isapnp_io_range[] = ISAPNP_IO_DESC;
static u_char isapnp_irq_range[] = ISAPNP_IRQ_DESC;
static u_char isapnp_drq_range[] = ISAPNP_DRQ_DESC;
static u_char isapnp_mem32_range[] = ISAPNP_MEM32_DESC;
const struct isapnp_region *r;
const struct isapnp_pin *p;
struct isapnp_region rz;
struct isapnp_pin pz;
memset(&pz, 0, sizeof(pz));
memset(&rz, 0, sizeof(rz));
#define B0(a) ((a) & 0xff)
#define B1(a) (((a) >> 8) & 0xff)
#define B2(a) (((a) >> 16) & 0xff)
#define B3(a) (((a) >> 24) & 0xff)
for (i = 0; i < sizeof(isapnp_io_range); i++) {
if (i < ipa->ipa_nio)
r = &ipa->ipa_io[i];
else
r = &rz;
isapnp_write_reg(sc,
isapnp_io_range[i] + ISAPNP_IO_BASE_15_8, B1(r->base));
isapnp_write_reg(sc,
isapnp_io_range[i] + ISAPNP_IO_BASE_7_0, B0(r->base));
}
for (i = 0; i < sizeof(isapnp_mem_range); i++) {
if (i < ipa->ipa_nmem)
r = &ipa->ipa_mem[i];
else
r = &rz;
isapnp_write_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_BASE_23_16, B2(r->base));
isapnp_write_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_BASE_15_8, B1(r->base));
isapnp_write_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_23_16,
B2(r->length));
isapnp_write_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_15_8,
B1(r->length));
}
for (i = 0; i < sizeof(isapnp_irq_range); i++) {
u_char v;
if (i < ipa->ipa_nirq)
p = &ipa->ipa_irq[i];
else
p = &pz;
isapnp_write_reg(sc,
isapnp_irq_range[i] + ISAPNP_IRQ_NUMBER, p->num);
switch (p->flags) {
case ISAPNP_IRQTYPE_LEVEL_PLUS:
v = ISAPNP_IRQ_LEVEL|ISAPNP_IRQ_HIGH;
break;
case ISAPNP_IRQTYPE_EDGE_PLUS:
v = ISAPNP_IRQ_HIGH;
break;
case ISAPNP_IRQTYPE_LEVEL_MINUS:
v = ISAPNP_IRQ_LEVEL;
break;
default:
case ISAPNP_IRQTYPE_EDGE_MINUS:
v = 0;
break;
}
isapnp_write_reg(sc,
isapnp_irq_range[i] + ISAPNP_IRQ_CONTROL, v);
}
for (i = 0; i < sizeof(isapnp_drq_range); i++) {
u_char v;
if (i < ipa->ipa_ndrq)
v = ipa->ipa_drq[i].num;
else
v = 4;
isapnp_write_reg(sc, isapnp_drq_range[i], v);
}
for (i = 0; i < sizeof(isapnp_mem32_range); i++) {
if (i < ipa->ipa_nmem32)
r = &ipa->ipa_mem32[i];
else
r = &rz;
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_31_24,
B3(r->base));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_23_16,
B2(r->base));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_15_8,
B1(r->base));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_7_0,
B0(r->base));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_31_24,
B3(r->length));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_23_16,
B2(r->length));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_15_8,
B1(r->length));
isapnp_write_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_7_0,
B0(r->length));
}
}
/* isapnp_match():
* Probe routine
*/
static int
isapnp_match(parent, match, aux)
struct device *parent;
void *match, *aux;
{
int rv;
struct isapnp_softc sc;
struct isa_attach_args *ia = aux;
sc.sc_iot = ia->ia_iot;
ia->ia_iobase = ISAPNP_ADDR;
ia->ia_iosize = 1;
(void) strcpy(sc.sc_dev.dv_xname, "(isapnp probe)");
if (isapnp_map(&sc))
return 0;
rv = isapnp_find(&sc);
isapnp_unmap(&sc);
return (rv);
}
/* isapnp_attach
* Find and attach PnP cards.
*/
static void
isapnp_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct isapnp_softc *sc = (struct isapnp_softc *) self;
struct isa_attach_args *ia = aux;
int c, d;
sc->sc_iot = ia->ia_iot;
sc->sc_memt = ia->ia_memt;
sc->sc_ncards = 0;
if (isapnp_map(sc))
panic("%s: bus map failed\n", sc->sc_dev.dv_xname);
if (!isapnp_find(sc))
panic("%s: no devices found\n", sc->sc_dev.dv_xname);
printf(": read port 0x%x\n", sc->sc_read_port);
for (c = 0; c < sc->sc_ncards; c++) {
struct isapnp_attach_args *ipa, *lpa;
/* Good morning card c */
isapnp_write_reg(sc, ISAPNP_WAKE, c + 1);
if ((ipa = isapnp_get_resource(sc, c)) == NULL)
continue;
DPRINTF(("Selecting attachments\n"));
for (d = 0; (lpa = isapnp_bestconfig(sc, &ipa)) != NULL; d++) {
isapnp_write_reg(sc, ISAPNP_LOGICAL_DEV_NUM, d);
isapnp_configure(sc, lpa);
#ifdef DEBUG_ISAPNP
{
struct isapnp_attach_args pa;
isapnp_get_config(sc, &pa);
isapnp_print_config(&pa);
}
#endif
#ifdef DEBUG
/* XXX do we even really need this? --thorpej */
printf("%s: configuring <%s, %s, %s>\n",
sc->sc_dev.dv_xname,
lpa->ipa_devident, lpa->ipa_devlogic,
lpa->ipa_devclass);
#endif
if (lpa->ipa_pref == ISAPNP_DEP_CONFLICTING) {
printf("%s: <%s, %s, %s> ignored; %s\n",
sc->sc_dev.dv_xname,
lpa->ipa_devident, lpa->ipa_devlogic,
lpa->ipa_devclass, "resource conflict");
ISAPNP_FREE(lpa);
continue;
}
lpa->ipa_ic = ia->ia_ic;
lpa->ipa_iot = ia->ia_iot;
lpa->ipa_memt = ia->ia_memt;
isapnp_write_reg(sc, ISAPNP_ACTIVATE, 1);
#ifdef _KERNEL
if(config_found_sm(self, lpa, isapnp_print,
isapnp_submatch) == NULL)
isapnp_write_reg(sc, ISAPNP_ACTIVATE, 0);
#else
isapnp_print(lpa, NULL);
printf("\n");
#endif
ISAPNP_FREE(lpa);
}
isapnp_write_reg(sc, ISAPNP_WAKE, 0); /* Good night cards */
}
}

View File

@ -0,0 +1,410 @@
/* $NetBSD: isapnpdebug.c,v 1.1 1997/01/16 22:01:00 christos Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef DEBUG_ISAPNP
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <dev/isa/isavar.h>
#include <dev/isapnp/isapnpreg.h>
#include <dev/isapnp/isapnpvar.h>
/* isapnp_print_mem():
* Print a memory tag
*/
void
isapnp_print_mem(str, mem)
const char *str;
const struct isapnp_region *mem;
{
printf("%s, Memory: %s,%sshadowable,decode-%s,%scacheable,%s", str,
(mem->flags & ISAPNP_MEMATTR_ROM) ? "ROM," : "RAM,",
(mem->flags & ISAPNP_MEMATTR_SHADOWABLE) ? "" : "non-",
(mem->flags & ISAPNP_MEMATTR_HIGH_ADDR) ?
"high-addr," : "range-len,",
(mem->flags & ISAPNP_MEMATTR_CACHEABLE) ? "" : "non-",
(mem->flags & ISAPNP_MEMATTR_WRITEABLE) ?
"writeable," : "read-only,");
switch (mem->flags & ISAPNP_MEMWIDTH_MASK) {
case ISAPNP_MEMWIDTH_8:
printf("8-bit ");
break;
case ISAPNP_MEMWIDTH_16:
printf("16-bit ");
break;
case ISAPNP_MEMWIDTH_8_16:
printf("8/16-bit ");
break;
case ISAPNP_MEMWIDTH_32:
printf("32-bit ");
break;
}
printf("min 0x%x, max 0x%x, ", mem->minbase, mem->maxbase);
printf("align 0x%x, length 0x%x\n", mem->align, mem->length);
}
/* isapnp_print_io():
* Print an io tag
*/
void
isapnp_print_io(str, io)
const char *str;
const struct isapnp_region *io;
{
printf("%d %s IO Ports: %d address bits, alignment %d ",
io->length, str, (io->flags & ISAPNP_IOFLAGS_16) ? 16 : 10,
io->align);
printf("min 0x%x, max 0x%x\n", io->minbase, io->maxbase);
}
/* isapnp_print_irq():
* Print an irq tag
*/
void
isapnp_print_irq(str, irq)
const char *str;
const struct isapnp_pin *irq;
{
int i;
printf("%sIRQ's supported: ", str);
for (i = 0; i < 16; i++)
if (irq->bits & (1 << i))
printf("%d ", i);
if (irq->flags & ISAPNP_IRQTYPE_EDGE_PLUS)
printf("E+");
if (irq->flags & ISAPNP_IRQTYPE_EDGE_MINUS)
printf("E-");
if (irq->flags & ISAPNP_IRQTYPE_LEVEL_PLUS)
printf("L+");
if (irq->flags & ISAPNP_IRQTYPE_LEVEL_MINUS)
printf("L-");
printf("\n");
}
/* isapnp_print_drq():
* Print a drq tag
*/
void
isapnp_print_drq(str, drq)
const char *str;
const struct isapnp_pin *drq;
{
int i;
u_char flags = drq->flags;
printf("%sDRQ's supported: ", str);
for (i = 0; i < 8; i++)
if (drq->bits & (1 << i))
printf("%d ", i);
printf("Width: ");
switch (flags & ISAPNP_DMAWIDTH_MASK) {
case ISAPNP_DMAWIDTH_8:
printf("8-bit ");
break;
case ISAPNP_DMAWIDTH_8_16:
printf("8/16-bit ");
break;
case ISAPNP_DMAWIDTH_16:
printf("16-bit ");
break;
case ISAPNP_DMAWIDTH_RESERVED:
printf("Reserved ");
break;
}
printf("Speed: ");
switch (flags & ISAPNP_DMASPEED_MASK) {
case ISAPNP_DMASPEED_COMPAT:
printf("compat ");
break;
case ISAPNP_DMASPEED_A:
printf("A ");
break;
case ISAPNP_DMASPEED_B:
printf("B ");
break;
case ISAPNP_DMASPEED_F:
printf("F ");
break;
}
if (flags & ISAPNP_DMAATTR_MASK)
printf("Attributes: %s%s%s",
(flags & ISAPNP_DMAATTR_BUS_MASTER) ? "bus master " : "",
(flags & ISAPNP_DMAATTR_INCR_8) ? "incr 8 " : "",
(flags & ISAPNP_DMAATTR_INCR_16) ? "incr 16 " : "");
printf("\n");
}
/* isapnp_print_dep_start():
* Print a start dependencies tag
*/
void
isapnp_print_dep_start(str, pref)
const char *str;
const u_char pref;
{
printf("%sconfig: ", str);
switch (pref) {
case ISAPNP_DEP_PREFERRED:
printf("preferred\n");
break;
case ISAPNP_DEP_ACCEPTABLE:
printf("acceptable\n");
break;
case ISAPNP_DEP_FUNCTIONAL:
printf("functional\n");
break;
case ISAPNP_DEP_UNSET: /* Used internally */
printf("unset\n");
break;
case ISAPNP_DEP_CONFLICTING: /* Used internally */
printf("conflicting\n");
break;
default:
printf("invalid\n");
break;
}
}
void
isapnp_print_attach(pa)
const struct isapnp_attach_args *pa;
{
int i;
printf("Found %s %s %s ", pa->ipa_devident,
pa->ipa_devlogic, pa->ipa_devclass);
isapnp_print_dep_start("", pa->ipa_pref);
for (i = 0; i < pa->ipa_nio; i++)
isapnp_print_io("", &pa->ipa_io[i]);
for (i = 0; i < pa->ipa_nmem; i++)
isapnp_print_mem("", &pa->ipa_mem[i]);
for (i = 0; i < pa->ipa_nirq; i++)
isapnp_print_irq("", &pa->ipa_irq[i]);
for (i = 0; i < pa->ipa_ndrq; i++)
isapnp_print_drq("", &pa->ipa_drq[i]);
for (i = 0; i < pa->ipa_nmem32; i++)
isapnp_print_mem("", &pa->ipa_mem32[i]);
}
/* isapnp_get_config():
* Get the current configuration of the card
*/
void
isapnp_get_config(sc, pa)
struct isapnp_softc *sc;
struct isapnp_attach_args *pa;
{
int i;
u_char v0, v1, v2, v3;
static u_char isapnp_mem_range[] = ISAPNP_MEM_DESC;
static u_char isapnp_io_range[] = ISAPNP_IO_DESC;
static u_char isapnp_irq_range[] = ISAPNP_IRQ_DESC;
static u_char isapnp_drq_range[] = ISAPNP_DRQ_DESC;
static u_char isapnp_mem32_range[] = ISAPNP_MEM32_DESC;
struct isapnp_region *r;
struct isapnp_pin *p;
memset(pa, 0, sizeof(*pa));
for (i = 0; i < sizeof(isapnp_io_range); i++) {
r = &pa->ipa_io[i];
v0 = isapnp_read_reg(sc,
isapnp_io_range[i] + ISAPNP_IO_BASE_15_8);
v1 = isapnp_read_reg(sc,
isapnp_io_range[i] + ISAPNP_IO_BASE_7_0);
r->base = (v0 << 8) | v1;
if (r->base == 0)
break;
}
pa->ipa_nio = i;
for (i = 0; i < sizeof(isapnp_mem_range); i++) {
r = &pa->ipa_mem[i];
v0 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_BASE_23_16);
v1 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_BASE_15_8);
r->base = (v0 << 16) | (v1 << 8);
if (r->base == 0)
break;
v0 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_23_16);
v1 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_15_8);
r->length = (v0 << 16) | (v1 << 8);
v0 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_CONTROL);
r->flags = 0;
if (v0 & ISAPNP_MEM_CONTROL_LIMIT)
r->flags |= ISAPNP_MEMATTR_HIGH_ADDR;
if (v0 & ISAPNP_MEM_CONTROL_16)
r->flags |= ISAPNP_MEMWIDTH_16;
}
pa->ipa_nmem = i;
for (i = 0; i < sizeof(isapnp_irq_range); i++) {
v0 = isapnp_read_reg(sc,
isapnp_irq_range[i] + ISAPNP_IRQ_NUMBER);
p = &pa->ipa_irq[i];
p->num = v0 & 0xf;
if (p->num == 0)
break;
switch (v0 & (ISAPNP_IRQ_LEVEL|ISAPNP_IRQ_HIGH)) {
case ISAPNP_IRQ_LEVEL|ISAPNP_IRQ_HIGH:
p->flags = ISAPNP_IRQTYPE_LEVEL_PLUS;
break;
case ISAPNP_IRQ_HIGH:
p->flags = ISAPNP_IRQTYPE_EDGE_PLUS;
break;
case ISAPNP_IRQ_LEVEL:
p->flags = ISAPNP_IRQTYPE_LEVEL_MINUS;
break;
default:
p->flags = ISAPNP_IRQTYPE_EDGE_MINUS;
break;
}
}
pa->ipa_nirq = i;
for (i = 0; i < sizeof(isapnp_drq_range); i++) {
v0 = isapnp_read_reg(sc, isapnp_drq_range[i]);
p = &pa->ipa_drq[i];
p->num = v0 & 0xf;
if (p->num == 4)
break;
}
pa->ipa_ndrq = i;
for (i = 0; i < sizeof(isapnp_mem32_range); i++) {
r = &pa->ipa_mem32[i];
v0 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_31_24);
v1 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_23_16);
v2 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_15_8);
v3 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_7_0);
r->base = (v0 << 24) | (v1 << 16) | (v2 << 8) | v3;
if (r->base == 0)
break;
v0 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_31_24);
v1 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_23_16);
v2 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_15_8);
v3 = isapnp_read_reg(sc,
isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_7_0);
r->length = (v0 << 24) | (v1 << 16) | (v2 << 8) | v3;
v0 = isapnp_read_reg(sc,
isapnp_mem_range[i] + ISAPNP_MEM_CONTROL);
r->flags = v0;
}
pa->ipa_nmem32 = i;
}
/* isapnp_print_config():
* Print the current configuration of the card
*/
void
isapnp_print_config(pa)
const struct isapnp_attach_args *pa;
{
int i;
const struct isapnp_region *r;
const struct isapnp_pin *p;
printf("Register configuration:\n");
if (pa->ipa_nio)
for (i = 0; i < pa->ipa_nio; i++) {
r = &pa->ipa_io[i];
printf("io[%d]: 0x%x/%d\n", i, r->base, r->length);
}
if (pa->ipa_nmem)
for (i = 0; i < pa->ipa_nmem; i++) {
r = &pa->ipa_mem[i];
printf("mem[%d]: 0x%x/%d\n", i, r->base, r->length);
}
if (pa->ipa_nirq)
for (i = 0; i < pa->ipa_nirq; i++) {
p = &pa->ipa_irq[i];
printf("irq[%d]: %d\n", i, p->num);
}
if (pa->ipa_nirq)
for (i = 0; i < pa->ipa_ndrq; i++) {
p = &pa->ipa_drq[i];
printf("drq[%d]: %d\n", i, p->num);
}
if (pa->ipa_nmem32)
for (i = 0; i < pa->ipa_nmem32; i++) {
r = &pa->ipa_mem32[i];
printf("mem32[%d]: 0x%x/%d\n", i, r->base, r->length);
}
}
#endif

171
sys/dev/isapnp/isapnpreg.h Normal file
View File

@ -0,0 +1,171 @@
/* $NetBSD: isapnpreg.h,v 1.1 1997/01/16 22:01:02 christos Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ISA Plug and Play register definitions;
* From Plug and Play ISA Specification V1.0a, May 5 1994
*/
#define ISAPNP_MAX_CARDS 8
#define ISAPNP_MAX_IDENT 32
#define ISAPNP_MAX_DEVCLASS 8
#define ISAPNP_SERIAL_SIZE 9
#define ISAPNP_MAX_TAGSIZE 256
#define ISAPNP_ADDR 0x279 /* Write only */
#define ISAPNP_WRDATA 0xa79 /* Write only */
/* The read port is in range 0x203 to 0x3ff */
#define ISAPNP_RDDATA_MIN 0x203 /* Read only */
#define ISAPNP_RDDATA_MAX 0x3ff
#define ISAPNP_LFSR_INIT 0x6A /* Initial value of LFSR sequence */
/* Formula to compute the next value */
#define ISAPNP_LFSR_NEXT(v) (((v) >> 1) | (((v) & 1) ^ (((v) & 2) >> 1)) << 7)
#define ISAPNP_SET_RD_PORT 0x00
#define ISAPNP_SERIAL_ISOLATION 0x01
#define ISAPNP_CONFIG_CONTROL 0x02
#define ISAPNP_CC_RESET 0x01
#define ISAPNP_CC_WAIT_FOR KEY 0x02
#define ISAPNP_CC_RESET_CSN 0x04
#define ISAPNP_CC_RESET_DRV 0x07
#define ISAPNP_WAKE 0x03
#define ISAPNP_RESOURCE_DATA 0x04
#define ISAPNP_STATUS 0x05
#define ISAPNP_CARD_SELECT_NUM 0x06
#define ISAPNP_LOGICAL_DEV_NUM 0x07
#define ISAPNP_ACTIVATE 0x30
#define ISAPNP_IO_RANGE_CHECK 0x31
#define ISAPNP_NUM_MEM 4
#define ISAPNP_MEM_DESC { 0x40, 0x48, 0x50, 0x58 }
#define ISAPNP_MEM_BASE_23_16 0x0
#define ISAPNP_MEM_BASE_15_8 0x1
#define ISAPNP_MEM_CONTROL 0x2
#define ISAPNP_MEM_CONTROL_LIMIT 1
#define ISAPNP_MEM_CONTROL_16 2
#define ISAPNP_MEM_LRANGE_23_16 0x3
#define ISAPNP_MEM_LRANGE_15_8 0x4
#define ISAPNP_NUM_IO 8
#define ISAPNP_IO_DESC { 0x60, 0x62, 0x64, 0x68, 0x6a, 0x6c, 0x6e }
#define ISAPNP_IO_BASE_15_8 0x0
#define ISAPNP_IO_BASE_7_0 0x1
#define ISAPNP_NUM_IRQ 16
#define ISAPNP_IRQ_DESC { 0x70, 0x72 }
#define ISAPNP_IRQ_NUMBER 0x0
#define ISAPNP_IRQ_CONTROL 0x1
#define ISAPNP_IRQ_LEVEL 1
#define ISAPNP_IRQ_HIGH 2
#define ISAPNP_NUM_DRQ 8
#define ISAPNP_DRQ_DESC { 0x74, 0x72 }
#define ISAPNP_NUM_MEM32 4
#define ISAPNP_MEM32_DESC { 0x76, 0x80, 0x90, 0xa0 }
#define ISAPNP_MEM32_BASE_31_24 0x0
#define ISAPNP_MEM32_BASE_23_16 0x1
#define ISAPNP_MEM32_BASE_15_8 0x2
#define ISAPNP_MEM32_BASE_7_0 0x3
#define ISAPNP_MEM32_CONTROL 0x4
#define ISAPNP_MEM32_CONTROL_LIMIT 1
#define ISAPNP_MEM32_CONTROL_16 2
#define ISAPNP_MEM32_CONTROL_32 6
#define ISAPNP_MEM32_LRANGE_31_24 0x5
#define ISAPNP_MEM32_LRANGE_23_16 0x6
#define ISAPNP_MEM32_LRANGE_15_8 0x7
#define ISAPNP_MEM32_LRANGE_7_0 0x8
/* Small Tags */
#define ISAPNP_TAG_VERSION_NUM 0x1
#define ISAPNP_TAG_LOGICAL_DEV_ID 0x2
#define ISAPNP_TAG_COMPAT_DEV_ID 0x3
#define ISAPNP_TAG_IRQ_FORMAT 0x4
#define ISAPNP_IRQTYPE_EDGE_PLUS 1
#define ISAPNP_IRQTYPE_EDGE_MINUS 2
#define ISAPNP_IRQTYPE_LEVEL_PLUS 4
#define ISAPNP_IRQTYPE_LEVEL_MINUS 8
#define ISAPNP_TAG_DMA_FORMAT 0x5
#define ISAPNP_DMAWIDTH_8 0x00
#define ISAPNP_DMAWIDTH_8_16 0x01
#define ISAPNP_DMAWIDTH_16 0x02
#define ISAPNP_DMAWIDTH_RESERVED 0x03
#define ISAPNP_DMAWIDTH_MASK 0x03
#define ISAPNP_DMAATTR_BUS_MASTER 0x04
#define ISAPNP_DMAATTR_INCR_8 0x08
#define ISAPNP_DMAATTR_INCR_16 0x10
#define ISAPNP_DMAATTR_MASK 0x1c
#define ISAPNP_DMASPEED_COMPAT 0x00
#define ISAPNP_DMASPEED_A 0x20
#define ISAPNP_DMASPEED_B 0x40
#define ISAPNP_DMASPEED_F 0x60
#define ISAPNP_DMASPEED_MASK 0x60
#define ISAPNP_TAG_DEP_START 0x6
#define ISAPNP_DEP_PREFERRED 0x0
#define ISAPNP_DEP_ACCEPTABLE 0x1
#define ISAPNP_DEP_FUNCTIONAL 0x2
#define ISAPNP_DEP_RESERVED 0x3
#define ISAPNP_DEP_MASK 0x3
#define ISAPNP_DEP_UNSET 0x80 /* Internal */
#define ISAPNP_DEP_CONFLICTING 0x81 /* Internal */
#define ISAPNP_TAG_DEP_END 0x7
#define ISAPNP_TAG_IO_PORT_DESC 0x8
#define ISAPNP_IOFLAGS_16 0x1
#define ISAPNP_TAG_FIXED_IO_PORT_DESC 0x9
#define ISAPNP_TAG_RESERVED1 0xa
#define ISAPNP_TAG_RESERVED2 0xb
#define ISAPNP_TAG_RESERVED3 0xc
#define ISAPNP_TAG_RESERVED4 0xd
#define ISAPNP_TAG_VENDOR_DEF 0xe
#define ISAPNP_TAG_END 0xf
/* Large Tags */
#define ISAPNP_LARGE_TAG 0x80
#define ISAPNP_TAG_MEM_RANGE_DESC 0x81
#define ISAPNP_MEMATTR_WRITEABLE 0x01
#define ISAPNP_MEMATTR_CACHEABLE 0x02
#define ISAPNP_MEMATTR_HIGH_ADDR 0x04
#define ISAPNP_MEMATTR_SHADOWABLE 0x20
#define ISAPNP_MEMATTR_ROM 0x40
#define ISAPNP_MEMATTR_MASK 0x67
#define ISAPNP_MEMWIDTH_8 0x00
#define ISAPNP_MEMWIDTH_16 0x08
#define ISAPNP_MEMWIDTH_8_16 0x10
#define ISAPNP_MEMWIDTH_32 0x18
#define ISAPNP_MEMWIDTH_MASK 0x18
#define ISAPNP_TAG_ANSI_IDENT_STRING 0x82
#define ISAPNP_TAG_UNICODE_IDENT_STRING 0x83
#define ISAPNP_TAG_VENDOR_DEFINED 0x84
#define ISAPNP_TAG_MEM32_RANGE_DESC 0x85
#define ISAPNP_TAG_FIXED_MEM32_RANGE_DESC 0x86

355
sys/dev/isapnp/isapnpres.c Normal file
View File

@ -0,0 +1,355 @@
/* $NetBSD: isapnpres.c,v 1.1 1997/01/16 22:01:03 christos Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Resource parser for Plug and Play cards.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/isa/isavar.h>
#include <dev/isapnp/isapnpreg.h>
#include <dev/isapnp/isapnpvar.h>
static int isapnp_wait_status __P((struct isapnp_softc *));
static struct isapnp_attach_args *isapnp_process_tag __P((u_char, u_char,
u_char *, struct isapnp_attach_args *));
/* isapnp_wait_status():
* Wait for the next byte of resource data to become available
*/
static int
isapnp_wait_status(sc)
struct isapnp_softc *sc;
{
int i;
for (i = 0; i < 10; i++) {
if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
return 0;
DELAY(10);
}
return 1;
}
/* isapnp_process_tag():
* Process a resource tag
*/
static struct isapnp_attach_args *
isapnp_process_tag(tag, len, buf, pa)
u_char tag, len, *buf;
struct isapnp_attach_args *pa;
{
struct isapnp_attach_args *npa;
char str[64];
struct isapnp_region *r;
struct isapnp_pin *p;
#define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
switch (tag) {
case ISAPNP_TAG_VERSION_NUM:
DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4, buf[1] & 0xf));
break;
case ISAPNP_TAG_LOGICAL_DEV_ID:
(void) isapnp_id_to_vendor(str, buf);
DPRINTF(("Logical device id %s\n", str));
COPY(pa->ipa_devlogic, str);
break;
case ISAPNP_TAG_COMPAT_DEV_ID:
(void) isapnp_id_to_vendor(str, buf);
DPRINTF(("Compatible device id %s\n", str));
break;
case ISAPNP_TAG_IRQ_FORMAT:
if (len < 2)
break;
if (len != 3)
buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
p = &pa->ipa_irq[pa->ipa_nirq++];
p->bits = buf[0] | (buf[1] << 8);
p->flags = buf[2];
#ifdef DEBUG_ISAPNP
isapnp_print_irq("", p);
#endif
break;
case ISAPNP_TAG_DMA_FORMAT:
if (buf[0] == 0)
break;
p = &pa->ipa_drq[pa->ipa_ndrq++];
p->bits = buf[0];
p->flags = buf[1];
#ifdef DEBUG_ISAPNP
isapnp_print_drq("", p);
#endif
break;
case ISAPNP_TAG_DEP_START:
if (len == 0)
buf[0] = ISAPNP_DEP_ACCEPTABLE;
if (pa->ipa_pref != ISAPNP_DEP_UNSET) {
npa = ISAPNP_MALLOC(sizeof(*npa));
memset(npa, 0, sizeof(*npa));
memcpy(npa->ipa_devident, pa->ipa_devident,
sizeof(pa->ipa_devident));
memcpy(npa->ipa_devlogic, pa->ipa_devlogic,
sizeof(pa->ipa_devlogic));
memcpy(npa->ipa_devclass, pa->ipa_devclass,
sizeof(pa->ipa_devclass));
pa->ipa_next = npa;
pa = npa;
}
pa->ipa_pref = buf[0];
#ifdef DEBUG_ISAPNP
isapnp_print_dep_start(">>> Start dependent functions ",
pa->ipa_pref);
#endif
break;
case ISAPNP_TAG_DEP_END:
DPRINTF(("<<<End dependend functions\n"));
npa = ISAPNP_MALLOC(sizeof(*npa));
memset(npa, 0, sizeof(*npa));
npa->ipa_pref = ISAPNP_DEP_UNSET;
memcpy(npa->ipa_devident, pa->ipa_devident,
sizeof(pa->ipa_devident));
pa->ipa_next = npa;
pa = npa;
break;
case ISAPNP_TAG_IO_PORT_DESC:
r = &pa->ipa_io[pa->ipa_nio++];
r->flags = buf[0];
r->minbase = (buf[2] << 8) | buf[1];
r->maxbase = (buf[4] << 8) | buf[3];
r->align = buf[5];
r->length = buf[6];
#ifdef DEBUG_ISAPNP
isapnp_print_io("", r);
#endif
break;
case ISAPNP_TAG_FIXED_IO_PORT_DESC:
r = &pa->ipa_io[pa->ipa_nio++];
r->flags = 0;
r->minbase = (buf[2] << 8) | buf[1];
r->maxbase = r->minbase;
r->align = 1;
r->length = buf[3];
#ifdef DEBUG_ISAPNP
isapnp_print_io("FIXED", r);
#endif
break;
case ISAPNP_TAG_RESERVED1:
case ISAPNP_TAG_RESERVED2:
case ISAPNP_TAG_RESERVED3:
case ISAPNP_TAG_RESERVED4:
break;
case ISAPNP_TAG_VENDOR_DEF:
break;
case ISAPNP_TAG_END:
break;
case ISAPNP_TAG_MEM_RANGE_DESC:
r = &pa->ipa_mem[pa->ipa_nmem++];
r->minbase = (buf[2] << 8) | buf[1];
r->maxbase = (buf[4] << 8) | buf[3];
r->align = (buf[6] << 8) | buf[5];
r->length = (buf[8] << 8) | buf[7];
#ifdef DEBUG_ISAPNP
isapnp_print_mem("16 bit", r);
#endif
break;
case ISAPNP_TAG_ANSI_IDENT_STRING:
buf[len] = '\0';
DPRINTF(("ANSI Ident: %s\n", buf));
if (pa->ipa_devident[0] == '\0')
COPY(pa->ipa_devident, buf);
else
COPY(pa->ipa_devclass, buf);
break;
case ISAPNP_TAG_UNICODE_IDENT_STRING:
buf[len] = '\0';
DPRINTF(("Unicode Ident: %s\n", buf));
break;
case ISAPNP_TAG_VENDOR_DEFINED:
break;
case ISAPNP_TAG_MEM32_RANGE_DESC:
r = &pa->ipa_mem32[pa->ipa_nmem32++];
r->flags = buf[0];
r->minbase = (buf[4] << 24) | (buf[3] << 16) |
(buf[2] << 8) | buf[1];
r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
(buf[6] << 8) | buf[5];
r->align = (buf[12] << 24) | (buf[11] << 16) |
(buf[10] << 8) | buf[9];
r->length = (buf[16] << 24) | (buf[15] << 16) |
(buf[14] << 8) | buf[13];
#ifdef DEBUG_ISAPNP
isapnp_print_mem("32 bit", r);
#endif
break;
case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
r = &pa->ipa_mem32[pa->ipa_nmem32++];
r->flags = buf[0];
r->minbase = (buf[4] << 24) | (buf[3] << 16) |
(buf[2] << 8) | buf[1];
r->maxbase = r->minbase;
r->align = 1;
r->length = (buf[8] << 24) | (buf[7] << 16) |
(buf[6] << 8) | buf[5];
#ifdef DEBUG_ISAPNP
isapnp_print_mem("FIXED 32 bit", r);
#endif
break;
default:
#ifdef DEBUG_ISAPNP
{
int i;
printf("tag %.2x, len %d: ", tag, len);
for (i = 0; i < len; i++)
printf("%.2x ", buf[i]);
printf("\n");
}
#endif
break;
}
return pa;
}
/* isapnp_get_resource():
* Read the resources for card c
*/
struct isapnp_attach_args *
isapnp_get_resource(sc, c)
struct isapnp_softc *sc;
int c;
{
u_char d, tag;
u_short len;
int i;
struct isapnp_attach_args *ipa, *pa;
pa = ipa = ISAPNP_MALLOC(sizeof(*ipa));
memset(ipa, 0, sizeof(*ipa));
pa->ipa_pref = ISAPNP_DEP_UNSET;
for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
if (isapnp_wait_status(sc))
goto bad;
d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA);
if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
printf("isapnp: card %d violates PnP spec; byte %d\n",
c + 1, i);
break;
}
}
do {
u_char buf[ISAPNP_MAX_TAGSIZE], *p;
memset(buf, 0, sizeof(buf));
#define NEXT_BYTE \
if (isapnp_wait_status(sc)) \
goto bad; \
d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA);
NEXT_BYTE;
if (d & ISAPNP_LARGE_TAG) {
tag = d;
NEXT_BYTE;
buf[0] = d;
NEXT_BYTE;
buf[1] = d;
len = (buf[1] << 8) | buf[0];
}
else {
tag = (d >> 3) & 0xf;
len = d & 0x7;
}
for (p = buf, i = 0; i < len; i++) {
NEXT_BYTE;
if (i < ISAPNP_MAX_TAGSIZE)
*p++ = d;
}
if (len >= ISAPNP_MAX_TAGSIZE) {
printf("isapnp: Maximum tag size exceeded, card %d\n",
c + 1);
len = ISAPNP_MAX_TAGSIZE;
}
pa = isapnp_process_tag(tag, len, buf, pa);
}
while (tag != ISAPNP_TAG_END);
return ipa;
bad:
while (ipa) {
pa = ipa->ipa_next;
ISAPNP_FREE(ipa);
ipa = pa;
}
printf("isapnp: Resource timeout, card %d\n", c + 1);
return NULL;
}

194
sys/dev/isapnp/isapnpvar.h Normal file
View File

@ -0,0 +1,194 @@
/* $NetBSD: isapnpvar.h,v 1.1 1997/01/16 22:01:05 christos Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christos Zoulas.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_ISAPNP_ISAPNPVAR_H_
#define _DEV_ISAPNP_ISAPNPVAR_H_
/*
* ISA Plug and Play register definitions;
* From Plug and Play ISA Specification V1.0a, May 5 1994
*/
/*
* Structures and definitions needed by the machine-dependent header.
*/
struct isapnp_softc;
#if (i386 != 1)
ERROR: COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE.
#endif
#if i386
#include <i386/isa/isapnp_machdep.h>
#endif
#ifndef _KERNEL
# include <string.h>
# include <unistd.h>
# include <stdlib.h>
# define ISAPNP_WRITE_ADDR(sc, v) outb(ISAPNP_ADDR, v)
# define ISAPNP_WRITE_DATA(sc, v) outb(ISAPNP_WRDATA, v)
# define ISAPNP_READ_DATA(sc) inb(sc->sc_read_port)
# define DELAY(us) usleep(us)
# define ISAPNP_MALLOC(a) malloc(a)
# define ISAPNP_FREE(a) free(a)
# define bus_space_map(a, b, c, d, e) 0
# define bus_space_unmap(a, b, c)
# define panic printf
#else
/* XXX */
# define memset(a, b, c) bzero(a, c)
# define ISAPNP_WRITE_ADDR(sc, v) \
bus_space_write_1(sc->sc_iot, sc->sc_addr_ioh, 0, v)
#define ISAPNP_WRITE_DATA(sc, v) \
bus_space_write_1(sc->sc_iot, sc->sc_wrdata_ioh, 0, v)
#define ISAPNP_READ_DATA(sc) \
bus_space_read_1(sc->sc_iot, sc->sc_read_ioh, 0)
#define ISAPNP_MALLOC(a) malloc(a, M_DEVBUF, M_WAITOK)
#define ISAPNP_FREE(a) free(a, M_DEVBUF)
#endif
#ifdef DEBUG_ISAPNP
# define DPRINTF(a) printf a
#else
# define DPRINTF(a)
#endif
struct isapnp_softc {
struct device sc_dev;
int sc_read_port;
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_addr_ioh;
bus_space_handle_t sc_wrdata_ioh;
bus_space_handle_t sc_read_ioh;
bus_space_handle_t sc_memh;
u_int8_t sc_ncards;
u_int8_t sc_id[ISAPNP_MAX_CARDS][ISAPNP_SERIAL_SIZE];
};
struct isapnp_region {
bus_space_handle_t h;
u_int32_t base;
u_int32_t minbase;
u_int32_t maxbase;
u_int32_t length;
u_int32_t align;
u_int8_t flags;
};
struct isapnp_pin {
u_int8_t num;
u_int16_t bits;
u_int8_t flags;
};
struct isapnp_attach_args {
bus_space_tag_t ipa_iot; /* isa i/o space tag */
bus_space_tag_t ipa_memt; /* isa mem space tag */
isa_chipset_tag_t ipa_ic;
struct isapnp_attach_args *ipa_next;
char ipa_devident[ISAPNP_MAX_IDENT];
char ipa_devlogic[ISAPNP_MAX_DEVCLASS];
char ipa_devclass[ISAPNP_MAX_DEVCLASS];
u_char ipa_pref;
u_char ipa_devnum;
u_char ipa_nio;
u_char ipa_nirq;
u_char ipa_ndrq;
u_char ipa_nmem;
u_char ipa_nmem32;
struct isapnp_region ipa_io[ISAPNP_NUM_IO];
struct isapnp_region ipa_mem[ISAPNP_NUM_MEM];
struct isapnp_region ipa_mem32[ISAPNP_NUM_MEM32];
struct isapnp_pin ipa_irq[ISAPNP_NUM_IRQ];
struct isapnp_pin ipa_drq[ISAPNP_NUM_DRQ];
};
static __inline void isapnp_write_reg __P((struct isapnp_softc *, int, u_char));
static __inline u_char isapnp_read_reg __P((struct isapnp_softc *, int));
static __inline void
isapnp_write_reg(sc, r, v)
struct isapnp_softc *sc;
int r;
u_char v;
{
ISAPNP_WRITE_ADDR(sc, r);
ISAPNP_WRITE_DATA(sc, v);
}
static __inline u_char
isapnp_read_reg(sc, r)
struct isapnp_softc *sc;
{
ISAPNP_WRITE_ADDR(sc, r);
return ISAPNP_READ_DATA(sc);
}
struct isapnp_attach_args *
isapnp_get_resource __P((struct isapnp_softc *, int));
char *isapnp_id_to_vendor __P((char *, const u_char *));
int isapnp_config __P((bus_space_tag_t, bus_space_tag_t,
struct isapnp_attach_args *));
void isapnp_unconfig __P((bus_space_tag_t, bus_space_tag_t,
struct isapnp_attach_args *));
#ifdef DEBUG_ISAPNP
void isapnp_print_mem __P((const char *, const struct isapnp_region *));
void isapnp_print_io __P((const char *, const struct isapnp_region *));
void isapnp_print_irq __P((const char *, const struct isapnp_pin *));
void isapnp_print_drq __P((const char *, const struct isapnp_pin *));
void isapnp_print_dep_start __P((const char *, const u_char));
void isapnp_print_attach __P((const struct isapnp_attach_args *));
void isapnp_get_config __P((struct isapnp_softc *,
struct isapnp_attach_args *));
void isapnp_print_config __P((const struct isapnp_attach_args *));
#endif
#endif /* ! _DEV_ISAPNP_ISAPNPVAR_H_ */

126
sys/dev/isapnp/sb_isapnp.c Normal file
View File

@ -0,0 +1,126 @@
/* $NetBSD: sb_isapnp.c,v 1.1 1997/01/16 22:01:08 christos Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <machine/bus.h>
#include <sys/audioio.h>
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
#include <dev/isapnp/isapnpreg.h>
#include <dev/isapnp/isapnpvar.h>
#include <dev/isa/sbreg.h>
#include <dev/isa/sbvar.h>
#include <dev/isa/sbdspvar.h>
int sb_isapnp_match __P((struct device *, void *, void *));
void sb_isapnp_attach __P((struct device *, struct device *, void *));
struct cfattach sb_isapnp_ca = {
sizeof(struct sbdsp_softc), sb_isapnp_match, sb_isapnp_attach
};
/*
* Probe / attach routines.
*/
/*
* Probe for the soundblaster hardware.
*/
int
sb_isapnp_match(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct isapnp_attach_args *ipa = aux;
return strcmp(ipa->ipa_devlogic, "CTL0001") == 0;
}
/*
* Attach hardware to driver, attach hardware driver to audio
* pseudo-device driver.
*/
void
sb_isapnp_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct sbdsp_softc *sc = (struct sbdsp_softc *)self;
struct isapnp_attach_args *ipa = aux;
sc->sc_ic = ipa->ipa_ic;
sc->sc_iot = ipa->ipa_iot;
sc->sc_iobase = ipa->ipa_io[0].base;
sc->sc_ioh = ipa->ipa_io[0].h;
sc->sc_irq = ipa->ipa_irq[0].num;
sc->sc_drq = ipa->ipa_drq[0].num;
sc->sc_drq16 = ipa->ipa_drq[1].num;
printf("\n");
if (isapnp_config(ipa->ipa_iot, ipa->ipa_memt, ipa)) {
printf("%s: error in region allocation\n", sc->sc_dev.dv_xname);
return;
}
if (!sbmatch(sc)) {
printf("%s: sbmatch failed\n", sc->sc_dev.dv_xname);
return;
}
printf("%s: %s %s", sc->sc_dev.dv_xname, ipa->ipa_devident,
ipa->ipa_devclass);
sbattach(sc);
}