1/* $NetBSD: isapnp.c,v 1.4 2005/12/11 12:17:48 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 48enum { 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 64static int pnpdataport; 65 66static int 67getiobase(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 82static int 83getdmachan(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 96struct 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 */ 105static int 106pnpisol(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 157static void 158pnpisolreset(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 */ 167static void 168pnpinit(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 183int 184isapnp_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