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