* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)ps.c 7.1 (Berkeley) %G%
* Evans and Sutherland Picture System 2 driver -- Bill Reeves.
#include "../machine/pte.h"
int psprobe(), psattach(), psextsync();
int psclockintr(), pssystemintr(), psdeviceintr(), psdmaintr();
struct uba_device
*psdinfo
[NPS
];
struct uba_driver psdriver
=
{ psprobe
, 0, psattach
, 0, psstd
, "ps", psdinfo
};
#define PSUNIT(dev) (minor(dev))
#define MAXDBSIZE (0177777/2)
#define PSWAIT(psaddr) { \
register short i = 20000, j; \
while (i-- != 0 && ((j = psaddr->ps_iostat) & DIOREADY) == 0) \
u_short sraddrs
[MAXAUTOREFRESH
];
u_short maddrs
[MAXAUTOMAP
];
char ps_open
; /* device is open */
uid_t ps_uid
; /* uid of device owner */
struct psrefresh ps_refresh
; /* refresh state */
struct psdbuffer ps_dbuffer
; /* double buffering state */
struct psmap ps_map
; /* segment map state */
int ps_clockticks
; /* clock ints between refresh */
int ps_clockmiss
; /* clock ints w/o refresh */
int ps_clockcnt
; /* count of clock interrupts */
int ps_hitcnt
; /* count of hit interrupts */
int ps_strayintr
; /* count of stray interrupts */
int ps_icnt
; /* count of system interrupts */
register struct psdevice
*psaddr
= (struct psdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
psclockintr((dev_t
)0); pssystemintr((dev_t
)0);
psdeviceintr((dev_t
)0); psdmaintr((dev_t
)0);
psaddr
->ps_iostat
= PSRESET
;
PSWAIT(psaddr
); psaddr
->ps_data
= 01;
psaddr
->ps_iostat
= PSIE
;
PSWAIT(psaddr
); psaddr
->ps_data
= SYNC
|RUN
;
psaddr
->ps_addr
= RTCREQ
;
PSWAIT(psaddr
); psaddr
->ps_data
= 01;
psaddr
->ps_iostat
= PSRESET
;
return (sizeof (struct psdevice
));
register struct uba_device
*ui
;
register int unit
= PSUNIT(dev
);
if (unit
>= NPS
|| (psp
= &ps
[minor(dev
)])->ps_open
||
(ui
= psdinfo
[unit
]) == 0 || ui
->ui_alive
== 0)
psp
->ps_refresh
.state
= SINGLE_STEP_RF
;
psp
->ps_refresh
.mode
= STOPPED_RF
;
psp
->ps_refresh
.waiting
= 0;
psp
->ps_refresh
.stop
= 0;
psp
->ps_dbuffer
.state
= OFF_DB
;
psp
->ps_map
.state
= SINGLE_STEP_MAP
;
psp
->ps_map
.mode
= STOPPED_MAP
;
psp
->ps_refresh
.icnt
= psp
->ps_map
.icnt
= psp
->ps_clockcnt
= 0;
register struct psdevice
*psaddr
=
(struct psdevice
*)psdinfo
[PSUNIT(dev
)]->ui_addr
;
ps
[PSUNIT(dev
)].ps_open
= 0;
psaddr
->ps_iostat
= 0; /* clear IENABLE */
PSWAIT(psaddr
); psaddr
->ps_addr
= RFSR
; /* set in auto refresh mode */
PSWAIT(psaddr
); psaddr
->ps_data
= AUTOREF
;
unmaptouser((caddr_t
)psaddr
);
psioctl(dev
, cmd
, data
, flag
)
register struct uba_device
*ui
= psdinfo
[PSUNIT(dev
)];
register struct ps
*psp
= &ps
[PSUNIT(dev
)];
int *waddr
= *(int **)data
;
*(caddr_t
*)data
= ui
->ui_addr
;
n
= fuword((caddr_t
)waddr
++);
if (n
< 0 || n
> MAXAUTOREFRESH
)
for (i
= 0; i
< n
; i
++) {
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
psp
->ps_refresh
.sraddrs
[i
] = arg
;
psp
->ps_refresh
.state
= AUTO_RF
;
psp
->ps_refresh
.nsraddrs
= n
;
psp
->ps_refresh
.srcntr
= 0;
psp
->ps_refresh
.mode
= WAITING_MAP
;
n
= fuword((caddr_t
)waddr
++);
if (n
< 0 || n
> MAXAUTOMAP
)
for (i
= 0; i
< n
; i
++) {
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
psp
->ps_map
.maddrs
[i
] = arg
;
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
psp
->ps_map
.outputstart
= arg
;
psp
->ps_map
.state
= AUTO_MAP
;
psp
->ps_map
.mode
= WAITING_START
;
psp
->ps_refresh
.state
= SINGLE_STEP_RF
;
psp
->ps_map
.state
= SINGLE_STEP_MAP
;
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
psp
->ps_dbuffer
.dbaddrs
[0] = arg
;
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
if (arg
<= 0 || arg
> MAXDBSIZE
)
psp
->ps_dbuffer
.dbsize
= arg
;
psp
->ps_dbuffer
.dbaddrs
[1] = psp
->ps_dbuffer
.dbaddrs
[0]+arg
;
psp
->ps_dbuffer
.state
= ON_DB
;
psp
->ps_dbuffer
.rbuffer
= 0;
psp
->ps_dbuffer
.state
= OFF_DB
;
if (psp
->ps_refresh
.state
!= SINGLE_STEP_RF
)
if ((arg
= fuword((caddr_t
)waddr
++)) == -1)
psp
->ps_refresh
.state
= TIME_RF
;
psp
->ps_refresh
.timecnt
= arg
;
if (psp
->ps_refresh
.mode
!= RUNNING_RF
) /* not running */
return (0); /* dont wait */
if (cmd
== PSIOSTOPREFRESH
) {
if (psp
->ps_refresh
.mode
== STOPPED_RF
&&
psp
->ps_refresh
.state
!= TIME_RF
)
psp
->ps_refresh
.stop
= 1;
psp
->ps_refresh
.waiting
= 1;
while (psp
->ps_refresh
.waiting
)
sleep(&psp
->ps_refresh
.waiting
, PSPRI
);
if (cmd
== PSIOSTOPREFRESH
)
psp
->ps_refresh
.mode
= STOPPED_RF
;
if (psp
->ps_refresh
.state
== TIME_RF
)
psp
->ps_refresh
.state
= SINGLE_STEP_RF
;
if (psp
->ps_map
.mode
!= RUNNING_MAP
) /* not running */
return (0); /* dont wait */
while (psp
->ps_map
.waiting
)
sleep(&psp
->ps_map
.waiting
, PSPRI
);
#define SAVEPSADDR(psaddr, savepsaddr) { \
while ((psaddr->ps_iostat & DIOREADY) == 0) \
savepsaddr = psaddr->ps_data; \
#define RESTORPSADDR(psaddr, savepsaddr) { \
while ((psaddr->ps_iostat & DIOREADY) == 0) \
psaddr->ps_addr = savepsaddr; \
register struct psdevice
*psaddr
=
(struct psdevice
*)psdinfo
[PSUNIT(dev
)]->ui_addr
;
register struct ps
*psp
= &ps
[PSUNIT(dev
)];
SAVEPSADDR(psaddr
, savepsaddr
);
if (psp
->ps_refresh
.state
== AUTO_RF
) {
if (psp
->ps_refresh
.mode
== SYNCING_RF
&&
psp
->ps_refresh
.state
!= TIME_RF
) {
(void) psrfnext(psp
, psaddr
);
PSWAIT(psaddr
); psaddr
->ps_addr
= RTCREQ
;
PSWAIT(psaddr
); psaddr
->ps_data
= 01; /* clear the request bits */
RESTORPSADDR(psaddr
, savepsaddr
);
register struct psdevice
*psaddr
=
(struct psdevice
*)psdinfo
[PSUNIT(dev
)]->ui_addr
;
register struct ps
*psp
= &ps
[PSUNIT(dev
)];
register int savepsaddr
, x
;
SAVEPSADDR(psaddr
, savepsaddr
);
PSWAIT(psaddr
); psaddr
->ps_addr
= SYSREQ
;
PSWAIT(psaddr
); request
= psaddr
->ps_data
;
psp
->ps_lastrequest2
= psp
->ps_lastrequest
;
psp
->ps_lastrequest
= request
;
if (request
&~ (HALT_REQ
|RFSTOP_REQ
|HIT_REQ
)) {
psp
->ps_lastfunnyrequest
= request
;
PSWAIT(psaddr
); psaddr
->ps_addr
= SYSREQ
;
tmp
= request
&(~(HALT_REQ
|MOSTOP_REQ
)); /* acknowledge */
PSWAIT(psaddr
); psaddr
->ps_data
= tmp
;
if (request
& (MOSTOP_REQ
|HALT_REQ
)) { /* Map stopped */
psmapstop(psaddr
, psp
, request
);/* kill it dead */
if (psp
->ps_map
.waiting
) {
wakeup(&psp
->ps_map
.waiting
);
if (psp
->ps_map
.state
== AUTO_MAP
&& !psmapnext(psp
, psaddr
)) {
/* prepare for next round */
pssetmapbounds(psp
, psaddr
);
if (psp
->ps_refresh
.state
== AUTO_RF
) {
if (psp
->ps_refresh
.mode
== WAITING_MAP
){
if (psp
->ps_dbuffer
.state
== ON_DB
)
psp
->ps_map
.mode
= WAITING_RF
;
(void) psrfnext(psp
, psaddr
);
psp
->ps_map
.mode
= WAITING_RF
;
} else { /* no auto refresh */
if (psp
->ps_dbuffer
.state
== ON_DB
)
(void) psmapnext(psp
, psaddr
);
if (request
& RFSTOP_REQ
) { /* Refresh stopped */
if (psp
->ps_refresh
.state
== TIME_RF
)
if (--psp
->ps_refresh
.timecnt
> 0)
if (psp
->ps_refresh
.waiting
) {
psp
->ps_refresh
.waiting
= 0;
wakeup(&psp
->ps_refresh
.waiting
);
if (psp
->ps_refresh
.stop
) {
psp
->ps_refresh
.stop
= 0;
if (psp
->ps_refresh
.state
== AUTO_RF
)
if (!psrfnext(psp
, psaddr
)) { /* at end of refresh cycle */
if (psp
->ps_map
.state
== AUTO_MAP
&&
psp
->ps_map
.mode
== WAITING_RF
) {
if (psp
->ps_dbuffer
.state
== ON_DB
)
(void) psmapnext(psp
, psaddr
);
psp
->ps_refresh
.srcntr
= 0;
psp
->ps_refresh
.mode
= SYNCING_RF
;
(void) psrfnext(psp
, psaddr
);
if (request
& HIT_REQ
) /* Hit request */
RESTORPSADDR(psaddr
, savepsaddr
);
register struct psdevice
*psaddr
;
if (psp
->ps_refresh
.srcntr
< psp
->ps_refresh
.nsraddrs
) {
psrfstart(psp
->ps_refresh
.sraddrs
[psp
->ps_refresh
.srcntr
++],
if (psp
->ps_refresh
.srcntr
== psp
->ps_refresh
.nsraddrs
&&
psp
->ps_dbuffer
.state
== ON_DB
) {
start
= psp
->ps_dbuffer
.dbaddrs
[psp
->ps_dbuffer
.rbuffer
];
last
= start
+psp
->ps_dbuffer
.dbsize
;
psrfstart(start
, last
, psp
, psaddr
);
psp
->ps_refresh
.srcntr
++; /* flag for after dbuffer */
psrfstart(dfaddr
, last
, psp
, psaddr
)
register struct psdevice
*psaddr
;
PSWAIT(psaddr
); psaddr
->ps_addr
= RFASA
;
PSWAIT(psaddr
); psaddr
->ps_data
= dfaddr
;
dummy
= psaddr
->ps_data
;/* just access to get to status reg */
PSWAIT(psaddr
); psaddr
->ps_data
= RFSTART
; /* may want | here */
psp
->ps_refresh
.mode
= RUNNING_RF
;
register struct psdevice
*psaddr
;
PSWAIT(psaddr
); psaddr
->ps_addr
= RFSR
;
PSWAIT(psaddr
); psaddr
->ps_data
= 0;
register struct psdevice
*psaddr
;
psp
->ps_dbuffer
.rbuffer
= !psp
->ps_dbuffer
.rbuffer
;
pssetmapbounds(psp
, psaddr
);
(void) psmapnext(psp
, psaddr
);
register struct psdevice
*psaddr
;
if (psp
->ps_map
.mcntr
< psp
->ps_map
.nmaddrs
) {
psmapstart(psp
->ps_map
.maddrs
[psp
->ps_map
.mcntr
++],
pssetmapbounds(psp
, psaddr
)
register struct psdevice
*psaddr
;
PSWAIT(psaddr
); psaddr
->ps_addr
= MAOL
;
if (psp
->ps_dbuffer
.state
== ON_DB
) {
start
= psp
->ps_dbuffer
.dbaddrs
[!psp
->ps_dbuffer
.rbuffer
];
last
= start
+psp
->ps_dbuffer
.dbsize
-2; /* 2 for halt cmd */
PSWAIT(psaddr
); psaddr
->ps_data
= start
;
start
= psaddr
->ps_data
; /* dummy: don't update limit */
PSWAIT(psaddr
); psaddr
->ps_data
= psp
->ps_map
.outputstart
;
psmapstart(dfaddr
, psp
, psaddr
)
register struct psdevice
*psaddr
;
PSWAIT(psaddr
); psaddr
->ps_addr
= MAIA
;
PSWAIT(psaddr
); psaddr
->ps_data
= dfaddr
;
PSWAIT(psaddr
); psaddr
->ps_data
= MAO
|MAI
; /* may want more here */
psp
->ps_map
.mode
= RUNNING_MAP
;
psmapstop(psaddr
, psp
, request
)
register struct psdevice
*psaddr
;
request
&= HALT_REQ
|MOSTOP_REQ
; /* overkill?? */
for (i
= 0; i
< pskillcnt
; i
++) {
PSWAIT(psaddr
); psaddr
->ps_addr
= MASR
;
PSWAIT(psaddr
); psaddr
->ps_data
= IOUT
; /* zero MAI & MAO */
PSWAIT(psaddr
); psaddr
->ps_addr
= MAIA
;
PSWAIT(psaddr
); psaddr
->ps_data
= 0; /* 0 input addr reg */
PSWAIT(psaddr
); psaddr
->ps_addr
= MAOA
;
PSWAIT(psaddr
); psaddr
->ps_data
= 0; /* 0 output addr reg */
PSWAIT(psaddr
); psaddr
->ps_addr
= SYSREQ
;
PSWAIT(psaddr
); psaddr
->ps_data
= request
;
psp
->ps_map
.mode
= STOPPED_MAP
;
printf("ps device intr\n");
register struct psdevice
*psaddr
;
for (psp
= ps
, n
= 0; n
< NPS
; psp
++, n
++) {
if (psp
->ps_refresh
.mode
== SYNCING_RF
&&
psp
->ps_refresh
.state
!= TIME_RF
) {
psaddr
= (struct psdevice
*)psdinfo
[n
]->ui_addr
;
SAVEPSADDR(psaddr
, savepsaddr
);
(void) psrfnext(psp
, psaddr
);
RESTORPSADDR(psaddr
, savepsaddr
);