#include "../vaxuba/ubavar.h"
* LPA driver for -- Asa Romberger
* write dedicated mode dispatch table
* ioctl TIOCSETP to set parameters
* short *baddr; buffer address
* short rate; - 1,000,000 / frequency in Hz
* short wc; 15-13 = number of buffers - 1
* 12-0 = buffer size in words
* read - 1 character indicating buffer index
* minor device number = DDCCCCCC where:
* DD = 00 for analog input
* CCCCCC = channel number
* define NOMCODE to eliminate the microcode download check
# define TRACER(x) printf(x)
# define TRACERN(x, d) printf(x, d)
/* PRIORITY AT WHICH PROGRAM SHOULD RUN */
/* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */
#define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf))
#define LPAPRI (PZERO + 0)
#define LPADEVICE(dev) (((dev) >> 6) & 03)
#define LPACHANNEL(dev) ((dev) & 077)
int lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
u_short lpastd
[] = {0170460, 0};
struct uba_device
*lpadinfo
[NLPA
];
struct uba_driver lpadriver
=
{lpaprobe
, 0, lpaattach
, 0, lpastd
, "lpa", lpadinfo
, 0, 0, 0 };
int sc_flag
; /* flags, as defined below */
int sc_device
; /* device: 0 = analog in, 1 = analog out */
int sc_channel
; /* device channel number */
struct buf sc_ubuffer
; /* user buffer header */
int sc_ubabuf
; /* uba allocation pointer for buffer */
int sc_ubufn
; /* present buffer that user is accessing */
int sc_lbufn
; /* present buffer that lpa is accessing */
int sc_lbufnx
; /* next buffer for lpa (value in ustat) */
int sc_nbuf
; /* number of buffers */
int sc_count
; /* buffer size in words */
short sc_ustat
; /* user status word */
struct buf sc_ustatbuf
; /* dummy user status word buffer for ubasetup */
int sc_ubaustat
; /* uba allocation pointer for ustat */
struct buf
*sc_buffer
; /* scratch buffer header */
int sc_start
; /* 0 if lpa operation has been started */
#define OPEN 01 /* device is open */
#define MCODE 02 /* microcode has been loaded */
#define DMDT 04 /* dedicated mode dispatch table loaded */
#define STTY 010 /* stty call and device initialized */
#define SLEEP 020 /* sleeping */
#define DONE 0100000 /* done */
#define STOP 0040000 /* stop data transfer */
#define NBI 0003400 /* next buffer index */
#define LBI 0000003 /* last buffer index */
short lcim
; /* control in and maintenance */
short lcos
; /* control and status out */
short lrda
; /* request description array address word */
short lms
; /* maintenance status */
/* control in and maintenance register bits */
#define READYI 0000200 /* ready in */
#define IIE 0000100 /* in interrupt enable */
#define RDAEXT 0000014 /* rda address extension */
#define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */
#define GO 0000001 /* go */
#define RUN 0100000 /* run */
#define RESET 0040000 /* reset */
#define CWRITE 0020000 /* cram write */
#define EA 0004000 /* enable arbitration */
#define ROMO 0002000 /* rom O */
#define ROMI 0001000 /* rom I */
#define SMICRO 0000400 /* step microprocessor */
/* control and status out register bits */
#define READYO 0200 /* ready out */
#define OIE 0100 /* out interrupt enable */
#define UINDEX 0007 /* user index */
#define ERROR 0100000 /* error */
#define ESTAT 0060000 /* error status */
#define ESCODE 0017400 /* error sub code */
#define ECODE 0077400 /* error status + error sub code */
#define OVERRUN 0243 /* overrun error */
/* LPA COMMAND DESCRIPTION AREA */
#define INIT 0 /* mode */
#define MCVERS 4 /* microcode version */
#define ACLOCKA 0170404 /* LPA bus addresses */
#define AAD2 1 /* 0170440 - DOES NOT EXIST */
#define ADIO1 1 /* 0167770 - DOES NOT EXIST */
#define ADIO2 1 /* 0167760 - DOES NOT EXIST */
#define ADIO3 1 /* 0167750 - DOES NOT EXIST */
#define ADIO4 1 /* 0167740 - DOES NOT EXIST */
#define ADIO5 1 /* 0167730 - DOES NOT EXIST */
/* CLOCK START COMMAND */
#define CLOCK 1 /* mode */
#define CLOCKA 0<<4 /* clock A */
#define ENACTR 1 /* enable counter */
#define R1M 1<<1 /* 1 MHz rate */
#define R100K 2<<1 /* 100 KHz rate */
#define R10K 3<<1 /* 10 KHz rate */
#define R1K 4<<1 /* 1 KHz rate */
#define R100 5<<1 /* 100 Hz rate */
#define REXT 6<<1 /* external rate (from st1 input) */
#define R60 7<<1 /* line frequency rate */
#define MFIE 0100 /* mode flag interrupt enable */
#define MSI 0<<8 /* single interval mode */
#define MRI 1<<8 /* repeat interval mode */
#define MEET 2<<8 /* external event time mode */
#define MEETZ 3<<8 /* external event time mode from zero base */
#define ST1EC 020000 /* st1 enable counter */
#define ST1IE 040000 /* st1 interrupt enable */
/* DATA TRANSFER START COMMAND */
#define SCHAN 1<<8 /* single channel */
register int br
, cvec
; /* value result */
register struct lpadevice
*lpaaddr
= (struct lpadevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
/* this should force an interrupt, stall, clear the lpa */
return (sizeof (struct lpadevice
));
register struct upa_device
*ui
;
register int unit
= LPAUNIT(dev
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if (unit
>= NLPA
|| sc
->sc_flag
& OPEN
|| ui
== 0 ||
lpaaddr
->lcos
= 0; /* clear the registers as a precaution */
sc
->sc_device
= LPADEVICE(dev
);
sc
->sc_channel
= LPACHANNEL(dev
);
sc
->sc_buffer
= geteblk();
sc
->sc_buffer
->b_error
= 0;
sc
->sc_buffer
->b_proc
= u
.u_procp
;
/* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
u
.u_procp
->p_nice
= NICE
;
register int unit
= LPAUNIT(dev
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if (sc
->sc_device
&& sc
->sc_ubufn
>= 0 && (sc
->sc_flag
& ERROR
) == 0) {
lpacmd(sc
->sc_buffer
, lpaaddr
, sc
, ui
->ui_ubanum
);
while (sc
->sc_flag
& STOP
) {
sleep((caddr_t
)sc
, LPAPRI
);
ubarelse(ui
->ui_ubanum
, &sc
->sc_ubabuf
);
vsunlock(sc
->sc_ubuffer
.b_un
.b_addr
, sc
->sc_ubuffer
.b_bcount
,
(sc
->sc_device
)? B_READ
: B_WRITE
);
u
.u_procp
->p_flag
&= ~SPHYSIO
;
ubarelse(ui
->ui_ubanum
, &sc
->sc_ubaustat
);
register int unit
= LPAUNIT(dev
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if ((f
& MCODE
) == 0) /* first write is the microcode */
return (lpamcode(lpaaddr
, sc
, uio
));
if ((f
& DMDT
) == 0) /* second write is the dispatch table */
return (lpadmdt(lpaaddr
, sc
, ui
->ui_ubanum
, uio
));
lpamcode(lpaaddr
, sc
, uio
)
register struct lpadevice
*lpaaddr
;
register struct lpa_softc
*sc
;
error
= uiomove(&v
, 2, UIO_WRITE
, uio
);
lpaaddr
->lcim
= 0; /* load microcode word */
lpaaddr
->lcim
= 0; /* verify microcode word */
if ((r
= lpaaddr
->lms
) != v
) {
printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v
, r
);
lpaaddr
->lcim
= RUN
| EA
; /* turn it on */
lpadmdt(lpaaddr
, sc
, ubanum
, uio
)
register struct lpadevice
*lpaaddr
;
register struct lpa_softc
*sc
;
p
= (short *) sc
->sc_buffer
->b_un
.b_addr
; /* INIT */
*p
++ = (MCVERS
<< 8) | INIT
; /* mode */
*p
++ = ACLOCKA
; /* LPA bus device addresses */
n
= min(uio
->uio_resid
, 256); /* dedicated mode dispatch table */
error
= uiomove((char *)p
, n
, UIO_WRITE
, uio
);
lpacmd(sc
->sc_buffer
, lpaaddr
, sc
, ubanum
);
lpaioctl(dev
, cmd
, data
, flag
)
register int unit
= LPAUNIT(dev
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if (cmd
!= TIOCSETP
|| (sc
->sc_flag
& DMDT
) == 0)
iocb
= (struct iocb
*)data
;
p
= (short *) sc
->sc_buffer
->b_un
.b_addr
; /* CLOCK START */
*p
++ = CLOCK
| CLOCKA
; /* mode */
*p
++ = ENACTR
| R1M
| MFIE
| MRI
; /* clock status */
*p
= iocb
->rate
; /* clock preset */
lpacmd(sc
->sc_buffer
, lpaaddr
, sc
, ui
->ui_ubanum
);
TRACER("CLOCK STARTED\n");
p
= (short *) sc
->sc_buffer
->b_un
.b_addr
; /* DATA TRANSFER START*/
*p
++ = (sc
->sc_device
<< 7) | DTS
| SCHAN
; /* mode */
sc
->sc_count
= iocb
->wc
& 017777; /* word count per buffer */
sc
->sc_ustatbuf
.b_un
.b_addr
= (caddr_t
) &sc
->sc_ustat
;
sc
->sc_ustatbuf
.b_flags
= 0;
sc
->sc_ustatbuf
.b_bcount
= 2;
sc
->sc_ustatbuf
.b_proc
= u
.u_procp
;
sc
->sc_ubaustat
= ubasetup(ui
->ui_ubanum
, &sc
->sc_ustatbuf
, 0);
*p
= (v
>> 16) & 03; /* into low portion of word */
sc
->sc_nbuf
= (iocb
->wc
>> 13) & 07; /* number of buffers */
*p
++ |= sc
->sc_nbuf
++ << 8; /* into high portion of word */
if (useracc(sc
->sc_ubuffer
.b_un
.b_addr
= (caddr_t
) iocb
->baddr
,
sc
->sc_ubuffer
.b_bcount
= sc
->sc_count
* sc
->sc_nbuf
* 2,
(i
= (sc
->sc_device
)? B_READ
: B_WRITE
) ) == NULL
) {
TRACER("USER BUFFER FAULT\n");
sc
->sc_ubuffer
.b_flags
= B_PHYS
| B_BUSY
| i
;
sc
->sc_ubuffer
.b_proc
= u
.u_procp
;
u
.u_procp
->p_flag
|= SPHYSIO
;
vslock(sc
->sc_ubuffer
.b_un
.b_addr
, sc
->sc_ubuffer
.b_bcount
);
sc
->sc_ubabuf
= ubasetup(ui
->ui_ubanum
, &sc
->sc_ubuffer
, 0);
for (i
= 0; i
< sc
->sc_nbuf
; i
++) {
*p
++ = 0; *p
++ = 0; /* random channel list address */
*p
++ = sc
->sc_channel
; /* start channel, channel inc */
*p
++ = 1; /* number of samples in a sequence */
*p
++ = 0; /* start word no., event mark word */
*p
++ = 0; /* start word mask */
*p
= 0; /* event mark mask */
sc
->sc_start
= (sc
->sc_device
)? sc
->sc_nbuf
+1 : 1;
register int unit
= LPAUNIT(dev
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if ((sc
->sc_flag
& STTY
) == 0)
if (--sc
->sc_start
== 0) {
lpacmd(sc
->sc_buffer
, lpaaddr
, sc
, ui
->ui_ubanum
);
while (sc
->sc_ubufn
== sc
->sc_lbufn
) {
TRACERN("READ %d\n", sc
->sc_ubufn
);
return (uiomove(&sc
->sc_ubufn
, 1, UIO_READ
, uio
));
lpacmd(bp
, lpaaddr
, sc
, ubanum
)
register struct lpadevice
*lpaaddr
;
register struct lpa_softc
*sc
;
ubareg
= ubasetup(ubanum
, bp
, UBA_NEEDBDP
);
lpaaddr
->lcim
&= ~RDAEXT
;
lpaaddr
->lcim
|= ((ubareg
>> (16-RDAEXTOFFSET
)) & RDAEXT
) | GO
;
ubarelse(ubanum
, &ubareg
);
register struct lpadevice
*lpaaddr
;
register struct lpa_softc
*sc
;
while ((lpaaddr
->lcim
& READYI
) == 0) {
sleep((caddr_t
)sc
, LPAPRI
);
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
if (sc
->sc_flag
& SLEEP
) {
register struct lpa_softc
*sc
= &lpa_softc
[unit
];
register struct uba_device
*ui
= lpadinfo
[unit
];
register struct lpadevice
*lpaaddr
= (struct lpadevice
*) ui
->ui_addr
;
if (sc
->sc_flag
& SLEEP
) {
lpaaddr
->lcos
&= ~READYO
;
if ((sc
->sc_flag
& STOP
) == 0 || (c
!= OVERRUN
)) {
printf("LPA ERROR %o %o\n", c
, m
&0177777);
TRACERN("<LPA %d>", sc
->sc_lbufnx
);
sc
->sc_lbufn
= sc
->sc_lbufnx
;
if (sc
->sc_ubufn
== sc
->sc_lbufnx
&& c
& ECODE
) {
TRACERN("<USTAT %o>", sc
->sc_ustat
);
sc
->sc_ustat
|= sc
->sc_lbufnx
<< 8;
TRACERN("<LPAN %d>}", sc
->sc_lbufnx
);
register struct uba_device
*ui
;
register struct lpadevice
*lpaaddr
;
register struct lpa_softc
*sc
;
for (unit
= 0; unit
< NLPA
; unit
++) {
if ((ui
= lpadinfo
[unit
]) == 0 ||
ui
->ui_ubanum
!= uban
|| ui
->ui_alive
== 0)
lpaaddr
= (struct lpadevice
*)ui
->ui_addr
;
if (sc
->sc_flag
& SLEEP
) {