177 lines
3.0 KiB
C
177 lines
3.0 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)sg.c 1.1 94/10/31 Copyr 1983 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1983 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* Sun-2 Sound Generator Driver (TI SN76489AN)
|
|
*/
|
|
#include "../h/param.h"
|
|
#include "../h/buf.h"
|
|
#include "../h/uio.h"
|
|
#include "../h/errno.h"
|
|
#include "../sun/pte.h"
|
|
#include "../sundev/mbvar.h"
|
|
#include "../sundev/video.h"
|
|
|
|
/*
|
|
* Driver information for auto-configuration stuff.
|
|
*/
|
|
int sgprobe(), sgattach();
|
|
struct mb_device *sginfo[1]; /* XXX only supports 1 chip */
|
|
u_long sgstd[] = { 0 }; /* no standard addresses */
|
|
struct mb_driver sgdriver = {
|
|
sgprobe, 0, sgattach, 0, 0, 0, sgstd, 0, 1, "sg", sginfo, 0, 0, 0
|
|
};
|
|
|
|
/*
|
|
* States driver can be in.
|
|
*/
|
|
#define S_CLOSED 0
|
|
#define S_OPEN 1
|
|
#define S_DELAY1 2
|
|
#define S_DELAY2 3
|
|
#define S_DELAY3 4
|
|
#define S_DELAY4 5
|
|
|
|
int sgstate; /* current state of driver */
|
|
u_int sgdelay; /* microseconds to delay */
|
|
|
|
#define SGBUFSIZ 512
|
|
#define SGPRI 29 /* priority to sleep at when delaying */
|
|
|
|
extern wakeup();
|
|
extern int hz;
|
|
|
|
/*ARGSUSED*/
|
|
sgprobe(reg, unit)
|
|
caddr_t reg;
|
|
int unit;
|
|
{
|
|
register int c;
|
|
|
|
if (pokec((char *)reg, 0))
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
sgattach(md)
|
|
register struct mb_device *md;
|
|
{
|
|
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
sgopen(dev, flag)
|
|
dev_t dev;
|
|
int flag;
|
|
{
|
|
struct videoctl *vc = (struct videoctl *)0xee3800;
|
|
|
|
if (sgstate != S_CLOSED)
|
|
return (ENXIO);
|
|
sgstate = S_OPEN;
|
|
sgdelay = 0;
|
|
vc->vc_sg_en = 1;
|
|
return (0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
sgclose(dev, flag)
|
|
dev_t dev;
|
|
int flag;
|
|
{
|
|
struct videoctl *vc = (struct videoctl *)0xee3800;
|
|
|
|
vc->vc_sg_en = 0;
|
|
if (sgdelay) {
|
|
untimeout(wakeup, (caddr_t)&sgdelay);
|
|
sgdelay = 0;
|
|
}
|
|
sgstate = S_CLOSED;
|
|
return (0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
sgwrite(dev, uio)
|
|
dev_t dev;
|
|
register struct uio *uio;
|
|
{
|
|
register u_char *sgp = (u_char *)sginfo[0]->md_addr;
|
|
register u_char *cp;
|
|
register int cc;
|
|
int error = 0;
|
|
u_char obuf[SGBUFSIZ];
|
|
|
|
/*
|
|
* Process the user's data in at most SGBUFSIZ chunks.
|
|
*/
|
|
while (uio->uio_resid > 0) {
|
|
/*
|
|
* Grab a hunk of data from the user.
|
|
*/
|
|
cc = uio->uio_iov->iov_len;
|
|
if (cc == 0) {
|
|
uio->uio_iovcnt--;
|
|
uio->uio_iov++;
|
|
if (uio->uio_iovcnt < 0) {
|
|
printf("sg: iovcnt < 0\n");
|
|
error = EIO;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (cc > SGBUFSIZ)
|
|
cc = SGBUFSIZ;
|
|
cp = obuf;
|
|
error = uiomove(cp, cc, UIO_WRITE, uio);
|
|
if (error)
|
|
break;
|
|
while (cc > 0) {
|
|
switch (sgstate) {
|
|
case S_CLOSED:
|
|
case S_OPEN:
|
|
default:
|
|
if ((*cp&0xc0) != 0x40) {
|
|
*sgp = *cp;
|
|
DELAY(8);
|
|
} else
|
|
sgstate = S_DELAY1;
|
|
break;
|
|
|
|
case S_DELAY1:
|
|
case S_DELAY2:
|
|
case S_DELAY3:
|
|
sgdelay <<= 8;
|
|
sgdelay |= *cp;
|
|
sgstate++;
|
|
break;
|
|
|
|
case S_DELAY4:
|
|
sgdelay <<= 8;
|
|
sgdelay |= *cp;
|
|
if (sgdelay < 4*(1000000/hz)) {
|
|
DELAY(sgdelay);
|
|
} else {
|
|
int s = spl6();
|
|
|
|
timeout(wakeup, (caddr_t)&sgdelay,
|
|
sgdelay / (1000000/hz));
|
|
sleep((caddr_t)&sgdelay, SGPRI);
|
|
(void) splx(s);
|
|
}
|
|
sgdelay = 0;
|
|
sgstate = S_OPEN;
|
|
break;
|
|
}
|
|
cp++;
|
|
cc--;
|
|
}
|
|
}
|
|
return (error);
|
|
}
|