Files
Arquivotheca.SunOS-4.1.4/sys/sundev/sky.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

330 lines
7.1 KiB
C

#ifndef lint
static char sccsid[] = "@(#)sky.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
/*
* Sky FFP
*/
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <machine/pte.h>
#include <machine/mmu.h>
#include <machine/cpu.h>
#include <machine/scb.h>
#include <sundev/mbvar.h>
#include <sundev/skyreg.h>
/*
* "page" size for VME sky board
* user page (0) doesn't allow access to nasty registers
* supervisor page (1) does
*/
#define SKYPGSIZE 0x800
/*
* Driver information for auto-configuration stuff.
*/
int skyprobe(), skyattach(), skyintr();
struct mb_device *skyinfo[1]; /* XXX only supports 1 board */
struct mb_driver skydriver = {
skyprobe, 0, skyattach, 0, 0, skyintr,
2 * SKYPGSIZE, "sky", skyinfo, 0, 0, 0,
};
struct skyreg *skyaddr;
int skyinit = 0, skyisnew = 0;
/*ARGSUSED*/
skyprobe(reg, unit)
caddr_t reg;
int unit;
{
register struct skyreg *skybase = (struct skyreg *)reg;
if (peek((short *)skybase) == -1)
return (0);
if (poke((short *)&skybase->sky_status, SKY_IHALT))
return (0);
skyaddr = (struct skyreg *)(SKYPGSIZE + reg);
if (cpu == CPU_SUN2_120 ||
poke((short *)&skyaddr->sky_status, SKY_IHALT)) {
/* old VMEbus or Multibus */
skyisnew = 0;
skyaddr = (struct skyreg *)reg;
} else
skyisnew = 1;
return (sizeof (struct skyreg));
}
/*
* Initialize the VME interrupt vector to be identical to
* the 68000 auto-vector for the appropriate interrupt level
* unless vectored interrupts have been specified.
*/
skyattach(md)
struct mb_device *md;
{
if (skyisnew) {
if (!md->md_intr) {
/* use auto-vectoring */
(void) poke((short *)&skyaddr->sky_vector,
AUTOBASE + md->md_intpri);
} else {
/* use vectored interrupts */
(void) poke((short *)&skyaddr->sky_vector,
md->md_intr->v_vec);
}
}
}
/*ARGSUSED*/
skyopen(dev, flag)
dev_t dev;
int flag;
{
int i;
register struct skyreg *s = skyaddr;
if (skyaddr == 0)
return (ENXIO);
if (skyinit == 2) {
/*
* Initialize the FFP.
* VME users can't do this themselves;
* since the status isn't writeable
*/
s->sky_status = SKY_RESET;
s->sky_command = SKY_START0;
s->sky_command = SKY_START0;
s->sky_command = SKY_START1;
s->sky_status = SKY_RUNENB;
u.u_pcb.u_skyctx.usc_used = 1;
u.u_pcb.u_skyctx.usc_cmd = SKY_NOP;
for (i=0; i<8; i++)
u.u_pcb.u_skyctx.usc_regs[i] = 0;
skyrestore();
} else if (flag & (FNDELAY|FNBIO|FNONBIO))
skyinit = 1;
else
return (ENXIO);
return (0);
}
/*ARGSUSED*/
skyclose(dev, flag)
dev_t dev;
int flag;
{
/*
* We have to save context here in case the user aborted
* and left the board in an unclean state.
*/
if (skyinit == 2)
skysave();
if (skyinit == 1)
skyinit = 2;
u.u_pcb.u_skyctx.usc_used = 0;
return (0);
}
/*ARGSUSED*/
skymmap(dev, off, prot)
dev_t dev;
off_t off;
int prot;
{
struct pte pte;
if (off)
return (-1);
off = (off_t)skyaddr;
if (skyisnew && skyinit == 2) /* use user page */
off -= SKYPGSIZE;
mmu_getkpte((addr_t)off, &pte);
return (MAKE_PFNUM(&pte));
}
/*ARGSUSED*/
skyintr(n)
int n;
{
static u_short skybooboo = 0;
if (skyaddr && (skyaddr->sky_status & (SKY_INTENB|SKY_INTRPT))) {
if (skyaddr->sky_status & SKY_INTENB) {
printf("skyintr: sky board interrupt enabled, status = 0x%x\n",
skyaddr->sky_status);
skyaddr->sky_status &= ~(SKY_INTENB|SKY_INTRPT);
return (1);
}
if (!skybooboo && (skyaddr->sky_status & SKY_INTRPT)) {
printf("skyintr: sky board unrecognized status, status = 0x%x\n",
skybooboo = skyaddr->sky_status);
return (0);
}
}
return (0);
}
skysave()
{
register short i;
register struct skyreg *s = skyaddr;
register u_short stat;
for (i = 0; i < 100; i++) {
stat = s->sky_status;
if (stat & SKY_IDLE) {
u.u_pcb.u_skyctx.usc_cmd = SKY_NOP;
goto sky_save;
}
if (stat & SKY_IORDY)
goto sky_ioready;
}
printf("sky0: hung\n");
skyinit = 0;
u.u_pcb.u_skyctx.usc_used = 0;
return;
/*
* I/O is ready, is it a read or write?
*/
sky_ioready:
s->sky_status = SKY_SNGRUN; /* set single step mode */
if (stat & SKY_IODIR)
i = s->sky_d1reg;
else
s->sky_d1reg = i;
/*
* Check again since data may have been a long word.
*/
stat = s->sky_status;
if (stat & SKY_IORDY)
if (stat & SKY_IODIR)
i = s->sky_d1reg;
else
s->sky_d1reg = i;
/*
* Read and save the command register.
* Decrement by 1 since command register
* is actually FFP program counter and we
* want to back it up.
*/
u.u_pcb.u_skyctx.usc_cmd = s->sky_command - 1;
/*
* Reinitialize the FFP.
*/
s->sky_status = SKY_RESET;
s->sky_command = SKY_START0;
s->sky_command = SKY_START0;
s->sky_command = SKY_START1;
s->sky_status = SKY_RUNENB;
/*
* Finally, actually do the context save function.
* (Unrolled loop for efficiency.)
*/
sky_save:
s->sky_command = SKY_NOP; /* set FFP in a clean mode */
s->sky_command = SKY_SAVE;
u.u_pcb.u_skyctx.usc_regs[0] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[1] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[2] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[3] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[4] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[5] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[6] = s->sky_data;
u.u_pcb.u_skyctx.usc_regs[7] = s->sky_data;
}
skyrestore()
{
register struct skyreg *s = skyaddr;
if (skyinit != 2) {
u.u_pcb.u_skyctx.usc_used = 0;
return;
}
s->sky_command = SKY_NOP; /* set FFP in a clean mode */
/*
* Do the context restore function.
*/
s->sky_command = SKY_RESTOR;
s->sky_data = u.u_pcb.u_skyctx.usc_regs[0];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[1];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[2];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[3];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[4];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[5];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[6];
s->sky_data = u.u_pcb.u_skyctx.usc_regs[7];
s->sky_command = u.u_pcb.u_skyctx.usc_cmd;
}
/*
* special ioctl to allow user to do a save in case of signal handling
* where no context switch occured.
*/
/*ARGSUSED*/
skyioctl(dev, cmd, data, flag)
dev_t dev;
caddr_t data;
{
int i;
register struct skyreg *s = skyaddr;
register u_short stat;
/*
* I/O is ready, is it a read or write?
*/
s->sky_status = SKY_SNGRUN; /* set single step mode */
stat = s->sky_status;
if (stat & SKY_IORDY)
if (stat & SKY_IODIR)
i = s->sky_d1reg;
else
s->sky_d1reg = i;
/*
* Check again since data may have been a long word.
*/
stat = s->sky_status;
if (stat & SKY_IORDY)
if (stat & SKY_IODIR)
i = s->sky_d1reg;
else
s->sky_d1reg = i;
/*
* Read and save the command register.
* Decrement by 1 since command register
* is actually FFP program counter and we
* want to back it up.
*/
*(u_short *)data = s->sky_command - 1;
/*
* Reinitialize the FFP.
*/
s->sky_status = SKY_RESET;
s->sky_command = SKY_START0;
s->sky_command = SKY_START0;
s->sky_command = SKY_START1;
s->sky_status = SKY_RUNENB;
return(0);
}