/*	$OpenBSD: isapnpdebug.c,v 1.3 2002/12/15 13:17:04 henning Exp $	*/
/*	$NetBSD: isapnpdebug.c,v 1.4 1997/08/03 08:12:23 mikel 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/isapnpreg.h>

#include <dev/isa/isavar.h>

/* isapnp_print_mem():
 *	Print a memory tag
 */
void
isapnp_print_mem(str, mem)
	const char *str;
	const struct isapnp_region *mem;
{
	printf("%sMemory: %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) ?
		"writable," : "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 %sIO 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 isa_attach_args *pa;
{
	int i;

	printf("Found <%s, %s, %s, %s> ", pa->ipa_devident,
	    pa->ipa_devlogic, pa->ipa_devcompat, 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 isa_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;

	bzero(pa, 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 isa_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_ndrq)
		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