NetBSD/sys/arch/mac68k/mac68k/psc.c

336 lines
6.6 KiB
C

/* $NetBSD: psc.c,v 1.3 1997/12/19 05:38:00 scottr Exp $ */
/*-
* Copyright (c) 1997 David Huang <khym@bga.com>
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
*/
/*
* This handles registration/unregistration of PSC (Peripheral
* Subsystem Controller) interrupts. The PSC is used only on the
* Centris/Quadra 660av and the Quadra 840av.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/psc.h>
void psc_init __P((void));
void psc_lev3_intr __P((struct frame *));
static void psc_lev3_noint __P((void *));
int psc_lev4_intr __P((struct frame *));
static int psc_lev4_noint __P((void *));
void psc_lev5_intr __P((struct frame *));
static void psc_lev5_noint __P((void *));
void psc_lev6_intr __P((struct frame *));
static void psc_lev6_noint __P((void *));
void psc_spurintr __P((struct frame *));
void (*lev3_intrvec) __P((struct frame *));
int (*lev4_intrvec) __P((struct frame *));
void (*lev5_intrvec) __P((struct frame *));
void (*lev6_intrvec) __P((struct frame *));
extern int zshard __P((void *)); /* from zs.c */
void (*psc3_ihandler) __P((void *)) = psc_lev3_noint;
void *psc3_iarg;
int (*psc4_itab[4]) __P((void *)) = {
psc_lev4_noint, /* 0 */
zshard, /* 1 */
zshard, /* 2 */
psc_lev4_noint /* 3 */
};
void *psc4_iarg[4] = {
(void *)0, (void *)1, (void *)2, (void *)3
};
void (*psc5_itab[2]) __P((void *)) = {
psc_lev5_noint, /* 0 */
psc_lev5_noint /* 1 */
};
void *psc5_iarg[2] = {
(void *)0, (void *)1
};
void (*psc6_itab[3]) __P((void *)) = {
psc_lev6_noint, /* 0 */
psc_lev6_noint, /* 1 */
psc_lev6_noint /* 2 */
};
void *psc6_iarg[3] = {
(void *)0, (void *)1, (void *)2
};
/*
* Setup the interrupt vectors and disable most of the PSC interrupts
*/
void
psc_init()
{
/*
* Only Quadra AVs have a PSC. On other machines, point the
* level 4 interrupt to zshard(), and levels 3, 5, and 6 to
* psc_spurintr().
*/
if (current_mac_model->class == MACH_CLASSAV) {
lev3_intrvec = psc_lev3_intr;
lev4_intrvec = psc_lev4_intr;
lev5_intrvec = psc_lev5_intr;
lev6_intrvec = psc_lev6_intr;
psc_reg1(PSC_LEV3_IER) = 0x01; /* disable level 3 interrupts */
psc_reg1(PSC_LEV4_IER) = 0x09; /* disable level 4 interrupts */
psc_reg1(PSC_LEV4_IER) = 0x86; /* except for SCC */
psc_reg1(PSC_LEV5_IER) = 0x03; /* disable level 5 interrupts */
psc_reg1(PSC_LEV6_IER) = 0x07; /* disable level 6 interrupts */
} else {
lev3_intrvec = lev5_intrvec = lev6_intrvec = psc_spurintr;
lev4_intrvec = (int (*)(struct frame *))zshard;
}
}
void
psc_spurintr(fp)
struct frame *fp;
{
}
int
add_psc_lev3_intr(handler, arg)
void (*handler)(void *);
void *arg;
{
int s;
s = splhigh();
psc3_ihandler = handler;
psc3_iarg = arg;
splx(s);
return 1;
}
int
remove_psc_lev3_intr()
{
return add_psc_lev3_intr(psc_lev3_noint, (void *)0);
}
void
psc_lev3_intr(fp)
struct frame *fp;
{
u_int8_t intbits;
while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR))
;
intbits &= 0x1 & psc_reg1(PSC_LEV3_IER);
if (intbits)
psc3_ihandler(psc3_iarg);
}
static void
psc_lev3_noint(arg)
void *arg;
{
printf("psc_lev3_noint\n");
}
int
psc_lev4_intr(fp)
struct frame *fp;
{
u_int8_t intbits, bitnum;
u_int mask;
while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR))
;
intbits &= 0xf & psc_reg1(PSC_LEV4_IER);
mask = 1;
bitnum = 0;
do {
if (intbits & mask)
psc4_itab[bitnum](psc4_iarg[bitnum]);
mask <<= 1;
} while (intbits >= mask && ++bitnum);
return 0;
}
int
add_psc_lev4_intr(dev, handler, arg)
int dev;
int (*handler)(void *);
void *arg;
{
int s;
if ((dev < 0) || (dev > 3))
return 0;
s = splhigh();
psc4_itab[dev] = handler;
psc4_iarg[dev] = arg;
splx(s);
return 1;
}
int
remove_psc_lev4_intr(dev)
int dev;
{
return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev);
}
int
psc_lev4_noint(arg)
void *arg;
{
printf("psc_lev4_noint: device %d\n", (int)arg);
return 0;
}
void
psc_lev5_intr(fp)
struct frame *fp;
{
u_int8_t intbits, bitnum;
u_int mask;
while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR))
;
intbits &= 0x3 & psc_reg1(PSC_LEV5_IER);
mask = 1;
bitnum = 0;
do {
if (intbits & mask)
psc5_itab[bitnum](psc5_iarg[bitnum]);
mask <<= 1;
} while (intbits >= mask && ++bitnum);
}
int
add_psc_lev5_intr(dev, handler, arg)
int dev;
void (*handler)(void *);
void *arg;
{
int s;
if ((dev < 0) || (dev > 1))
return 0;
s = splhigh();
psc5_itab[dev] = handler;
psc5_iarg[dev] = arg;
splx(s);
return 1;
}
int
remove_psc_lev5_intr(dev)
int dev;
{
return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev);
}
void
psc_lev5_noint(arg)
void *arg;
{
printf("psc_lev5_noint: device %d\n", (int)arg);
}
void
psc_lev6_intr(fp)
struct frame *fp;
{
u_int8_t intbits, bitnum;
u_int mask;
while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR))
;
intbits &= 0x7 & psc_reg1(PSC_LEV6_IER);
mask = 1;
bitnum = 0;
do {
if (intbits & mask)
psc6_itab[bitnum](psc6_iarg[bitnum]);
mask <<= 1;
} while (intbits >= mask && ++bitnum);
}
int
add_psc_lev6_intr(dev, handler, arg)
int dev;
void (*handler)(void *);
void *arg;
{
int s;
if ((dev < 0) || (dev > 2))
return 0;
s = splhigh();
psc6_itab[dev] = handler;
psc6_iarg[dev] = arg;
splx(s);
return 1;
}
int
remove_psc_lev6_intr(dev)
int dev;
{
return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev);
}
void
psc_lev6_noint(arg)
void *arg;
{
printf("psc_lev6_noint: device %d\n", (int)arg);
}