272 lines
6.3 KiB
C
272 lines
6.3 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
isr.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code for the interrupt service routine
|
||
for the SoundBlaster device driver.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
--*/
|
||
|
||
#include "sound.h"
|
||
|
||
//
|
||
// Driver ISR
|
||
//
|
||
// When we get here, we acknowledge the interrupt from the
|
||
// DSP and simply let the defered processing routine take over
|
||
// to complete the task.
|
||
//
|
||
// NOTE: If we were to be doing MIDI input, we would read the
|
||
// data port to extract the received character and save it.
|
||
//
|
||
// That was NigelT's note - currently MIDI input reads the
|
||
// byte in the Dpc routine - hasn't failed yet - RCBS
|
||
//
|
||
|
||
#if DBG
|
||
ULONG sndBogusInterrupts = 0;
|
||
#endif // DBG
|
||
|
||
//
|
||
// Internal routine
|
||
//
|
||
|
||
VOID
|
||
SoundReProgramDMA(
|
||
IN OUT PWAVE_INFO WaveInfo
|
||
)
|
||
;
|
||
|
||
BOOLEAN
|
||
SoundISR(
|
||
IN PKINTERRUPT pInterrupt,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Interrupt service routine for the soundblaster card.
|
||
|
||
Arguments:
|
||
|
||
pInterrupt - our interrupt
|
||
Contest - Pointer to our global device info
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE if we handled the interrupt
|
||
|
||
--*/
|
||
{
|
||
PGLOBAL_DEVICE_INFO pGDI;
|
||
BOOLEAN Result;
|
||
PSOUND_HARDWARE pHw;
|
||
|
||
pGDI = (PGLOBAL_DEVICE_INFO)Context;
|
||
ASSERT(pGDI->Key == GDI_KEY);
|
||
|
||
pHw = &pGDI->Hw;
|
||
|
||
dprintf5(("<"));
|
||
|
||
//
|
||
// Acknowledge the interrupt from the DSP
|
||
//
|
||
|
||
if (SB16(pHw)) {
|
||
UCHAR Source;
|
||
|
||
Result = FALSE;
|
||
|
||
//
|
||
// Determine interrupt source
|
||
//
|
||
|
||
OUTPORT(pHw, MIX_ADDR_PORT, MIX_INTERRUPT_SOURCE_REG);
|
||
Source = INPORT(pHw, MIX_DATA_PORT);
|
||
|
||
//
|
||
// See if it's for MPU401
|
||
//
|
||
|
||
if ((Source & 0x04) && MPU401(pHw)) {
|
||
int i;
|
||
|
||
//
|
||
// MPU401!
|
||
//
|
||
|
||
//
|
||
// Read data (at least 1 byte) in the isr otherwise the
|
||
// interrupt isn't cleared
|
||
//
|
||
|
||
for (i = 0; i < sizeof(pHw->MPU401.MidiData) - 1; i++) {
|
||
UCHAR MidiByte;
|
||
int WritePosition;
|
||
int NextWritePosition;
|
||
|
||
if (READ_PORT_UCHAR(pHw->MPU401.PortBase + MPU401_REG_STATUS) &
|
||
MPU401_DSR) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Read the data
|
||
//
|
||
|
||
MidiByte = READ_PORT_UCHAR(pHw->MPU401.PortBase + MPU401_REG_DATA);
|
||
|
||
//
|
||
// Save the bytes (note we could do this only if InputActive
|
||
// if set - this would mean making InputActive volatile
|
||
// to make the initialization stuff to work and also having
|
||
// a flag to prevent us queueing the Dpc during
|
||
// initialization.
|
||
//
|
||
|
||
WritePosition = pHw->MPU401.WritePosition;
|
||
NextWritePosition = WritePosition + 1;
|
||
if (NextWritePosition == sizeof(pHw->MPU401.MidiData)) {
|
||
NextWritePosition = 0;
|
||
}
|
||
|
||
//
|
||
// Always leave 1 empty slot to simplify things
|
||
// (ie so we don't confuse full with empty)
|
||
//
|
||
if (NextWritePosition != pHw->MPU401.ReadPosition) {
|
||
pHw->MPU401.MidiData[WritePosition] = MidiByte;
|
||
pHw->MPU401.WritePosition = NextWritePosition;
|
||
} else {
|
||
if (pHw->MPU401.InputActive) {
|
||
dprintf1(("MPU401 Midi input overflowed!"));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (pHw->MPU401.InputActive) {
|
||
//
|
||
// Fire off the DPC - this will take care of
|
||
// copying the data to the IRPs and completing
|
||
// them.
|
||
//
|
||
IoRequestDpc(pGDI->DeviceObject[MidiInDevice],
|
||
NULL,
|
||
NULL);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
if (!(Source & 0x03)) {
|
||
return Result;
|
||
}
|
||
|
||
if (Source & 0x01) {
|
||
INPORT(pHw, DATA_AVAIL_PORT);
|
||
}
|
||
|
||
if (Source & 0x02) {
|
||
INPORT(pHw, DMA_16_ACK_PORT);
|
||
}
|
||
} else {
|
||
INPORT(pHw, DATA_AVAIL_PORT);
|
||
}
|
||
|
||
//
|
||
// See who the interrupt is for and request the
|
||
// appropriate deferred routine
|
||
//
|
||
|
||
Result = TRUE;
|
||
switch (pGDI->Usage) {
|
||
case WaveInDevice:
|
||
case WaveOutDevice:
|
||
//
|
||
// It is valid to test DMABusy because it is set ON before we start
|
||
// interrupts
|
||
|
||
if (pGDI->WaveInfo.DMABusy) {
|
||
dprintf5((pGDI->WaveInfo.Direction ? "o" : "i"));
|
||
|
||
//
|
||
// Check to see if we're overrunning, don't queue a Dpc if
|
||
// we are.
|
||
//
|
||
|
||
if (!pGDI->WaveInfo.DpcQueued) {
|
||
|
||
pGDI->WaveInfo.DpcQueued = TRUE;
|
||
|
||
// ASSERTMSG("Overrun count not zeroed by Dpc routine",
|
||
// pGDI->WaveInfo.Overrun == 0);
|
||
|
||
IoRequestDpc(pGDI->WaveInfo.DeviceObject,
|
||
NULL,
|
||
NULL);
|
||
|
||
} else {
|
||
//
|
||
// Overrun !
|
||
//
|
||
if (pGDI->WaveInfo.Overrun == 0) {
|
||
dprintf2(("Wave overrun"));
|
||
}
|
||
pGDI->WaveInfo.Overrun++;
|
||
}
|
||
|
||
}
|
||
break;
|
||
|
||
case MidiInDevice:
|
||
// get all MIDI input chars available and save them for the DPC
|
||
// start the midi in dpc
|
||
IoRequestDpc(pGDI->DeviceObject[MidiInDevice],
|
||
NULL,
|
||
NULL);
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// Set interrupts in case of autodetect.
|
||
//
|
||
pGDI->InterruptsReceived++;
|
||
#if DBG
|
||
// We only get 10 valid interrupts when we test the interrupt
|
||
// for validity in init.c. If we get lots more here there
|
||
// may be a problem.
|
||
|
||
sndBogusInterrupts++;
|
||
if ((sndBogusInterrupts % 20) == 0) {
|
||
dprintf(("%u bogus interrupts so far", sndBogusInterrupts - 10));
|
||
}
|
||
#endif // DBG
|
||
|
||
//
|
||
// Set the return value to FALSE to say we didn't
|
||
// handle the interrupt.
|
||
//
|
||
|
||
Result = FALSE;
|
||
|
||
break;
|
||
}
|
||
|
||
dprintf5((">"));
|
||
|
||
return Result;
|
||
}
|