xref: /netbsd/sys/arch/i386/stand/lib/isapnp.c (revision bf9ec67e)
1 /*	$NetBSD: isapnp.c,v 1.2 1997/03/22 01:48:34 thorpej Exp $	 */
2 
3 /*
4  * Copyright (c) 1997
5  *	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed for the NetBSD Project
18  *	by Matthias Drochner.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /*
36  * minimal ISA PnP implementation: find adapter, return settings (1 IO and 1
37  * DMA only for now)
38  */
39 
40 #include <sys/types.h>
41 #include <machine/pio.h>
42 
43 #include <lib/libsa/stand.h>
44 
45 #include <libi386.h>
46 
47 #include "isapnpvar.h"
48 
49 #define PNPADDR 0x0279
50 #define PNPWDATA 0x0a79
51 #define PNPRDATAMIN 0x0203
52 #define PNPRDATAMAX 0x03ff
53 
54 enum {
55 	DATAPORT,
56 	ISOL,
57 	CONTROL,
58 	WAKE,
59 	RESDATA,
60 	RESSTAT,
61 	SETCSN,
62 	SETLDEV
63 };
64 
65 #define MEMBASE 0x40
66 #define IOBASE 0x60
67 #define INTBASE 0x70
68 #define DMABASE 0x74
69 
70 static int      pnpdataport;
71 
72 static int
73 getiobase(nr)
74 	int             nr;
75 {
76 	unsigned short  iobase;
77 
78 	outb(PNPADDR, SETLDEV);
79 	outb(PNPWDATA, 0);	/* subdev 0 */
80 
81 	outb(PNPADDR, IOBASE + nr * 2);
82 	iobase = (inb(pnpdataport) << 8);
83 	outb(PNPADDR, IOBASE + nr * 2 + 1);
84 	iobase |= inb(pnpdataport);
85 
86 	return (iobase);
87 }
88 
89 static int
90 getdmachan(nr)
91 	int             nr;
92 {
93 	unsigned char   dmachannel;
94 
95 	outb(PNPADDR, SETLDEV);
96 	outb(PNPWDATA, 0);	/* subdev 0 */
97 
98 	outb(PNPADDR, DMABASE + nr);
99 	dmachannel = inb(pnpdataport) & 0x07;
100 
101 	return (dmachannel);
102 }
103 
104 struct cardid {
105 	unsigned char   eisaid[4];
106 	unsigned int    serial;
107 	unsigned char   crc;
108 };
109 
110 /*
111  do isolation, call pnpscanresc() in board config state
112  */
113 static int
114 pnpisol(csn)
115 	int             csn;
116 {
117 	unsigned char   buf[9];
118 	int             i, j;
119 	struct cardid  *id;
120 	unsigned char   crc = 0x6a;
121 
122 	/*
123 	 * do 72 pairs of reads from ISOL register all but 1 go to sleep
124 	 * state (ch. 3.3)
125 	 */
126 	outb(PNPADDR, ISOL);
127 	delay(1000);
128 
129 	for (i = 0; i < 9; i++) {
130 		for (j = 0; j < 8; j++) {
131 			unsigned char   a, b;
132 			int             bitset;
133 
134 			a = inb(pnpdataport);
135 			b = inb(pnpdataport);
136 			if ((a == 0x55) && (b == 0xaa))
137 				bitset = 1;
138 			else if ((a == 0xff) && (b == 0xff))
139 				bitset = 0;
140 			else
141 				return (-1);	/* data port conflict */
142 
143 			buf[i] = (buf[i] >> 1) | (bitset << 7);
144 
145 			if (i < 8)	/* calc crc for first 8 bytes (app.
146 					 * B.2) */
147 				crc = (crc >> 1) |
148 				  ((bitset != ((crc & 1) == !(crc & 2))) << 7);
149 
150 			delay(250);
151 		}
152 	}
153 	id = (struct cardid *) buf;
154 
155 	if (id->crc != crc)
156 		return (0);	/* normal end */
157 
158 	outb(PNPADDR, SETCSN);
159 	outb(PNPWDATA, csn);	/* set csn for winning card and put it to
160 				 * config state */
161 
162 	return ((id->eisaid[0] << 24) | (id->eisaid[1] << 16)
163 		| (id->eisaid[2] << 8) | (id->eisaid[3]));
164 }
165 
166 static void
167 pnpisolreset()
168 {
169 	outb(PNPADDR, WAKE);
170 	outb(PNPWDATA, 0);	/* put all remaining cards to isolation state */
171 }
172 
173 /*
174  send initiation sequence (app. B.1)
175  */
176 static void
177 pnpinit()
178 {
179 	int             i;
180 	unsigned char   key = 0x6a;
181 
182 	outb(PNPADDR, 0);
183 	outb(PNPADDR, 0);
184 
185 	for (i = 0; i < 32; i++) {
186 		outb(PNPADDR, key);
187 		key = (key >> 1) |
188 			(((key & 1) == !(key & 2)) << 7);
189 	}
190 }
191 
192 int
193 isapnp_finddev(id, iobase, dmachan)
194 	int             id;
195 	int            *iobase, *dmachan;
196 {
197 	int             csn;
198 
199 	outb(PNPADDR, CONTROL);
200 	outb(PNPWDATA, 2);	/* XXX force wait for key */
201 
202 	/* scan all allowed data ports (ch. 3.1) */
203 	for (pnpdataport = PNPRDATAMIN; pnpdataport <= PNPRDATAMAX;
204 	     pnpdataport += 4) {
205 		int             res, found = 0;
206 
207 		pnpinit();	/* initiation sequence */
208 
209 		outb(PNPADDR, CONTROL);
210 		outb(PNPWDATA, 4);	/* CSN=0 - only these respond to
211 					 * WAKE[0] */
212 
213 		outb(PNPADDR, WAKE);
214 		outb(PNPWDATA, 0);	/* put into isolation state */
215 
216 		outb(PNPADDR, DATAPORT);
217 		outb(PNPWDATA, pnpdataport >> 2);	/* set READ_DATA port */
218 
219 		csn = 0;
220 		do {
221 			res = pnpisol(++csn);
222 
223 			if ((res) == id) {
224 				if (iobase)
225 					*iobase = getiobase(0);
226 				if (dmachan)
227 					*dmachan = getdmachan(0);
228 				found = 1;
229 			}
230 			pnpisolreset();
231 		} while ((res != 0) && (res != -1));
232 
233 		outb(PNPADDR, CONTROL);
234 		outb(PNPWDATA, 2);	/* return to wait for key */
235 
236 		if (csn > 1)	/* at least 1 board found */
237 			return (!found);
238 
239 		/* if no board found, try next dataport */
240 	}
241 	return (-1);		/* nothing found */
242 }
243