MODULE EnsoniqSound;
IMPORT SYSTEM, KernelLog, PCI, Objects, Kernel, Machine, Modules, Plugins, SoundDevices;
CONST
Trace = FALSE;
Bsize = 25600 * 3;
Es1370RegControl = 0;
Es1370RegStatus = 4H;
Es1370RegSerialControl = 20H;
Es1370RegMemPage = 0CH;
Es1371RegCodec = 14H;
Es1371RegLegacy = 18H;
Es1371RegSmprate = 10H;
Es1370RegDac1Scount = 24H;
Es1370RegDac2Scount = 28H;
Es1370RegAdcScount = 2CH;
Es1371SyncRes = 4000H;
Es1371DisSrc = 400000H;
Es1371SrcRamBusy = 800000H;
EsSmpregDac1 = 70H;
EsSmpregDac2 = 74H;
EsSmpregAdc = 78H;
EsSmpregVolAdc = 6CH;
EsSmpregVolDac1 = 7CH;
EsSmpregVolDac2 = 7EH;
NumMixerChannels = 5;
TYPE
Sample = ARRAY 4 OF CHAR;
Bufferlist = RECORD
content : SoundDevices.Buffer;
next : POINTER TO Bufferlist
END;
Listenerlist = RECORD
proc : SoundDevices.MixerChangedProc;
next : POINTER TO Listenerlist
END;
BuffersToReturn = RECORD
blistener : SoundDevices.BufferListener;
content : SoundDevices.Buffer;
next : POINTER TO BuffersToReturn
END;
BufferObj* = OBJECT
VAR inplaycopy : BOOLEAN;
drv : Driver;
PROCEDURE Setinplaycopy(pc: BOOLEAN);
BEGIN {EXCLUSIVE}
inplaycopy := pc
END Setinplaycopy;
PROCEDURE ReturnAllBuffers(chan: Channel);
BEGIN {EXCLUSIVE}
AWAIT(inplaycopy=FALSE);
chan.ReturnAllBuffers
END ReturnAllBuffers;
END BufferObj;
MixerChannel*=OBJECT(SoundDevices.MixerChannel)
VAR vol : LONGINT;
muted : BOOLEAN;
name, desc : POINTER TO ARRAY OF CHAR;
reg : LONGINT;
drv : Driver;
PROCEDURE &Constr*(drv: Driver; name, desc : ARRAY OF CHAR; reg : LONGINT);
VAR i : LONGINT;
BEGIN
SELF.drv := drv;
NEW(SELF.name, LEN(name));
FOR i := 0 TO LEN(name)-1 DO
SELF.name^[i] := name[i]
END;
NEW(SELF.desc, LEN(desc));
FOR i := 0 TO LEN(desc)-1 DO
SELF.desc^[i] := desc[i]
END;
SELF.reg := reg;
i := 0;
WHILE (i < NumMixerChannels-1) & (SELF.drv.mixerChannels[i] # NIL) DO
INC(i)
END;
SELF.drv.mixerChannels[i] := SELF
END Constr;
PROCEDURE SetVolume*(vol : LONGINT);
VAR resl : LONGINT;
BEGIN
IF vol > 0FFH THEN SELF.vol := 0FFH END;
IF vol < 0 THEN SELF.vol := 0 END;
SELF.vol := vol;
resl := 31-SELF.vol DIV 8;
resl := resl+256*resl;
drv.EsWrCd(reg, SYSTEM.VAL(INTEGER, resl));
CallListener
END SetVolume;
PROCEDURE GetVolume*() : LONGINT;
BEGIN
RETURN(vol)
END GetVolume;
PROCEDURE GetIsMute*(): BOOLEAN;
BEGIN
RETURN muted
END GetIsMute;
PROCEDURE CallListener;
VAR nl : POINTER TO Listenerlist;
BEGIN
IF drv.listenerlist # NIL THEN
nl := drv.listenerlist;
WHILE nl.next # NIL DO
IF nl.proc # NIL THEN
nl.proc(SELF)
END;
nl := nl.next
END;
IF nl.proc # NIL THEN
nl.proc(SELF)
END
END
END CallListener;
PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
BEGIN
COPY(SELF.name^, name)
END GetName;
PROCEDURE GetDesc*(VAR desc: ARRAY OF CHAR);
BEGIN
COPY (SELF.desc^, desc)
END GetDesc;
PROCEDURE SetMute*(muted: BOOLEAN);
BEGIN
IF SELF.muted # muted THEN
IF muted THEN
drv.EsWrCd(reg, SYSTEM.VAL(INTEGER, 8000H))
ELSE
SetVolume(vol)
END;
SELF.muted := muted;
CallListener
END
END SetMute;
END MixerChannel;
PlayMixerChannel=OBJECT(MixerChannel)
PROCEDURE SetVolume*(vol: LONGINT);
VAR resl : LONGINT;
BEGIN
IF vol > 0FFH THEN vol := 0FFH END;
IF vol < 0 THEN vol := 0 END;
SELF.vol := vol;
resl := 63-vol DIV 4;
resl := resl+256*resl;
drv.EsWrCd(reg, SYSTEM.VAL(INTEGER, resl));
CallListener
END SetVolume;
END PlayMixerChannel;
RecMixerChannel=OBJECT(MixerChannel)
PROCEDURE SetVolume*(vol: LONGINT);
VAR resl : LONGINT;
BEGIN
IF vol > 0FFH THEN vol := 0FFH END;
IF vol < 0 THEN vol := 0 END;
SELF.vol := vol;
resl := vol DIV 16;
resl := resl+256*resl;
drv.EsWrCd(reg, SYSTEM.VAL(INTEGER, resl));
CallListener
END SetVolume;
END RecMixerChannel;
Channel*=OBJECT(SoundDevices.Channel)
VAR active, free: BOOLEAN;
first, last: POINTER TO Bufferlist;
blistener : SoundDevices.BufferListener;
vol : INTEGER;
ratedone : LONGINT;
pos : LONGINT;
samplingRate, samplingResolution, nofSubChannels: LONGINT;
delta: LONGINT;
drv : Driver;
pause, stop, start : BOOLEAN;
silent, rsilent : BOOLEAN;
PROCEDURE ReturnAllBuffers;
VAR driver : POINTER TO Bufferlist;
BEGIN
driver := first;
WHILE driver#NIL DO
drv.AddBufferToReturn(blistener, driver.content);
driver := driver.next
END;
first := NIL; last := NIL
END ReturnAllBuffers;
PROCEDURE &Init*(drv : Driver);
BEGIN
SELF.drv := drv;
pause := FALSE; stop := FALSE; start := FALSE
END Init;
PROCEDURE SetVolume*(vol: LONGINT);
BEGIN
IF vol > 0FFFFH THEN vol := 0FFFFH; END;
IF vol < 0 THEN vol := 0; END;
SELF.vol := SHORT(vol)
END SetVolume;
PROCEDURE GetVolume*() : LONGINT;
BEGIN
RETURN vol
END GetVolume;
PROCEDURE GetPosition() : LONGINT;
BEGIN
RETURN pos
END GetPosition;
PROCEDURE Pause*;
BEGIN {EXCLUSIVE}
active := FALSE
END Pause;
PROCEDURE PauseNonExclusive;
BEGIN
active := FALSE
END PauseNonExclusive;
PROCEDURE Close*;
BEGIN
Stop;
free := TRUE
END Close;
PROCEDURE RegisterBufferListener*(blistener: SoundDevices.BufferListener);
BEGIN
SELF.blistener := blistener
END RegisterBufferListener;
END Channel;
PlayerChannel=OBJECT(Channel)
VAR sample, oldsample : Sample;
PROCEDURE Pause*;
BEGIN {EXCLUSIVE}
pause := TRUE
END Pause;
PROCEDURE PauseNonExclusive;
BEGIN
drv.introbj.Deactivate(SELF)
END PauseNonExclusive;
PROCEDURE Stop*;
BEGIN {EXCLUSIVE}
stop := TRUE
END Stop;
PROCEDURE QueueBuffer*(buf: SoundDevices.Buffer);
VAR bufferlist: POINTER TO Bufferlist;
BEGIN {EXCLUSIVE}
IF last # NIL THEN
NEW(bufferlist);
last.next := bufferlist;
bufferlist.next := NIL;
bufferlist.content := buf;
last := bufferlist
ELSE
NEW(bufferlist);
last := bufferlist;
last.next := NIL;
bufferlist.content := buf;
sample[0] := CHR(0); sample[1] := CHR(0);
sample[2] := CHR(0); sample[3] := CHR(0);
ratedone := 48000-samplingRate;
pos := 0
END;
IF first = NIL THEN first := bufferlist END
END QueueBuffer;
PROCEDURE NextBuffer;
BEGIN {EXCLUSIVE}
IF first # NIL THEN
IF first.next # NIL THEN
first := first.next
ELSE
silent := TRUE; active := FALSE;
DEC(drv.introbj.numplayer);
first := NIL
END
END
END NextBuffer;
PROCEDURE Start*;
BEGIN {EXCLUSIVE}
start := TRUE
END Start;
PROCEDURE AwaitEvent;
BEGIN {EXCLUSIVE}
AWAIT(pause OR start OR stop)
END AwaitEvent;
BEGIN {ACTIVE}
REPEAT
AwaitEvent;
IF pause THEN
drv.introbj.Deactivate(SELF); pause := FALSE
END;
IF stop THEN
drv.introbj.Deactivate(SELF);
drv.bufferobj.ReturnAllBuffers(SELF);
stop := FALSE
END;
IF start THEN
IF (first#NIL) THEN (* at least one buffer is registered *)
drv.introbj.Activate(SELF)
END;
start := FALSE
END
UNTIL 1=2
END PlayerChannel;
RecordChannel=OBJECT(Channel)
PROCEDURE Stop*;
BEGIN {EXCLUSIVE}
PauseNonExclusive;
drv.introbj.WaitNoRec;
drv.bufferobj.ReturnAllBuffers(SELF)
END Stop;
PROCEDURE QueueBuffer*(buf: SoundDevices.Buffer);
VAR bufferlist: POINTER TO Bufferlist;
BEGIN
IF last # NIL THEN
NEW(bufferlist);
last.next := bufferlist;
bufferlist.next := NIL;
bufferlist.content := buf;
last := bufferlist
ELSE
NEW(bufferlist);
last := bufferlist;
last.next := NIL;
bufferlist.content := buf;
ratedone := 0;
pos := 0
END;
IF first = NIL THEN first := bufferlist END
END QueueBuffer;
PROCEDURE NextBuffer;
BEGIN {EXCLUSIVE}
IF first.next # NIL THEN
first := first.next
ELSE
rsilent := TRUE; active := FALSE;
first := NIL
END
END NextBuffer;
PROCEDURE Start;
BEGIN {EXCLUSIVE}
IF first#NIL THEN
active := TRUE;
IF ~ (4 IN SYSTEM.VAL(SET, drv.EsState.rctrl)) THEN
IF Trace THEN KernelLog.String("Enabling ADC Interrupt"); END;
drv.rloopcount := 0;
Machine.Portout8(drv.base+Es1370RegMemPage, 0DX);
Machine.Portout32(drv.base+34H, SYSTEM.VAL(LONGINT, Bsize DIV 4-1));
drv.EsState.rctrl := SYSTEM.VAL(LONGINT, {4}+SYSTEM.VAL(SET, drv.EsState.rctrl));
Machine.Portout32(drv.base+Es1370RegControl, drv.EsState.rctrl)
END
END
END Start;
END RecordChannel;
Driver*=OBJECT(SoundDevices.Driver)
VAR playchannels : ARRAY 32 OF PlayerChannel;
recordchannels : ARRAY 32 OF RecordChannel;
pcm, line, cd : MixerChannel;
time: Kernel.Timer;
base, irq : LONGINT;
EsState : RECORD
sctrl : LONGINT;
rctrl : LONGINT;
END;
p2, pr2 : POINTER TO ARRAY OF CHAR;
loopcount, rloopcount : LONGINT;
next: Driver;
introbj : Introbj;
masterout : PlayMixerChannel;
masterin : RecMixerChannel;
allsilent, rallsilent : BOOLEAN;
playcopy, reccopy : BOOLEAN;
listenerlist : POINTER TO Listenerlist;
mixerChannels : ARRAY NumMixerChannels OF MixerChannel;
buffersToReturn, lastbtr : POINTER TO BuffersToReturn;
bufferobj : BufferObj;
PROCEDURE SetRecordSource*(i: INTEGER);
BEGIN
EsWrCd(1AH, SYSTEM.VAL(INTEGER, i+i*256))
END SetRecordSource;
PROCEDURE &Constructor*(irq, base: LONGINT);
BEGIN
NEW(bufferobj);
buffersToReturn := NIL;
lastbtr := NIL;
SELF.base := base;
SELF.irq := irq;
SELF.next := installedDrivers;
installedDrivers := SELF;
INC(installed);
Init
END Constructor;
PROCEDURE AddBufferToReturn(blistener: SoundDevices.BufferListener; content: SoundDevices.Buffer);
VAR newbtr : POINTER TO BuffersToReturn;
BEGIN {EXCLUSIVE}
NEW(newbtr);
newbtr.blistener := blistener;
newbtr.content := content;
newbtr.next := NIL;
IF buffersToReturn # NIL THEN lastbtr.next := newbtr; lastbtr := newbtr
ELSE buffersToReturn := newbtr; lastbtr := buffersToReturn END
END AddBufferToReturn;
PROCEDURE ReturnBuffers;
BEGIN {EXCLUSIVE}
WHILE buffersToReturn # NIL DO
buffersToReturn.blistener(buffersToReturn.content);
buffersToReturn := buffersToReturn.next
END
END ReturnBuffers;
PROCEDURE WaitBuffersToReturn;
BEGIN {EXCLUSIVE}
AWAIT(buffersToReturn # NIL)
END WaitBuffersToReturn;
PROCEDURE EsWaitSrcReady() : LONGINT;
VAR t, r : LONGINT;
BEGIN
FOR t := 0 TO 500 DO
Machine.Portin32(base+Es1371RegSmprate, SYSTEM.VAL(LONGINT, r));
IF ~(23 IN SYSTEM.VAL(SET, r)) THEN
RETURN r
END
END;
KernelLog.String("es1371: wait src ready timeout");
RETURN 0
END EsWaitSrcReady;
PROCEDURE EsSrcRamAddro(reg: LONGINT): SET;
VAR s, s2 : SET;
i : LONGINT;
BEGIN
s := SYSTEM.VAL(SET, reg);
s := s*{0..6};
s2 := {};
FOR i := 0 TO 6 DO
IF i IN s THEN s2 := s2+{i+25} END
END;
RETURN s2
END EsSrcRamAddro;
PROCEDURE EsSrcRamDatao(reg: LONGINT): SET;
VAR s : SET;
BEGIN
s := SYSTEM.VAL(SET, reg);
s := s*{0..15};
RETURN s
END EsSrcRamDatao;
PROCEDURE EsSrcWrite(reg, data: LONGINT);
VAR r : LONGINT;
VAR s : SET;
BEGIN
r := EsWaitSrcReady();
s := SYSTEM.VAL(SET, r);
s := s * {19..22};
s := s + EsSrcRamAddro(reg)+EsSrcRamDatao(data);
s := s + {24};
r := SYSTEM.VAL(LONGINT, s);
Machine.Portout32(base+Es1371RegSmprate, r)
END EsSrcWrite;
PROCEDURE EsSrcRead(reg: LONGINT) : LONGINT;
VAR r : LONGINT; s : SET;
BEGIN
r := EsWaitSrcReady();
s := SYSTEM.VAL(SET, r);
s := s*{19..22};
s := s + EsSrcRamAddro(reg);
r := SYSTEM.VAL(LONGINT, r);
Machine.Portout32(base+Es1371RegSmprate, r);
r := EsWaitSrcReady();
RETURN SYSTEM.VAL(LONGINT, EsSrcRamDatao(r))
END EsSrcRead;
PROCEDURE EsAdcRate(rate, set: LONGINT);
VAR n, truncm, freq, result, tmp : LONGINT;
stmp : SET;
BEGIN
IF rate > 48000 THEN rate := 48000 END;
IF rate < 4000 THEN rate := 4000 END;
n := rate DIV 3000;
IF ((n=15) OR (n=13) OR (n=11) OR (n=9)) THEN DEC(n) END;
truncm := (21*n-1);
truncm := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, truncm)+{0});
freq := ((48000*32768) DIV rate) * n;
result := ((48000*32768) DIV (freq DIV n));
IF set>0 THEN
IF (rate >= 24000) THEN
IF (truncm > 239) THEN truncm := 239; END;
tmp := ((239-truncm) DIV 2) * 512;
stmp := SYSTEM.VAL(SET, tmp) + SYSTEM.VAL(SET, n*16);
tmp := SYSTEM.VAL(LONGINT, stmp);
EsSrcWrite(EsSmpregAdc, tmp)
ELSE
IF (truncm < 119) THEN truncm := 119; END;
tmp := ((119-truncm) DIV 2) * 512;
stmp := SYSTEM.VAL(SET, tmp)+SYSTEM.VAL(SET, n*16)+{15};
tmp := SYSTEM.VAL(LONGINT, stmp);
EsSrcWrite(EsSmpregAdc, tmp)
END;
tmp := EsSrcRead(EsSmpregAdc+1);
stmp := SYSTEM.VAL(SET, tmp)*{0..7};
stmp := stmp + (SYSTEM.VAL(SET, freq DIV 32)*{10..15});
EsSrcWrite(EsSmpregAdc+1, SYSTEM.VAL(LONGINT, stmp));
EsSrcWrite(EsSmpregAdc+3, SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, freq)*{0..14}));
EsSrcWrite(EsSmpregVolAdc, SYSTEM.VAL(LONGINT, n * 256));
EsSrcWrite(EsSmpregVolAdc+1, SYSTEM.VAL(LONGINT, n * 256))
END
END EsAdcRate;
PROCEDURE EsDacRate(rate, set: LONGINT);
VAR freq, r, result, dac, dis, temp : LONGINT;
VAR stmp : SET;
BEGIN
IF rate > 48000 THEN rate := 48000; END;
IF rate < 4000 THEN rate := 4000; END;
freq := (rate * 32768) DIV 3000;
result := (freq * 3000) DIV 32768;
IF set>0 THEN
IF set = 1 THEN dac := EsSmpregDac1; ELSE dac := EsSmpregDac2; END;
IF set = 1 THEN dis := 20; ELSE dis := 21; END;
r := EsWaitSrcReady();
stmp := SYSTEM.VAL(SET, r)*{19..22};
r := SYSTEM.VAL(LONGINT, stmp);
Machine.Portout32(base+Es1371RegSmprate, r);
r := EsSrcRead(dac+1);
stmp := SYSTEM.VAL(SET, r)*{0..7};
stmp := stmp + (SYSTEM.VAL(SET, freq DIV 32)*{10..15});
temp := SYSTEM.VAL(LONGINT, stmp);
EsSrcWrite(dac+1, temp);
stmp := SYSTEM.VAL(SET, freq);
stmp := stmp*{0..14};
temp := SYSTEM.VAL(LONGINT, stmp);
EsSrcWrite(dac+3, temp);
r := EsWaitSrcReady();
stmp := SYSTEM.VAL(SET, r);
stmp := stmp*({22}+{dis}+{19});
r := SYSTEM.VAL(LONGINT, stmp);
Machine.Portout32(base+Es1371RegSmprate, r)
END
END EsDacRate;
PROCEDURE EsWrCd(addr, data: LONGINT);
VAR t, res, x, i: LONGINT;
VAR tset, tset2 : SET;
BEGIN
t := 0;
REPEAT
INC(t);
Machine.Portin32(base+Es1371RegCodec, SYSTEM.VAL(LONGINT, res))
UNTIL ((t>2000) OR ~(30 IN SYSTEM.VAL(SET, res)));
Machine.Portin32(base+Es1371RegSmprate, SYSTEM.VAL(LONGINT, x));
t := EsWaitSrcReady();
t := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, t)*{19..22});
Machine.Portout32(base+Es1371RegSmprate, t);
t := 0;
REPEAT
INC(t);
Machine.Portin32(base+Es1371RegSmprate, SYSTEM.VAL(LONGINT, res))
UNTIL (t>2000) OR (SYSTEM.VAL(SET, res)*{16..18, 23} = {16});
tset := SYSTEM.VAL(SET, addr)*{0..6};
tset2 := {};
FOR i := 0 TO 6 DO
IF i IN tset THEN tset2 := tset2+{i+16} END
END;
tset := SYSTEM.VAL(SET, data)*{0..15};
tset := tset+tset2;
res := SYSTEM.VAL(LONGINT, tset);
Machine.Portout32(base+Es1371RegCodec, res);
t := EsWaitSrcReady();
Machine.Portout32(base+Es1371RegSmprate, x)
END EsWrCd;
PROCEDURE Initdrv;
VAR i: LONGINT;
sndbuf : Machine.Address32;
BEGIN
FOR i := 0 TO 31 DO
NEW(playchannels[i], SELF);
playchannels[i].active := FALSE;
playchannels[i].free := TRUE
END;
FOR i := 0 TO 31 DO
NEW(recordchannels[i], SELF);
recordchannels[i].active := FALSE;
recordchannels[i].free := TRUE
END;
NEW(introbj, SELF);
introbj.numplayer := 0;
EsState.sctrl := SYSTEM.VAL(LONGINT, {20});
EsState.rctrl := 0;
NEW(time);
Objects.InstallHandler(introbj.HandleInterrupt, Machine.IRQ0+irq);
Machine.Portout32(base+Es1370RegStatus, SYSTEM.VAL(LONGINT, {29}));
time.Sleep(20);
Machine.Portout32(base+Es1370RegSerialControl, SYSTEM.VAL(LONGINT, 0));
Machine.Portout32(base+Es1371RegLegacy, SYSTEM.VAL(LONGINT, 0));
Machine.Portout32(base+Es1370RegControl, SYSTEM.VAL(LONGINT, Es1371SyncRes));
time.Sleep(2); Machine.Portout32(base+Es1370RegControl, SYSTEM.VAL(LONGINT, {}));
Machine.Portout32(base+Es1371RegSmprate, SYSTEM.VAL(LONGINT, Es1371DisSrc));
FOR i := 0 TO 07FH DO
EsSrcWrite(SYSTEM.VAL(INTEGER, i), 0)
END;
EsSrcWrite(EsSmpregDac1, SYSTEM.VAL(LONGINT, {8}));
EsSrcWrite(EsSmpregDac1+1, SYSTEM.VAL(LONGINT, {14}));
EsSrcWrite(EsSmpregDac2, SYSTEM.VAL(LONGINT, {8}));
EsSrcWrite(EsSmpregDac2+1, SYSTEM.VAL(LONGINT, {14}));
EsSrcWrite(EsSmpregAdc, SYSTEM.VAL(LONGINT, {8}));
EsSrcWrite(EsSmpregAdc+1, SYSTEM.VAL(LONGINT, {14}));
EsSrcWrite(EsSmpregVolAdc, SYSTEM.VAL(LONGINT, {12}));
EsSrcWrite(EsSmpregVolAdc+1, SYSTEM.VAL(LONGINT, {12}));
EsSrcWrite(EsSmpregVolDac1, SYSTEM.VAL(LONGINT, {12}));
EsSrcWrite(EsSmpregVolDac1+1, SYSTEM.VAL(LONGINT, {12}));
EsSrcWrite(EsSmpregVolDac2, SYSTEM.VAL(LONGINT, {12}));
EsSrcWrite(EsSmpregVolDac2+1, SYSTEM.VAL(LONGINT, {12}));
EsAdcRate(48000, 1);
EsDacRate(48000, 2);
Machine.Portout32(base+Es1371RegSmprate, SYSTEM.VAL(LONGINT, 0));
NEW(pr2, Bsize);
rloopcount := 0;
NEW(p2, Bsize);
loopcount := 0;
Machine.Portout32(base+Es1370RegControl, SYSTEM.VAL(LONGINT, {}));
sndbuf := Machine.Ensure32BitAddress (Machine.PhysicalAdr(SYSTEM.ADR(pr2[0]), Bsize));
IF sndbuf = -1 THEN KernelLog.String("not enough defragmented space"); END;
Machine.Portout8(base+Es1370RegMemPage, 0DX);
Machine.Portout32(base+30H, SYSTEM.VAL(LONGINT, sndbuf));
Machine.Portout32(base+34H, SYSTEM.VAL(LONGINT, Bsize DIV 4-1));
Machine.Portout32(base+Es1370RegAdcScount, SYSTEM.VAL(LONGINT, Bsize DIV 8-1));
EsState.sctrl := SYSTEM.VAL(LONGINT, {4, 5, 10}+SYSTEM.VAL(SET, EsState.sctrl));
Machine.Portout32(base+Es1370RegSerialControl, EsState.sctrl);
sndbuf := Machine.Ensure32BitAddress (Machine.PhysicalAdr(SYSTEM.ADR(p2[0]), Bsize));
IF sndbuf = -1 THEN KernelLog.String("not enough defragmented space") END;
Machine.Portout8(base+Es1370RegMemPage, 0CX);
Machine.Portout32(base+38H, SYSTEM.VAL(LONGINT, sndbuf));
Machine.Portout32(base+3CH, SYSTEM.VAL(LONGINT, Bsize DIV 4-1));
Machine.Portout32(base+Es1370RegDac2Scount, SYSTEM.VAL(LONGINT, Bsize DIV 8-1));
EsState.sctrl := SYSTEM.VAL(LONGINT, {2, 3, 9} + SYSTEM.VAL(SET, EsState.sctrl));
Machine.Portout32(base+Es1370RegSerialControl, EsState.sctrl)
END Initdrv;
PROCEDURE Initvol;
BEGIN
EsWrCd(2, 0000H);
EsWrCd(4, 8000H);
EsWrCd(6, 8000H);
EsWrCd(8, 8000H);
EsWrCd(0CH, 8000H);
EsWrCd(0EH, 8000H);
EsWrCd(10H, 4040H);
EsWrCd(18H, 4040H);
EsWrCd(1AH, SYSTEM.VAL(INTEGER, 5+5*256));
EsWrCd(1CH, SYSTEM.VAL(INTEGER, 0+0*256));
EsWrCd(1EH, SYSTEM.VAL(INTEGER, 0));
IF Trace THEN KernelLog.String("Volume initialized"); KernelLog.Ln END
END Initvol;
PROCEDURE Finalize;
BEGIN
Machine.Portout32(base+Es1370RegSerialControl, SYSTEM.VAL(LONGINT, {20}));
Objects.RemoveHandler(introbj.HandleInterrupt, Machine.IRQ0+irq);
time.Sleep(100);
IF Modules.shutdown = Modules.None THEN
SoundDevices.devices.Remove(SELF)
END
END Finalize;
PROCEDURE Init*;
VAR i : LONGINT;
BEGIN
Initdrv;
Initvol;
FOR i := 0 TO NumMixerChannels-1 DO mixerChannels[i] := NIL END;
NEW(masterout, SELF, "MasterOut", "Master Output mixer channel", 02H);
NEW(masterin, SELF, "MasterIn", "master Input mixer channel", 1CH);
NEW(pcm, SELF, "PCM", "PCM Output mixer channel", 18H);
NEW(line, SELF, "LineIn", "Line In mixer channel", 10H);
NEW(cd, SELF, "CD", "CD mixer channel", 12H);
masterIn := masterin;
masterOut := masterout;
desc := "Ensoniq PCI Sound driver";
masterin.SetVolume(0H);
masterout.SetVolume(0FFH);
pcm.SetVolume(0D8H);
masterin.muted := FALSE;
masterout.muted := FALSE;
pcm.muted := FALSE;
line.SetVolume(0D8H);
cd.SetVolume(0D8H);
cd.SetMute(TRUE);
NEW(listenerlist);
listenerlist.proc := NIL;
listenerlist.next := NIL;
IF Trace THEN KernelLog.String("init done"); KernelLog.Ln END
END Init;
PROCEDURE OpenPlayChannel*(VAR channel : SoundDevices.Channel;
samplingRate, samplingResolution, nofSubChannels, format : LONGINT;
VAR res : LONGINT);
VAR i, count : LONGINT;
BEGIN {EXCLUSIVE}
channel := NIL;
count := 0;
FOR i := 0 TO 31 DO
IF ~playchannels[i].free THEN
INC(count)
END
END;
IF Trace THEN KernelLog.String("Active channel #: "); KernelLog.Int(count, 0); KernelLog.Ln END;
i := 0;
WHILE (i<=31) & (~playchannels[i].free) DO
INC(i);
END;
IF i <32 THEN
channel := playchannels[i];
playchannels[i].free := FALSE;
playchannels[i].first := NIL;
playchannels[i].last := NIL;
playchannels[i].samplingRate := samplingRate;
playchannels[i].samplingResolution := samplingResolution;
playchannels[i].nofSubChannels := nofSubChannels;
playchannels[i].delta := (samplingResolution DIV 8) * nofSubChannels;
playchannels[i].SetVolume(100H);
playchannels[i].RegisterBufferListener(DefaultBufferListener);
res := SoundDevices.ResOK;
IF Trace THEN KernelLog.String("Open play channel #: "); KernelLog.Int(i, 0); KernelLog.Ln END
ELSE res := SoundDevices.ResNoMoreChannels
END
END OpenPlayChannel;
PROCEDURE OpenRecordChannel*(VAR channel : SoundDevices.Channel;
samplingRate, samplingResolution, nofSubChannels, format : LONGINT;
VAR res: LONGINT);
VAR i : LONGINT;
BEGIN
channel := NIL;
i := 0;
WHILE (i <= 31) & (~recordchannels[i].free) DO
INC(i)
END;
IF i<32 THEN
channel := recordchannels[i];
recordchannels[i].free := FALSE;
recordchannels[i].first := NIL;
recordchannels[i].last := NIL;
recordchannels[i].samplingRate := samplingRate;
recordchannels[i].samplingResolution := samplingResolution;
recordchannels[i].nofSubChannels := nofSubChannels;
recordchannels[i].delta := (samplingResolution DIV 8) * nofSubChannels;
recordchannels[i].SetVolume(100H);
recordchannels[i].RegisterBufferListener(DefaultBufferListener);
res := SoundDevices.ResOK
ELSE res := SoundDevices.ResNoMoreChannels
END
END OpenRecordChannel;
PROCEDURE NofNativeFrequencies*():LONGINT;
BEGIN
RETURN 1
END NofNativeFrequencies;
PROCEDURE GetNativeFrequency*(nr: LONGINT): LONGINT;
BEGIN
RETURN 48000
END GetNativeFrequency;
PROCEDURE RegisterMixerChangeListener*(mixChangedProc: SoundDevices.MixerChangedProc);
VAR nlistenerlist, nl : POINTER TO Listenerlist;
BEGIN
IF listenerlist.proc = NIL THEN
listenerlist.proc := mixChangedProc
ELSE
nlistenerlist := listenerlist;
WHILE nlistenerlist.next # NIL DO
nlistenerlist := nlistenerlist.next
END;
NEW(nl);
nl.proc := mixChangedProc;
nl.next := NIL;
nlistenerlist.next := nl
END
END RegisterMixerChangeListener;
PROCEDURE UnregisterMixerChangeListener*(mixChangedProc: SoundDevices.MixerChangedProc);
VAR nlistenerlist, nl : POINTER TO Listenerlist;
BEGIN
nlistenerlist := listenerlist;
IF nlistenerlist.proc = mixChangedProc THEN
IF listenerlist.next # NIL THEN listenerlist := listenerlist.next
ELSE
listenerlist.proc := NIL
END
ELSE
WHILE (nlistenerlist.next # NIL) & (nlistenerlist.proc # mixChangedProc) DO
nl := nlistenerlist;
nlistenerlist := nlistenerlist.next
END;
IF nlistenerlist.proc=mixChangedProc THEN
nl.next := nlistenerlist.next
END
END
END UnregisterMixerChangeListener;
PROCEDURE GetMixerChannel*(channelNr: LONGINT; VAR channel: SoundDevices.MixerChannel);
BEGIN
IF (channelNr<NumMixerChannels) & (channelNr>=0) THEN
channel := (mixerChannels[channelNr])
ELSE
channel := NIL
END;
END GetMixerChannel;
PROCEDURE GetNofMixerChannels*() : LONGINT;
BEGIN
RETURN NumMixerChannels
END GetNofMixerChannels;
BEGIN {ACTIVE}
REPEAT
WaitBuffersToReturn;
ReturnBuffers
UNTIL 1=2
END Driver;
Introbj=OBJECT
VAR numplayer : LONGINT;
driver : Driver;
VAR copy : BOOLEAN;
PROCEDURE &Init*(driver : Driver);
BEGIN
SELF.driver := driver;
copy := FALSE
END Init;
PROCEDURE WaitInterruptStop;
BEGIN
AWAIT(~(5 IN SYSTEM.VAL(SET, driver.EsState.rctrl)))
END WaitInterruptStop;
PROCEDURE Deactivate(playerchannel : PlayerChannel);
BEGIN {EXCLUSIVE}
IF playerchannel.active THEN
playerchannel.active := FALSE;
DEC(numplayer);
IF numplayer=0 THEN
WaitInterruptStop
END
END
END Deactivate;
PROCEDURE Activate(playerchannel : PlayerChannel);
BEGIN {EXCLUSIVE}
IF playerchannel.active = FALSE THEN
IF numplayer=0 THEN
WaitInterruptStop;
driver.playcopy := TRUE;
driver.loopcount := 1
END;
playerchannel.active := TRUE;
INC(numplayer)
END
END Activate;
PROCEDURE HandleInterrupt;
VAR r, where : LONGINT;
sr, ssctrl : SET;
BEGIN {EXCLUSIVE}
Machine.Portin32(driver.base+Es1370RegStatus, r);
sr := SYSTEM.VAL(SET, r);
IF 31 IN sr THEN
IF 0 IN sr THEN
Machine.Portout8(driver.base+Es1370RegMemPage, 0DX);
Machine.Portin32(driver.base+34H, where);
IF where DIV 65536 >= Bsize DIV 8 -1 THEN
driver.rloopcount := 0 ELSE driver.rloopcount := 1
END;
driver.reccopy := TRUE;
ssctrl := SYSTEM.VAL(SET, driver.EsState.sctrl)-{10};
Machine.Portout32(driver.base+Es1370RegSerialControl, SYSTEM.VAL(LONGINT, ssctrl));
Machine.Portout32(driver.base+Es1370RegSerialControl, driver.EsState.sctrl)
END;
IF 1 IN sr THEN
Machine.Portout8(driver.base+Es1370RegMemPage, 0CX);
Machine.Portin32(driver.base+3CH, where);
IF where DIV 65536 >= Bsize DIV 8 - 1 THEN
driver.loopcount := 0 ELSE driver.loopcount := 1;
END;
driver.playcopy := TRUE;
ssctrl := SYSTEM.VAL(SET, driver.EsState.sctrl)-{9};
Machine.Portout32(driver.base+Es1370RegSerialControl, SYSTEM.VAL(LONGINT, ssctrl));
Machine.Portout32(driver.base+Es1370RegSerialControl, driver.EsState.sctrl)
END;
IF 2 IN sr THEN
ssctrl := SYSTEM.VAL(SET, driver.EsState.sctrl)-{8};
Machine.Portout32(driver.base+Es1370RegSerialControl, SYSTEM.VAL(LONGINT, ssctrl));
Machine.Portout32(driver.base+Es1370RegSerialControl, driver.EsState.sctrl)
END
END
END HandleInterrupt;
PROCEDURE Wait;
BEGIN {EXCLUSIVE}
AWAIT(driver.playcopy OR driver.reccopy)
END Wait;
PROCEDURE WaitNoPlay;
BEGIN {EXCLUSIVE}
AWAIT(~driver.playcopy);
END WaitNoPlay;
PROCEDURE WaitNoRec;
BEGIN
AWAIT(~driver.reccopy)
END WaitNoRec;
PROCEDURE Setplaycopy(VALUE: BOOLEAN);
BEGIN {EXCLUSIVE}
driver.playcopy := VALUE
END Setplaycopy;
PROCEDURE Clip(VAR lsigned: LONGINT);
BEGIN
IF lsigned >MAX(INTEGER) THEN
lsigned := MAX(INTEGER)
END;
IF lsigned <MIN(INTEGER) THEN
lsigned := MIN(INTEGER)
END
END Clip;
PROCEDURE Copy;
VAR first : BOOLEAN;
PROCEDURE mono(VAR ca: Sample);
BEGIN
ca[2] := ca[0];
ca[3] := ca[1]
END mono;
PROCEDURE eight(VAR ca: Sample);
BEGIN
ca[3] := CHR(ORD(ca[1])-128);
ca[2] := CHR(0);
ca[1] := CHR(ORD(ca[0])-128);
ca[0] := CHR(0)
END eight;
PROCEDURE eightmono(VAR ca: Sample);
BEGIN
eight(ca);
mono(ca)
END eightmono;
PROCEDURE Playcopy(from, to : LONGINT);
VAR signed : INTEGER;
lsigned, i, j, l : LONGINT;
nr : LONGINT;
temp : LONGINT;
PROCEDURE Readnextsample;
BEGIN
driver.playchannels[j].pos := driver.playchannels[j].pos+driver.playchannels[j].delta;
driver.playchannels[j].ratedone := nr;
driver.playchannels[j].oldsample := driver.playchannels[j].sample;
IF (driver.playchannels[j].first # NIL) & (driver.playchannels[j].pos >= driver.playchannels[j].first.content.len) THEN
driver.playchannels[j].pos := 0;
driver.AddBufferToReturn(driver.playchannels[j].blistener, driver.playchannels[j].first.content);
driver.playchannels[j].NextBuffer;
END;
IF (driver.playchannels[j].silent) OR (driver.playchannels[j].first = NIL) THEN
driver.playchannels[j].sample[0]:= CHR(0);
driver.playchannels[j].sample[1]:= CHR(0);
driver.playchannels[j].sample[2]:= CHR(0);
driver.playchannels[j].sample[3]:= CHR(0)
ELSE
driver.allsilent := FALSE;
driver.playchannels[j].sample[0] :=
driver.playchannels[j].first.content.data[driver.playchannels[j].pos];
IF (driver.playchannels[j].samplingResolution=8) &
(driver.playchannels[j].nofSubChannels=1) THEN
eightmono(driver.playchannels[j].sample)
END;
IF (driver.playchannels[j].samplingResolution=16) OR
(driver.playchannels[j].nofSubChannels=2) THEN
driver.playchannels[j].sample[1] :=
driver.playchannels[j].first.content.data[driver.playchannels[j].pos+1];
IF (driver.playchannels[j].samplingResolution=8) THEN
eight(driver.playchannels[j].sample)
END;
IF (driver.playchannels[j].nofSubChannels=1) THEN
mono(driver.playchannels[j].sample)
END;
IF (driver.playchannels[j].samplingResolution=16) &
(driver.playchannels[j].nofSubChannels=2) THEN
driver.playchannels[j].sample[2] :=
driver.playchannels[j].first.content.data[driver.playchannels[j].pos+2];
driver.playchannels[j].sample[3] :=
driver.playchannels[j].first.content.data[driver.playchannels[j].pos+3]
END
END
END
END Readnextsample;
BEGIN {EXCLUSIVE}
driver.bufferobj.Setinplaycopy(TRUE);
FOR j := 0 TO 31 DO
IF driver.playchannels[j].active THEN
driver.playchannels[j].silent := FALSE;
i := from;
WHILE (i <= to) DO
driver.playchannels[j].ratedone :=
driver.playchannels[j].ratedone + driver.playchannels[j].samplingRate;
nr := driver.playchannels[j].ratedone MOD 48000;
IF (nr # driver.playchannels[j].ratedone) THEN
IF (driver.playchannels[j].active) THEN
Readnextsample
ELSE
driver.playchannels[j].oldsample[0] := CHR(0);
driver.playchannels[j].oldsample[1] := CHR(0);
driver.playchannels[j].oldsample[2] := CHR(0);
driver.playchannels[j].oldsample[3] := CHR(0)
END
END;
IF first THEN
FOR l := 0 TO 1 DO
signed := SYSTEM.VAL(INTEGER, driver.playchannels[j].sample[2*l]);
lsigned := LONG(signed);
signed := SYSTEM.VAL(INTEGER, driver.playchannels[j].oldsample[2*l]);
lsigned := ENTIER((1-driver.playchannels[j].ratedone/48000)*
LONG(signed)+(driver.playchannels[j].ratedone/48000)*lsigned+0.5);
lsigned := lsigned*(driver.playchannels[j].vol) DIV 256 ;
Clip(lsigned);
signed := SHORT(lsigned);
driver.p2[i+2*l] := CHR(signed MOD 256);
driver.p2[i+2*l+1] := CHR(signed DIV 256)
END
ELSE
FOR l := 0 TO 1 DO
signed := SYSTEM.VAL(INTEGER, driver.playchannels[j].sample[2*l]);
lsigned := LONG(signed);
signed := SYSTEM.VAL(INTEGER, driver.playchannels[j].oldsample[2*l]);
lsigned := ENTIER((1-driver.playchannels[j].ratedone/48000)*
LONG(signed)+(driver.playchannels[j].ratedone/48000)*lsigned+0.5);
lsigned := lsigned*(driver.playchannels[j].vol) DIV 256 ;
signed := SYSTEM.VAL(INTEGER, driver.p2[i+2*l]);
lsigned := LONG(signed) + lsigned;
Clip(lsigned);
signed := SHORT(lsigned);
driver.p2[i+2*l] := CHR(signed MOD 256);
driver.p2[i+1+2*l] := CHR(signed DIV 256)
END
END;
INC(i, 4)
END;
first := FALSE
END
END;
IF ~driver.allsilent THEN
IF ~ (5 IN SYSTEM.VAL(SET, driver.EsState.rctrl)) THEN
IF Trace THEN KernelLog.String("Enabling DAC2 Interrupt"); KernelLog.Ln END;
Machine.Portout8(driver.base+Es1370RegMemPage, 0CX);
Machine.Portout32(driver.base+3CH, SYSTEM.VAL(LONGINT, Bsize DIV 4-1));
driver.EsState.rctrl := SYSTEM.VAL(LONGINT, {5}+SYSTEM.VAL(SET, driver.EsState.rctrl));
Machine.Portout32(driver.base+Es1370RegControl, driver.EsState.rctrl);
END;
ELSE
IF (5 IN SYSTEM.VAL(SET, driver.EsState.rctrl)) THEN
temp := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, driver.EsState.rctrl)-{5});
Machine.Portout32(driver.base+Es1370RegControl, temp);
FOR i := 0 TO Bsize-1 DO driver.p2[i] := CHR(0) END;
driver.EsState.rctrl := temp
END
END;
driver.bufferobj.Setinplaycopy(FALSE)
END Playcopy;
PROCEDURE Reccopy(from, to: LONGINT);
VAR sample : Sample;
signed : INTEGER;
lsigned, i, j, l : LONGINT;
nr : LONGINT;
BEGIN {EXCLUSIVE}
FOR j := 0 TO 31 DO
IF driver.recordchannels[j].active THEN
driver.recordchannels[j].rsilent := FALSE;
i := from;
WHILE (i <= to) & (driver.recordchannels[j].active) DO
IF driver.recordchannels[j].pos >= driver.recordchannels[j].first.content.len THEN
driver.recordchannels[j].pos := 0;
driver.AddBufferToReturn(driver.recordchannels[j].blistener,
driver.recordchannels[j].first.content);
driver.recordchannels[j].NextBuffer;
END;
driver.recordchannels[j].ratedone :=
driver.recordchannels[j].ratedone + driver.recordchannels[j].samplingRate;
nr := driver.recordchannels[j].ratedone MOD 48000;
IF nr # driver.recordchannels[j].ratedone THEN
driver.recordchannels[j].ratedone := nr;
IF ~driver.recordchannels[j].rsilent THEN
driver.rallsilent := FALSE;
sample[0] := driver.pr2[i];
sample[1] := driver.pr2[i+1];
sample[2] := driver.pr2[i+2];
sample[3] := driver.pr2[i+3];
FOR l := 0 TO 1 DO
signed := SYSTEM.VAL(INTEGER, sample[2*l]);
lsigned := LONG(signed);
lsigned := lsigned*(driver.recordchannels[j].vol) DIV 256;
Clip(lsigned);
signed := SHORT(lsigned);
sample[2*l] := CHR(signed MOD 256);
sample[2*l+1] := CHR(signed DIV 256)
END;
IF driver.recordchannels[j].samplingResolution=8 THEN
IF driver.recordchannels[j].nofSubChannels=1 THEN
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos]
:= CHR( (ORD(sample[1])-128 + ORD(sample[3])-128) DIV 2)
ELSE
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos]
:= CHR(ORD(sample[1])-128);
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos+1]
:= CHR(ORD(sample[3])-128)
END
ELSE
IF driver.recordchannels[j].nofSubChannels=1 THEN
lsigned := SYSTEM.VAL(INTEGER, sample[0]);
lsigned := lsigned+SYSTEM.VAL(INTEGER, sample[2]);
signed := SHORT(lsigned DIV 2);
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos]
:= CHR(signed MOD 256);
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos+1]
:= CHR(signed DIV 256)
ELSE
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos]
:= sample[0];
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos+1]
:= sample[1];
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos+2]
:= sample[2];
driver.recordchannels[j].first.content.data[driver.recordchannels[j].pos+3]
:= sample[3]
END
END
END;
driver.recordchannels[j].pos:= driver.recordchannels[j].pos+driver.recordchannels[j].delta
END;
INC(i, 4)
END
END
END;
IF ~driver.rallsilent THEN
IF ~ (4 IN SYSTEM.VAL(SET, driver.EsState.rctrl)) THEN
Machine.Portout8(driver.base+Es1370RegMemPage, 0DX);
Machine.Portout32(driver.base+34H, SYSTEM.VAL(LONGINT, Bsize DIV 4-1));
driver.EsState.rctrl := SYSTEM.VAL(LONGINT, {4}+SYSTEM.VAL(SET, driver.EsState.rctrl));
Machine.Portout32(driver.base+Es1370RegControl, driver.EsState.rctrl)
END
ELSE
IF (4 IN SYSTEM.VAL(SET, driver.EsState.rctrl)) THEN
driver.EsState.rctrl := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, driver.EsState.rctrl)-{4});
Machine.Portout32(driver.base+Es1370RegControl, driver.EsState.rctrl);
FOR i := 0 TO Bsize-1 DO driver.pr2[i] := CHR(0) END
END
END
END Reccopy;
BEGIN
driver.allsilent := TRUE; first := TRUE;
driver.rallsilent := TRUE;
IF driver.reccopy=TRUE THEN
IF driver.rloopcount MOD 2 = 0 THEN
Reccopy(0, Bsize DIV 2 -1)
ELSE
Reccopy(Bsize DIV 2, Bsize -1)
END;
driver.reccopy := FALSE
END;
IF driver.playcopy = TRUE THEN
Setplaycopy(FALSE);
IF driver.loopcount MOD 2 = 0 THEN
Playcopy(0, Bsize DIV 2 -1)
ELSE
Playcopy(Bsize DIV 2, Bsize -1)
END
END
END Copy;
BEGIN {ACTIVE}
driver.playcopy := FALSE;
driver.reccopy := FALSE;
REPEAT (* wait for user/interrupt setting playcopy/reccopy as long as driver is loaded *)
Wait;
Copy
UNTIL 1=2
END Introbj;
VAR installedDrivers: Driver;
installed: LONGINT;
PROCEDURE DefaultBufferListener(buffer: SoundDevices.Buffer);
END DefaultBufferListener;
PROCEDURE Cleanup;
BEGIN
WHILE installedDrivers # NIL DO
installedDrivers.Finalize;
installedDrivers := installedDrivers.next
END;
installed := 0;
END Cleanup;
PROCEDURE ScanPCI(vendor, device: LONGINT; name: Plugins.Name);
VAR index, bus, dev, fct, res, base, irq, i : LONGINT;
driver : Driver;
drivername : Plugins.Name;
BEGIN
driver := NIL;
index := 0;
WHILE (PCI.FindPCIDevice(device, vendor, index, bus, dev, fct) = PCI.Done) & (installed < 10) DO
IF Trace THEN
KernelLog.String("Bus "); KernelLog.Int(bus, 1);
KernelLog.String(", device: "); KernelLog.Int(dev, 1);
KernelLog.String(", function: "); KernelLog.Int(fct, 1);
KernelLog.String(", vendor/device "); KernelLog.Hex(ASH(vendor, 16) + device, 0); KernelLog.Ln;
END;
res := PCI.ReadConfigDword(bus, dev, fct, PCI.Adr0Reg, base);
ASSERT(res=PCI.Done);
ASSERT(ODD(base));
DEC(base, base MOD 4);
IF Trace THEN KernelLog.String("Base address: "); KernelLog.Hex(base, 0); KernelLog.Ln END;
res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq);
ASSERT(res=PCI.Done);
IF Trace THEN KernelLog.String("IRQ"); KernelLog.Int(irq, 1); KernelLog.Ln END;
NEW(driver, irq, base);
KernelLog.String("Ensoniq sound driver installed."); KernelLog.Ln;
i := 0;
WHILE name[i] # 0X DO drivername[i] := name[i]; INC(i) END;
drivername[i] := "#";
drivername[i + 1] := CHR(ORD("0") + installed);
drivername[i + 2] := 0X;
driver.SetName(drivername);
SoundDevices.devices.Add(driver, res);
ASSERT(res=0);
INC(index)
END
END ScanPCI;
PROCEDURE Install*;
END Install;
PROCEDURE Init;
BEGIN
IF installedDrivers = NIL THEN
ScanPCI(1274H, 1371H, "ES1371");
ScanPCI(1274H, 1373H, "ES1373");
ScanPCI(1274H, 5880H, "5880 AudioPCI")
END;
END Init;
BEGIN {EXCLUSIVE}
Modules.InstallTermHandler(Cleanup);
installedDrivers := NIL;
installed := 0;
Init;
END EnsoniqSound.
EnsoniqSound.Install ~
SystemTools.Free EnsoniqSound ~
Installation
Add EnsoniqSound.Install to Configuration.XML, section 'Autostart' to load driver at system startup.