232 lines
5 KiB
C
232 lines
5 KiB
C
|
/* $NetBSD: isapnp.c,v 1.5 2008/12/14 17:03:43 christos Exp $ */
|
||
|
|
||
|
/*
|
||
|
* Copyright (c) 1997
|
||
|
* Matthias Drochner. All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* minimal ISA PnP implementation: find adapter, return settings (1 IO and 1
|
||
|
* DMA only for now)
|
||
|
*/
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <machine/pio.h>
|
||
|
|
||
|
#include <lib/libsa/stand.h>
|
||
|
|
||
|
#include <libi386.h>
|
||
|
|
||
|
#include "isapnpvar.h"
|
||
|
|
||
|
#define PNPADDR 0x0279
|
||
|
#define PNPWDATA 0x0a79
|
||
|
#define PNPRDATAMIN 0x0203
|
||
|
#define PNPRDATAMAX 0x03ff
|
||
|
|
||
|
enum {
|
||
|
DATAPORT,
|
||
|
ISOL,
|
||
|
CONTROL,
|
||
|
WAKE,
|
||
|
RESDATA,
|
||
|
RESSTAT,
|
||
|
SETCSN,
|
||
|
SETLDEV
|
||
|
};
|
||
|
|
||
|
#define MEMBASE 0x40
|
||
|
#define IOBASE 0x60
|
||
|
#define INTBASE 0x70
|
||
|
#define DMABASE 0x74
|
||
|
|
||
|
static int pnpdataport;
|
||
|
|
||
|
static int
|
||
|
getiobase(int nr)
|
||
|
{
|
||
|
unsigned short iobase;
|
||
|
|
||
|
outb(PNPADDR, SETLDEV);
|
||
|
outb(PNPWDATA, 0); /* subdev 0 */
|
||
|
|
||
|
outb(PNPADDR, IOBASE + nr * 2);
|
||
|
iobase = (inb(pnpdataport) << 8);
|
||
|
outb(PNPADDR, IOBASE + nr * 2 + 1);
|
||
|
iobase |= inb(pnpdataport);
|
||
|
|
||
|
return iobase;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
getdmachan(int nr)
|
||
|
{
|
||
|
unsigned char dmachannel;
|
||
|
|
||
|
outb(PNPADDR, SETLDEV);
|
||
|
outb(PNPWDATA, 0); /* subdev 0 */
|
||
|
|
||
|
outb(PNPADDR, DMABASE + nr);
|
||
|
dmachannel = inb(pnpdataport) & 0x07;
|
||
|
|
||
|
return dmachannel;
|
||
|
}
|
||
|
|
||
|
struct cardid {
|
||
|
unsigned char eisaid[4];
|
||
|
unsigned int serial;
|
||
|
unsigned char crc;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
do isolation, call pnpscanresc() in board config state
|
||
|
*/
|
||
|
static int
|
||
|
pnpisol(int csn)
|
||
|
{
|
||
|
unsigned char buf[9];
|
||
|
int i, j;
|
||
|
struct cardid *id;
|
||
|
unsigned char crc = 0x6a;
|
||
|
|
||
|
/*
|
||
|
* do 72 pairs of reads from ISOL register all but 1 go to sleep
|
||
|
* state (ch. 3.3)
|
||
|
*/
|
||
|
outb(PNPADDR, ISOL);
|
||
|
delay(1000);
|
||
|
|
||
|
for (i = 0; i < 9; i++) {
|
||
|
for (j = 0; j < 8; j++) {
|
||
|
unsigned char a, b;
|
||
|
int bitset;
|
||
|
|
||
|
a = inb(pnpdataport);
|
||
|
b = inb(pnpdataport);
|
||
|
if ((a == 0x55) && (b == 0xaa))
|
||
|
bitset = 1;
|
||
|
else if ((a == 0xff) && (b == 0xff))
|
||
|
bitset = 0;
|
||
|
else
|
||
|
return -1; /* data port conflict */
|
||
|
|
||
|
buf[i] = (buf[i] >> 1) | (bitset << 7);
|
||
|
|
||
|
if (i < 8) /* calc crc for first 8 bytes (app.
|
||
|
* B.2) */
|
||
|
crc = (crc >> 1) |
|
||
|
((bitset != ((crc & 1) == !(crc & 2))) << 7);
|
||
|
|
||
|
delay(250);
|
||
|
}
|
||
|
}
|
||
|
id = (struct cardid *) buf;
|
||
|
|
||
|
if (id->crc != crc)
|
||
|
return 0; /* normal end */
|
||
|
|
||
|
outb(PNPADDR, SETCSN);
|
||
|
outb(PNPWDATA, csn); /* set csn for winning card and put it to
|
||
|
* config state */
|
||
|
|
||
|
return (id->eisaid[0] << 24) | (id->eisaid[1] << 16)
|
||
|
| (id->eisaid[2] << 8) | (id->eisaid[3]);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pnpisolreset(void)
|
||
|
{
|
||
|
outb(PNPADDR, WAKE);
|
||
|
outb(PNPWDATA, 0); /* put all remaining cards to isolation state */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
send initiation sequence (app. B.1)
|
||
|
*/
|
||
|
static void
|
||
|
pnpinit(void)
|
||
|
{
|
||
|
int i;
|
||
|
unsigned char key = 0x6a;
|
||
|
|
||
|
outb(PNPADDR, 0);
|
||
|
outb(PNPADDR, 0);
|
||
|
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
outb(PNPADDR, key);
|
||
|
key = (key >> 1) |
|
||
|
(((key & 1) == !(key & 2)) << 7);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
isapnp_finddev(int id, int *iobase, int *dmachan)
|
||
|
{
|
||
|
int csn;
|
||
|
|
||
|
outb(PNPADDR, CONTROL);
|
||
|
outb(PNPWDATA, 2); /* XXX force wait for key */
|
||
|
|
||
|
/* scan all allowed data ports (ch. 3.1) */
|
||
|
for (pnpdataport = PNPRDATAMIN; pnpdataport <= PNPRDATAMAX;
|
||
|
pnpdataport += 4) {
|
||
|
int res, found = 0;
|
||
|
|
||
|
pnpinit(); /* initiation sequence */
|
||
|
|
||
|
outb(PNPADDR, CONTROL);
|
||
|
outb(PNPWDATA, 4); /* CSN=0 - only these respond to
|
||
|
* WAKE[0] */
|
||
|
|
||
|
outb(PNPADDR, WAKE);
|
||
|
outb(PNPWDATA, 0); /* put into isolation state */
|
||
|
|
||
|
outb(PNPADDR, DATAPORT);
|
||
|
outb(PNPWDATA, pnpdataport >> 2); /* set READ_DATA port */
|
||
|
|
||
|
csn = 0;
|
||
|
do {
|
||
|
res = pnpisol(++csn);
|
||
|
|
||
|
if ((res) == id) {
|
||
|
if (iobase)
|
||
|
*iobase = getiobase(0);
|
||
|
if (dmachan)
|
||
|
*dmachan = getdmachan(0);
|
||
|
found = 1;
|
||
|
}
|
||
|
pnpisolreset();
|
||
|
} while ((res != 0) && (res != -1));
|
||
|
|
||
|
outb(PNPADDR, CONTROL);
|
||
|
outb(PNPWDATA, 2); /* return to wait for key */
|
||
|
|
||
|
if (csn > 1) /* at least 1 board found */
|
||
|
return !found;
|
||
|
|
||
|
/* if no board found, try next dataport */
|
||
|
}
|
||
|
return -1; /* nothing found */
|
||
|
}
|