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