150769Sdfr/*
250769Sdfr * Copyright (c) 1996, Sujal M. Patel
350769Sdfr * All rights reserved.
450769Sdfr *
550769Sdfr * Redistribution and use in source and binary forms, with or without
650769Sdfr * modification, are permitted provided that the following conditions
750769Sdfr * are met:
850769Sdfr * 1. Redistributions of source code must retain the above copyright
950769Sdfr *    notice, this list of conditions and the following disclaimer.
1050769Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1150769Sdfr *    notice, this list of conditions and the following disclaimer in the
1250769Sdfr *    documentation and/or other materials provided with the distribution.
1350769Sdfr *
1450769Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550769Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650769Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750769Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850769Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950769Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050769Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150769Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250769Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350769Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450769Sdfr * SUCH DAMAGE.
2550769Sdfr *
2650769Sdfr *      from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp
2750769Sdfr */
2850769Sdfr
29116181Sobrien#include <sys/cdefs.h>
30116181Sobrien__FBSDID("$FreeBSD$");
31116181Sobrien
3250769Sdfr#include <sys/param.h>
3350769Sdfr#include <sys/systm.h>
3450769Sdfr#include <sys/kernel.h>
3550769Sdfr#include <sys/module.h>
3650769Sdfr#include <sys/bus.h>
37150687Smarius#include <sys/endian.h>
3850769Sdfr#include <sys/malloc.h>
3950769Sdfr#include <isa/isavar.h>
4050769Sdfr#include <isa/pnpreg.h>
4150769Sdfr#include <isa/pnpvar.h>
4265176Sdfr#include <machine/bus.h>
4350769Sdfr
4450769Sdfrtypedef struct _pnp_id {
45139268Simp	uint32_t vendor_id;
46139268Simp	uint32_t serial;
4750769Sdfr	u_char checksum;
4850769Sdfr} pnp_id;
4950769Sdfr
5050769Sdfrstruct pnp_set_config_arg {
5150769Sdfr	int	csn;		/* Card number to configure */
5250769Sdfr	int	ldn;		/* Logical device on card */
5350769Sdfr};
5450769Sdfr
5550769Sdfrstruct pnp_quirk {
56139268Simp	uint32_t vendor_id;	/* Vendor of the card */
57139268Simp	uint32_t logical_id;	/* ID of the device with quirk */
5850769Sdfr	int	type;
5950769Sdfr#define PNP_QUIRK_WRITE_REG	1 /* Need to write a pnp register  */
6062947Stanimura#define PNP_QUIRK_EXTRA_IO	2 /* Has extra io ports  */
6150769Sdfr	int	arg1;
6250769Sdfr	int	arg2;
6350769Sdfr};
6450769Sdfr
6550769Sdfrstruct pnp_quirk pnp_quirks[] = {
6650769Sdfr	/*
6750769Sdfr	 * The Gravis UltraSound needs register 0xf2 to be set to 0xff
6850769Sdfr	 * to enable power.
6950769Sdfr	 * XXX need to know the logical device id.
7050769Sdfr	 */
7150769Sdfr	{ 0x0100561e /* GRV0001 */,	0,
7250769Sdfr	  PNP_QUIRK_WRITE_REG,	0xf2,	 0xff },
7362947Stanimura	/*
7462947Stanimura	 * An emu8000 does not give us other than the first
7562947Stanimura	 * port.
7662947Stanimura	 */
7762947Stanimura	{ 0x26008c0e /* SB16 */,	0x21008c0e,
7862947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
7962947Stanimura	{ 0x42008c0e /* SB32(CTL0042) */,	0x21008c0e,
8062947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
8162947Stanimura	{ 0x44008c0e /* SB32(CTL0044) */,	0x21008c0e,
8262947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
8362947Stanimura	{ 0x49008c0e /* SB32(CTL0049) */,	0x21008c0e,
8462947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
8562947Stanimura	{ 0xf1008c0e /* SB32(CTL00f1) */,	0x21008c0e,
8662947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
8762947Stanimura	{ 0xc1008c0e /* SB64(CTL00c1) */,	0x22008c0e,
8862947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
8990234Stanimura	{ 0xc5008c0e /* SB64(CTL00c5) */,	0x22008c0e,
9090234Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
9162947Stanimura	{ 0xe4008c0e /* SB64(CTL00e4) */,	0x22008c0e,
9262947Stanimura	  PNP_QUIRK_EXTRA_IO,	0x400,	 0x800 },
9350769Sdfr
9450769Sdfr	{ 0 }
9550769Sdfr};
9650769Sdfr
97104142Snyan#ifdef PC98
98104142Snyan/* Some NEC PnP cards have 9 bytes serial code. */
99104142Snyanstatic pnp_id necids[] = {
100104142Snyan	{0x4180a3b8, 0xffffffff, 0x00},	/* PC-9801CB-B04 (NEC8041) */
101104142Snyan	{0x5181a3b8, 0xffffffff, 0x46},	/* PC-9821CB2-B04(NEC8151) */
102104142Snyan	{0x5182a3b8, 0xffffffff, 0xb8},	/* PC-9801-XX    (NEC8251) */
103104142Snyan	{0x9181a3b8, 0xffffffff, 0x00},	/* PC-9801-120   (NEC8191) */
104104142Snyan	{0, 0, 0}
105104142Snyan};
106104142Snyan#endif
107104142Snyan
10850769Sdfr/* The READ_DATA port that we are using currently */
10950769Sdfrstatic int pnp_rd_port;
11050769Sdfr
11150769Sdfrstatic void   pnp_send_initiation_key(void);
11250769Sdfrstatic int    pnp_get_serial(pnp_id *p);
11350769Sdfrstatic int    pnp_isolation_protocol(device_t parent);
11450769Sdfr
11552241Sdfrchar *
116139268Simppnp_eisaformat(uint32_t id)
11752241Sdfr{
118150687Smarius	uint8_t *data;
11952241Sdfr	static char idbuf[8];
12052241Sdfr	const char  hextoascii[] = "0123456789abcdef";
12152241Sdfr
122150687Smarius	id = htole32(id);
123150687Smarius	data = (uint8_t *)&id;
12452241Sdfr	idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
12552241Sdfr	idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
12652241Sdfr	idbuf[2] = '@' + (data[1] & 0x1f);
12752241Sdfr	idbuf[3] = hextoascii[(data[2] >> 4)];
12852241Sdfr	idbuf[4] = hextoascii[(data[2] & 0xf)];
12952241Sdfr	idbuf[5] = hextoascii[(data[3] >> 4)];
13052241Sdfr	idbuf[6] = hextoascii[(data[3] & 0xf)];
13152241Sdfr	idbuf[7] = 0;
13252241Sdfr	return(idbuf);
13352241Sdfr}
13452241Sdfr
13550769Sdfrstatic void
13650769Sdfrpnp_write(int d, u_char r)
13750769Sdfr{
13850769Sdfr	outb (_PNP_ADDRESS, d);
13950769Sdfr	outb (_PNP_WRITE_DATA, r);
14050769Sdfr}
14150769Sdfr
14250769Sdfr/*
14350769Sdfr * Send Initiation LFSR as described in "Plug and Play ISA Specification",
14450769Sdfr * Intel May 94.
14550769Sdfr */
14650769Sdfrstatic void
14750769Sdfrpnp_send_initiation_key()
14850769Sdfr{
14950769Sdfr	int cur, i;
15050769Sdfr
15150769Sdfr	/* Reset the LSFR */
15250769Sdfr	outb(_PNP_ADDRESS, 0);
15350769Sdfr	outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
15450769Sdfr
15550769Sdfr	cur = 0x6a;
15650769Sdfr	outb(_PNP_ADDRESS, cur);
15750769Sdfr
15850769Sdfr	for (i = 1; i < 32; i++) {
15950769Sdfr		cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
16050769Sdfr		outb(_PNP_ADDRESS, cur);
16150769Sdfr	}
16250769Sdfr}
16350769Sdfr
16450769Sdfr
16550769Sdfr/*
16650769Sdfr * Get the device's serial number.  Returns 1 if the serial is valid.
16750769Sdfr */
16850769Sdfrstatic int
16950769Sdfrpnp_get_serial(pnp_id *p)
17050769Sdfr{
17150769Sdfr	int i, bit, valid = 0, sum = 0x6a;
17250769Sdfr	u_char *data = (u_char *)p;
17350769Sdfr
17450769Sdfr	bzero(data, sizeof(char) * 9);
17550769Sdfr	outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
17650769Sdfr	for (i = 0; i < 72; i++) {
17750769Sdfr		bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;
17850769Sdfr		DELAY(250);	/* Delay 250 usec */
17950769Sdfr
18050769Sdfr		/* Can't Short Circuit the next evaluation, so 'and' is last */
18150769Sdfr		bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;
18250769Sdfr		DELAY(250);	/* Delay 250 usec */
18350769Sdfr
18450769Sdfr		valid = valid || bit;
18550769Sdfr		if (i < 64)
18650769Sdfr			sum = (sum >> 1) |
187139268Simp			  (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
18850769Sdfr		data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
18950769Sdfr	}
19050769Sdfr
19150769Sdfr	valid = valid && (data[8] == sum);
19250769Sdfr
193139268Simp	return (valid);
19450769Sdfr}
19550769Sdfr
19650769Sdfr/*
19750769Sdfr * Fill's the buffer with resource info from the device.
19852059Sdfr * Returns the number of characters read.
19950769Sdfr */
20050769Sdfrstatic int
20150769Sdfrpnp_get_resource_info(u_char *buffer, int len)
20250769Sdfr{
20352059Sdfr	int i, j, count;
20450769Sdfr	u_char temp;
20550769Sdfr
20652059Sdfr	count = 0;
20750769Sdfr	for (i = 0; i < len; i++) {
20850769Sdfr		outb(_PNP_ADDRESS, PNP_STATUS);
20950769Sdfr		for (j = 0; j < 100; j++) {
21050769Sdfr			if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)
21150769Sdfr				break;
212220126Sjhb			DELAY(10);
21350769Sdfr		}
21450769Sdfr		if (j == 100) {
21550769Sdfr			printf("PnP device failed to report resource data\n");
216139268Simp			return (count);
21750769Sdfr		}
21850769Sdfr		outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
21950769Sdfr		temp = inb((pnp_rd_port << 2) | 0x3);
22050769Sdfr		if (buffer != NULL)
22150769Sdfr			buffer[i] = temp;
22252059Sdfr		count++;
22350769Sdfr	}
224139268Simp	return (count);
22550769Sdfr}
22650769Sdfr
22750769Sdfr/*
22850769Sdfr * This function is called after the bus has assigned resource
22950769Sdfr * locations for a logical device.
23050769Sdfr */
23150769Sdfrstatic void
23250769Sdfrpnp_set_config(void *arg, struct isa_config *config, int enable)
23350769Sdfr{
23450769Sdfr	int csn = ((struct pnp_set_config_arg *) arg)->csn;
23550769Sdfr	int ldn = ((struct pnp_set_config_arg *) arg)->ldn;
23650769Sdfr	int i;
23750769Sdfr
23850769Sdfr	/*
23950769Sdfr	 * First put all cards into Sleep state with the initiation
24050769Sdfr	 * key, then put our card into Config state.
24150769Sdfr	 */
24250769Sdfr	pnp_send_initiation_key();
24350769Sdfr	pnp_write(PNP_WAKE, csn);
24450769Sdfr
24550769Sdfr	/*
24650769Sdfr	 * Select our logical device so that we can program it.
24750769Sdfr	 */
24850769Sdfr	pnp_write(PNP_SET_LDN, ldn);
24950769Sdfr
25050769Sdfr	/*
25166840Smsmith	 * Constrain the number of resources we will try to program
25266840Smsmith	 */
25366840Smsmith	if (config->ic_nmem > ISA_PNP_NMEM) {
254139268Simp		printf("too many ISA memory ranges (%d > %d)\n",
255139268Simp		    config->ic_nmem, ISA_PNP_NMEM);
256139268Simp		config->ic_nmem = ISA_PNP_NMEM;
25766840Smsmith	}
25866840Smsmith	if (config->ic_nport > ISA_PNP_NPORT) {
259139268Simp		printf("too many ISA I/O ranges (%d > %d)\n", config->ic_nport,
260139268Simp		    ISA_PNP_NPORT);
261139268Simp		config->ic_nport = ISA_PNP_NPORT;
26266840Smsmith	}
26366840Smsmith	if (config->ic_nirq > ISA_PNP_NIRQ) {
264139268Simp		printf("too many ISA IRQs (%d > %d)\n", config->ic_nirq,
265139268Simp		    ISA_PNP_NIRQ);
266139268Simp		config->ic_nirq = ISA_PNP_NIRQ;
26766840Smsmith	}
26866840Smsmith	if (config->ic_ndrq > ISA_PNP_NDRQ) {
269139268Simp		printf("too many ISA DRQs (%d > %d)\n", config->ic_ndrq,
270139268Simp		    ISA_PNP_NDRQ);
271139268Simp		config->ic_ndrq = ISA_PNP_NDRQ;
27266840Smsmith	}
27366840Smsmith
27466840Smsmith	/*
27550769Sdfr	 * Now program the resources.
27650769Sdfr	 */
27750769Sdfr	for (i = 0; i < config->ic_nmem; i++) {
278139268Simp		uint32_t start;
279139268Simp		uint32_t size;
28083051Syokota
28183051Syokota		/* XXX: should handle memory control register, 32 bit memory */
28283051Syokota		if (config->ic_mem[i].ir_size == 0) {
28383051Syokota			pnp_write(PNP_MEM_BASE_HIGH(i), 0);
28483051Syokota			pnp_write(PNP_MEM_BASE_LOW(i), 0);
28583051Syokota			pnp_write(PNP_MEM_RANGE_HIGH(i), 0);
28683051Syokota			pnp_write(PNP_MEM_RANGE_LOW(i), 0);
28783051Syokota		} else {
28883051Syokota			start = config->ic_mem[i].ir_start;
28983051Syokota			size =  config->ic_mem[i].ir_size;
29083051Syokota			if (start & 0xff)
29183051Syokota				panic("pnp_set_config: bogus memory assignment");
29283051Syokota			pnp_write(PNP_MEM_BASE_HIGH(i), (start >> 16) & 0xff);
29383051Syokota			pnp_write(PNP_MEM_BASE_LOW(i), (start >> 8) & 0xff);
29483051Syokota			pnp_write(PNP_MEM_RANGE_HIGH(i), (size >> 16) & 0xff);
29583051Syokota			pnp_write(PNP_MEM_RANGE_LOW(i), (size >> 8) & 0xff);
29683051Syokota		}
29750769Sdfr	}
29866840Smsmith	for (; i < ISA_PNP_NMEM; i++) {
29950769Sdfr		pnp_write(PNP_MEM_BASE_HIGH(i), 0);
30050769Sdfr		pnp_write(PNP_MEM_BASE_LOW(i), 0);
30150769Sdfr		pnp_write(PNP_MEM_RANGE_HIGH(i), 0);
30250769Sdfr		pnp_write(PNP_MEM_RANGE_LOW(i), 0);
30350769Sdfr	}
30450769Sdfr
30550769Sdfr	for (i = 0; i < config->ic_nport; i++) {
306139268Simp		uint32_t start;
30783051Syokota
30883051Syokota		if (config->ic_port[i].ir_size == 0) {
30983051Syokota			pnp_write(PNP_IO_BASE_HIGH(i), 0);
31083051Syokota			pnp_write(PNP_IO_BASE_LOW(i), 0);
31183051Syokota		} else {
31283051Syokota			start = config->ic_port[i].ir_start;
31383051Syokota			pnp_write(PNP_IO_BASE_HIGH(i), (start >> 8) & 0xff);
31483051Syokota			pnp_write(PNP_IO_BASE_LOW(i), (start >> 0) & 0xff);
31583051Syokota		}
31650769Sdfr	}
31766840Smsmith	for (; i < ISA_PNP_NPORT; i++) {
31850769Sdfr		pnp_write(PNP_IO_BASE_HIGH(i), 0);
31950769Sdfr		pnp_write(PNP_IO_BASE_LOW(i), 0);
32050769Sdfr	}
32150769Sdfr
32250769Sdfr	for (i = 0; i < config->ic_nirq; i++) {
32383051Syokota		int irq;
32483051Syokota
32583051Syokota		/* XXX: interrupt type */
32683051Syokota		if (config->ic_irqmask[i] == 0) {
32783051Syokota			pnp_write(PNP_IRQ_LEVEL(i), 0);
32883051Syokota			pnp_write(PNP_IRQ_TYPE(i), 2);
32983051Syokota		} else {
33083051Syokota			irq = ffs(config->ic_irqmask[i]) - 1;
33183051Syokota			pnp_write(PNP_IRQ_LEVEL(i), irq);
33283051Syokota			pnp_write(PNP_IRQ_TYPE(i), 2); /* XXX */
33383051Syokota		}
33450769Sdfr	}
33566840Smsmith	for (; i < ISA_PNP_NIRQ; i++) {
33650769Sdfr		/*
33750769Sdfr		 * IRQ 0 is not a valid interrupt selection and
33850769Sdfr		 * represents no interrupt selection.
33950769Sdfr		 */
34050769Sdfr		pnp_write(PNP_IRQ_LEVEL(i), 0);
34183051Syokota		pnp_write(PNP_IRQ_TYPE(i), 2);
34250769Sdfr	}
34350769Sdfr
34450769Sdfr	for (i = 0; i < config->ic_ndrq; i++) {
34583051Syokota		int drq;
34683051Syokota
34783051Syokota		if (config->ic_drqmask[i] == 0) {
34883051Syokota			pnp_write(PNP_DMA_CHANNEL(i), 4);
34983051Syokota		} else {
35083051Syokota			drq = ffs(config->ic_drqmask[i]) - 1;
35183051Syokota			pnp_write(PNP_DMA_CHANNEL(i), drq);
35283051Syokota		}
35350769Sdfr	}
35466840Smsmith	for (; i < ISA_PNP_NDRQ; i++) {
35550769Sdfr		/*
35650769Sdfr		 * DMA channel 4, the cascade channel is used to
35750769Sdfr		 * indicate no DMA channel is active.
35850769Sdfr		 */
35950769Sdfr		pnp_write(PNP_DMA_CHANNEL(i), 4);
36050769Sdfr	}
36150769Sdfr
36250769Sdfr	pnp_write(PNP_ACTIVATE, enable ? 1 : 0);
36350769Sdfr
36450769Sdfr	/*
36550769Sdfr	 * Wake everyone up again, we are finished.
36650769Sdfr	 */
36750769Sdfr	pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
36850769Sdfr}
36950769Sdfr
37050769Sdfr/*
37150769Sdfr * Process quirks for a logical device.. The card must be in Config state.
37250769Sdfr */
37362947Stanimuravoid
374139268Simppnp_check_quirks(uint32_t vendor_id, uint32_t logical_id, int ldn,
375139268Simp    struct isa_config *config)
37650769Sdfr{
37750769Sdfr	struct pnp_quirk *qp;
37850769Sdfr
37950769Sdfr	for (qp = &pnp_quirks[0]; qp->vendor_id; qp++) {
38050769Sdfr		if (qp->vendor_id == vendor_id
381139268Simp		    && (qp->logical_id == 0 || qp->logical_id == logical_id)) {
38250769Sdfr			switch (qp->type) {
38350769Sdfr			case PNP_QUIRK_WRITE_REG:
38450769Sdfr				pnp_write(PNP_SET_LDN, ldn);
38550769Sdfr				pnp_write(qp->arg1, qp->arg2);
38650769Sdfr				break;
38762947Stanimura			case PNP_QUIRK_EXTRA_IO:
38862947Stanimura				if (config == NULL)
38962947Stanimura					break;
39062947Stanimura				if (qp->arg1 != 0) {
39162947Stanimura					config->ic_nport++;
39262947Stanimura					config->ic_port[config->ic_nport - 1] = config->ic_port[0];
39362947Stanimura					config->ic_port[config->ic_nport - 1].ir_start += qp->arg1;
39462947Stanimura					config->ic_port[config->ic_nport - 1].ir_end += qp->arg1;
39562947Stanimura				}
39662947Stanimura				if (qp->arg2 != 0) {
39762947Stanimura					config->ic_nport++;
39862947Stanimura					config->ic_port[config->ic_nport - 1] = config->ic_port[0];
39962947Stanimura					config->ic_port[config->ic_nport - 1].ir_start += qp->arg2;
40062947Stanimura					config->ic_port[config->ic_nport - 1].ir_end += qp->arg2;
40162947Stanimura				}
40262947Stanimura				break;
40350769Sdfr			}
40450769Sdfr		}
40550769Sdfr	}
40650769Sdfr}
40750769Sdfr
40850769Sdfr/*
40950769Sdfr * Scan Resource Data for Logical Devices.
41050769Sdfr *
41150769Sdfr * This function exits as soon as it gets an error reading *ANY*
41252059Sdfr * Resource Data or it reaches the end of Resource Data.  In the first
41350769Sdfr * case the return value will be TRUE, FALSE otherwise.
41450769Sdfr */
41550769Sdfrstatic int
41652059Sdfrpnp_create_devices(device_t parent, pnp_id *p, int csn,
417139268Simp    u_char *resources, int len)
41850769Sdfr{
41952059Sdfr	u_char tag, *resp, *resinfo, *startres = 0;
42052059Sdfr	int large_len, scanning = len, retval = FALSE;
421139268Simp	uint32_t logical_id;
42250769Sdfr	device_t dev = 0;
42350769Sdfr	int ldn = 0;
42450769Sdfr	struct pnp_set_config_arg *csnldn;
42552059Sdfr	char buf[100];
42650769Sdfr	char *desc = 0;
42750769Sdfr
42852059Sdfr	resp = resources;
42952059Sdfr	while (scanning > 0) {
43052059Sdfr		tag = *resp++;
43152059Sdfr		scanning--;
43252059Sdfr		if (PNP_RES_TYPE(tag) != 0) {
43352059Sdfr			/* Large resource */
43452059Sdfr			if (scanning < 2) {
43550769Sdfr				scanning = 0;
43650769Sdfr				continue;
43750769Sdfr			}
43852059Sdfr			large_len = resp[0] + (resp[1] << 8);
43952059Sdfr			resp += 2;
44050769Sdfr
44152059Sdfr			if (scanning < large_len) {
44250769Sdfr				scanning = 0;
44350769Sdfr				continue;
44450769Sdfr			}
44552059Sdfr			resinfo = resp;
44652059Sdfr			resp += large_len;
44752059Sdfr			scanning -= large_len;
44850769Sdfr
44950769Sdfr			if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) {
45083504Syokota				if (dev) {
45183504Syokota					/*
45283504Syokota					 * This is an optional device
45383504Syokota					 * indentifier string. Skipt it
45483504Syokota					 * for now.
45583504Syokota					 */
45683504Syokota					continue;
45783504Syokota				}
45883504Syokota				/* else mandately card identifier string */
45952059Sdfr				if (large_len > sizeof(buf) - 1)
46052059Sdfr					large_len = sizeof(buf) - 1;
46152059Sdfr				bcopy(resinfo, buf, large_len);
46252059Sdfr
46350769Sdfr				/*
46452059Sdfr				 * Trim trailing spaces.
46550769Sdfr				 */
46652059Sdfr				while (buf[large_len-1] == ' ')
46752059Sdfr					large_len--;
46852059Sdfr				buf[large_len] = '\0';
46952059Sdfr				desc = buf;
47050769Sdfr				continue;
47150769Sdfr			}
47250769Sdfr
47352059Sdfr			continue;
47452059Sdfr		}
47552059Sdfr
47652059Sdfr		/* Small resource */
47752059Sdfr		if (scanning < PNP_SRES_LEN(tag)) {
47852059Sdfr			scanning = 0;
47952059Sdfr			continue;
48052059Sdfr		}
48152059Sdfr		resinfo = resp;
48252059Sdfr		resp += PNP_SRES_LEN(tag);
483201758Smbr		scanning -= PNP_SRES_LEN(tag);
48452059Sdfr
48552059Sdfr		switch (PNP_SRES_NUM(tag)) {
48652059Sdfr		case PNP_TAG_LOGICAL_DEVICE:
48752059Sdfr			/*
48852059Sdfr			 * Parse the resources for the previous
48952059Sdfr			 * logical device (if any).
49052059Sdfr			 */
49152059Sdfr			if (startres) {
49252059Sdfr				pnp_parse_resources(dev, startres,
493139268Simp				    resinfo - startres - 1, ldn);
49452059Sdfr				dev = 0;
49552059Sdfr				startres = 0;
49650769Sdfr			}
49750769Sdfr
49852059Sdfr			/*
49952059Sdfr			 * A new logical device. Scan for end of
50052059Sdfr			 * resources.
50152059Sdfr			 */
50252059Sdfr			bcopy(resinfo, &logical_id, 4);
50362947Stanimura			pnp_check_quirks(p->vendor_id, logical_id, ldn, NULL);
50452059Sdfr			dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1);
50552059Sdfr			if (desc)
50652059Sdfr				device_set_desc_copy(dev, desc);
50783504Syokota			else
50883504Syokota				device_set_desc_copy(dev,
509139268Simp				    pnp_eisaformat(logical_id));
51052059Sdfr			isa_set_vendorid(dev, p->vendor_id);
51152059Sdfr			isa_set_serial(dev, p->serial);
51252059Sdfr			isa_set_logicalid(dev, logical_id);
51383051Syokota			isa_set_configattr(dev,
514139268Simp			    ISACFGATTR_CANDISABLE | ISACFGATTR_DYNAMIC);
51552059Sdfr			csnldn = malloc(sizeof *csnldn, M_DEVBUF, M_NOWAIT);
51652059Sdfr			if (!csnldn) {
517139268Simp				device_printf(parent, "out of memory\n");
51850769Sdfr				scanning = 0;
51952059Sdfr				break;
52050769Sdfr			}
52152059Sdfr			csnldn->csn = csn;
52252059Sdfr			csnldn->ldn = ldn;
523139268Simp			ISA_SET_CONFIG_CALLBACK(parent, dev, pnp_set_config,
524139268Simp			    csnldn);
525184564Simp			isa_set_pnp_csn(dev, csn);
526184564Simp			isa_set_pnp_ldn(dev, ldn);
52752059Sdfr			ldn++;
52852059Sdfr			startres = resp;
52952059Sdfr			break;
53052059Sdfr
53152059Sdfr		case PNP_TAG_END:
53252059Sdfr			if (!startres) {
533139268Simp				device_printf(parent, "malformed resources\n");
53450769Sdfr				scanning = 0;
53550769Sdfr				break;
53650769Sdfr			}
53752059Sdfr			pnp_parse_resources(dev, startres,
538139268Simp			    resinfo - startres - 1, ldn);
53952059Sdfr			dev = 0;
54052059Sdfr			startres = 0;
54152059Sdfr			scanning = 0;
54252059Sdfr			break;
54350769Sdfr
54452059Sdfr		default:
54552059Sdfr			/* Skip this resource */
54652059Sdfr			break;
54750769Sdfr		}
54850769Sdfr	}
54950769Sdfr
550139268Simp	return (retval);
55150769Sdfr}
55250769Sdfr
55350769Sdfr/*
55452059Sdfr * Read 'amount' bytes of resources from the card, allocating memory
55552059Sdfr * as needed. If a buffer is already available, it should be passed in
55652059Sdfr * '*resourcesp' and its length in '*spacep'. The number of resource
55752059Sdfr * bytes already in the buffer should be passed in '*lenp'. The memory
55852059Sdfr * allocated will be returned in '*resourcesp' with its size and the
55952059Sdfr * number of bytes of resources in '*spacep' and '*lenp' respectively.
560105226Sphk *
561105226Sphk * XXX: Multiple problems here, we forget to free() stuff in one
562105226Sphk * XXX: error return, and in another case we free (*resourcesp) but
563105226Sphk * XXX: don't tell the caller.
56452059Sdfr */
56552059Sdfrstatic int
56652059Sdfrpnp_read_bytes(int amount, u_char **resourcesp, int *spacep, int *lenp)
56752059Sdfr{
56852059Sdfr	u_char *resources = *resourcesp;
56952059Sdfr	u_char *newres;
57052059Sdfr	int space = *spacep;
57152059Sdfr	int len = *lenp;
57252059Sdfr
57352059Sdfr	if (space == 0) {
57452059Sdfr		space = 1024;
57552059Sdfr		resources = malloc(space, M_TEMP, M_NOWAIT);
57652059Sdfr		if (!resources)
577139268Simp			return (ENOMEM);
57852059Sdfr	}
57952059Sdfr
58052059Sdfr	if (len + amount > space) {
58152059Sdfr		int extra = 1024;
58252059Sdfr		while (len + amount > space + extra)
58352059Sdfr			extra += 1024;
58452059Sdfr		newres = malloc(space + extra, M_TEMP, M_NOWAIT);
585115543Sphk		if (!newres) {
586115543Sphk			/* XXX: free resources */
587139268Simp			return (ENOMEM);
588115543Sphk		}
58952059Sdfr		bcopy(resources, newres, len);
59052059Sdfr		free(resources, M_TEMP);
59152059Sdfr		resources = newres;
59252059Sdfr		space += extra;
59352059Sdfr	}
59452059Sdfr
59552059Sdfr	if (pnp_get_resource_info(resources + len, amount) != amount)
596139268Simp		return (EINVAL);
59752059Sdfr	len += amount;
59852059Sdfr
59952059Sdfr	*resourcesp = resources;
60052059Sdfr	*spacep = space;
60152059Sdfr	*lenp = len;
60252059Sdfr
603139268Simp	return (0);
60452059Sdfr}
60552059Sdfr
60652059Sdfr/*
60752059Sdfr * Read all resources from the card, allocating memory as needed. If a
60852059Sdfr * buffer is already available, it should be passed in '*resourcesp'
60952059Sdfr * and its length in '*spacep'. The memory allocated will be returned
61052059Sdfr * in '*resourcesp' with its size and the number of bytes of resources
61152059Sdfr * in '*spacep' and '*lenp' respectively.
61252059Sdfr */
61352059Sdfrstatic int
61452059Sdfrpnp_read_resources(u_char **resourcesp, int *spacep, int *lenp)
61552059Sdfr{
61652059Sdfr	u_char *resources = *resourcesp;
61752059Sdfr	int space = *spacep;
61852059Sdfr	int len = 0;
61952059Sdfr	int error, done;
62052059Sdfr	u_char tag;
62152059Sdfr
62252059Sdfr	error = 0;
62352059Sdfr	done = 0;
62452059Sdfr	while (!done) {
62552059Sdfr		error = pnp_read_bytes(1, &resources, &space, &len);
62652059Sdfr		if (error)
62752059Sdfr			goto out;
62852059Sdfr		tag = resources[len-1];
62952059Sdfr		if (PNP_RES_TYPE(tag) == 0) {
63052059Sdfr			/*
63152059Sdfr			 * Small resource, read contents.
63252059Sdfr			 */
63352059Sdfr			error = pnp_read_bytes(PNP_SRES_LEN(tag),
634139268Simp			    &resources, &space, &len);
63552059Sdfr			if (error)
63652059Sdfr				goto out;
63752059Sdfr			if (PNP_SRES_NUM(tag) == PNP_TAG_END)
63852059Sdfr				done = 1;
63952059Sdfr		} else {
64052059Sdfr			/*
64152059Sdfr			 * Large resource, read length and contents.
64252059Sdfr			 */
64352059Sdfr			error = pnp_read_bytes(2, &resources, &space, &len);
64452059Sdfr			if (error)
64552059Sdfr				goto out;
64652059Sdfr			error = pnp_read_bytes(resources[len-2]
647139268Simp			    + (resources[len-1] << 8), &resources, &space,
648139268Simp			    &len);
64952059Sdfr			if (error)
65052059Sdfr				goto out;
65152059Sdfr		}
65252059Sdfr	}
65352059Sdfr
65452059Sdfr out:
65552059Sdfr	*resourcesp = resources;
65652059Sdfr	*spacep = space;
65752059Sdfr	*lenp = len;
658139268Simp	return (error);
65952059Sdfr}
66052059Sdfr
66152059Sdfr/*
66250769Sdfr * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
66350769Sdfr * value (caller should try multiple READ_DATA locations before giving
66450769Sdfr * up). Upon exiting, all cards are aware that they should use
66550769Sdfr * pnp_rd_port as the READ_DATA port.
66650769Sdfr *
66750769Sdfr * In the first pass, a csn is assigned to each board and pnp_id's
66850769Sdfr * are saved to an array, pnp_devices. In the second pass, each
66950769Sdfr * card is woken up and the device configuration is called.
67050769Sdfr */
67150769Sdfrstatic int
67250769Sdfrpnp_isolation_protocol(device_t parent)
67350769Sdfr{
67450769Sdfr	int csn;
67550769Sdfr	pnp_id id;
67652059Sdfr	int found = 0, len;
67752059Sdfr	u_char *resources = 0;
67852059Sdfr	int space = 0;
67952059Sdfr	int error;
680104142Snyan#ifdef PC98
681104142Snyan	int n, necpnp;
682104142Snyan	u_char buffer[10];
683104142Snyan#endif
68450769Sdfr
68550769Sdfr	/*
68650769Sdfr	 * Put all cards into the Sleep state so that we can clear
68750769Sdfr	 * their CSNs.
68850769Sdfr	 */
68950769Sdfr	pnp_send_initiation_key();
69050769Sdfr
69150769Sdfr	/*
69250769Sdfr	 * Clear the CSN for all cards.
69350769Sdfr	 */
69450769Sdfr	pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_RESET_CSN);
69550769Sdfr
69650769Sdfr	/*
69750769Sdfr	 * Move all cards to the Isolation state.
69850769Sdfr	 */
69950769Sdfr	pnp_write(PNP_WAKE, 0);
70050769Sdfr
70150769Sdfr	/*
70250769Sdfr	 * Tell them where the read point is going to be this time.
70350769Sdfr	 */
70450769Sdfr	pnp_write(PNP_SET_RD_DATA, pnp_rd_port);
70550769Sdfr
70650769Sdfr	for (csn = 1; csn < PNP_MAX_CARDS; csn++) {
70750769Sdfr		/*
70850769Sdfr		 * Start the serial isolation protocol.
70950769Sdfr		 */
71050769Sdfr		outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
71150769Sdfr		DELAY(1000);	/* Delay 1 msec */
71250769Sdfr
71350769Sdfr		if (pnp_get_serial(&id)) {
71450769Sdfr			/*
71550769Sdfr			 * We have read the id from a card
71650769Sdfr			 * successfully. The card which won the
71750769Sdfr			 * isolation protocol will be in Isolation
71852059Sdfr			 * mode and all others will be in Sleep.
71950769Sdfr			 * Program the CSN of the isolated card
72050769Sdfr			 * (taking it to Config state) and read its
72150769Sdfr			 * resources, creating devices as we find
72250769Sdfr			 * logical devices on the card.
72350769Sdfr			 */
72450769Sdfr			pnp_write(PNP_SET_CSN, csn);
725104142Snyan#ifdef PC98
726104142Snyan			if (bootverbose)
727104142Snyan				printf("PnP Vendor ID = %x\n", id.vendor_id);
728104142Snyan			/* Check for NEC PnP (9 bytes serial). */
729104142Snyan			for (n = necpnp = 0; necids[n].vendor_id; n++) {
730104142Snyan				if (id.vendor_id == necids[n].vendor_id) {
731104142Snyan					necpnp = 1;
732104142Snyan					break;
733104142Snyan				}
734104142Snyan			}
735104142Snyan			if (necpnp) {
736104142Snyan				if (bootverbose)
737139268Simp					printf("An NEC-PnP card (%s).\n",
738139268Simp					    pnp_eisaformat(id.vendor_id));
739104142Snyan				/*  Read dummy 9 bytes serial area. */
740104142Snyan				pnp_get_resource_info(buffer, 9);
741104142Snyan			} else {
742104142Snyan				if (bootverbose)
743139268Simp					printf("A Normal-ISA-PnP card (%s).\n",
744139268Simp					    pnp_eisaformat(id.vendor_id));
745104142Snyan			}
746220126Sjhb#endif
747104142Snyan			if (bootverbose)
748104142Snyan				printf("Reading PnP configuration for %s.\n",
749139268Simp				    pnp_eisaformat(id.vendor_id));
750139268Simp			error = pnp_read_resources(&resources, &space, &len);
75152059Sdfr			if (error)
75252059Sdfr				break;
753139268Simp			pnp_create_devices(parent, &id, csn, resources, len);
75450769Sdfr			found++;
75550769Sdfr		} else
75650769Sdfr			break;
75750769Sdfr
75850769Sdfr		/*
75950769Sdfr		 * Put this card back to the Sleep state and
76050769Sdfr		 * simultaneously move all cards which don't have a
76150769Sdfr		 * CSN yet to Isolation state.
76250769Sdfr		 */
76350769Sdfr		pnp_write(PNP_WAKE, 0);
76450769Sdfr	}
76550769Sdfr
76650769Sdfr	/*
76750769Sdfr	 * Unless we have chosen the wrong read port, all cards will
76850769Sdfr	 * be in Sleep state. Put them back into WaitForKey for
76950769Sdfr	 * now. Their resources will be programmed later.
77050769Sdfr	 */
77150769Sdfr	pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
77250769Sdfr
77352059Sdfr	/*
77452059Sdfr	 * Cleanup.
77552059Sdfr	 */
77652059Sdfr	if (resources)
77752059Sdfr		free(resources, M_TEMP);
77852059Sdfr
779139268Simp	return (found);
78050769Sdfr}
78150769Sdfr
78250769Sdfr
78350769Sdfr/*
78450769Sdfr * pnp_identify()
78550769Sdfr *
78650769Sdfr * autoconfiguration of pnp devices. This routine just runs the
78750769Sdfr * isolation protocol over several ports, until one is successful.
78850769Sdfr *
78950769Sdfr * may be called more than once ?
79050769Sdfr *
79150769Sdfr */
79250769Sdfr
79350769Sdfrstatic void
79450769Sdfrpnp_identify(driver_t *driver, device_t parent)
79550769Sdfr{
79650769Sdfr	int num_pnp_devs;
79750769Sdfr
79850769Sdfr	/* Try various READ_DATA ports from 0x203-0x3ff */
79950769Sdfr	for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) {
80050769Sdfr		if (bootverbose)
801139271Simp			printf("pnp_identify: Trying Read_Port at %x\n",
802139268Simp			    (pnp_rd_port << 2) | 0x3);
80350769Sdfr
80450769Sdfr		num_pnp_devs = pnp_isolation_protocol(parent);
80550769Sdfr		if (num_pnp_devs)
80650769Sdfr			break;
80750769Sdfr	}
808139269Simp	if (bootverbose)
809139269Simp		printf("PNP Identify complete\n");
81050769Sdfr}
81150769Sdfr
81250769Sdfrstatic device_method_t pnp_methods[] = {
81350769Sdfr	/* Device interface */
81450769Sdfr	DEVMETHOD(device_identify,	pnp_identify),
81550769Sdfr
81650769Sdfr	{ 0, 0 }
81750769Sdfr};
81850769Sdfr
81950769Sdfrstatic driver_t pnp_driver = {
82050769Sdfr	"pnp",
82150769Sdfr	pnp_methods,
82250769Sdfr	1,			/* no softc */
82350769Sdfr};
82450769Sdfr
82550769Sdfrstatic devclass_t pnp_devclass;
82650769Sdfr
82750769SdfrDRIVER_MODULE(pnp, isa, pnp_driver, pnp_devclass, 0, 0);
828