BOOLEAN HwMidiRead( IN PMIDI_INFO MidiInfo, OUT PUCHAR Byte ) /*++ Routine Description : Read a midi byte from the MPU Arguments : MidiInfo - Midi parameters Return Value : BOOL success/falure --*/ { PSOUND_HARDWARE pHw; pHw = MidiInfo->HwContext; if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) { // do we have data waiting (bit 7 clear)? *Byte = INPORT(pHw, MPU_DATA_PORT); return TRUE; } else { return FALSE; } }
BOOLEAN mpuDumpBufferNoLock( PSOUND_HARDWARE pHw ) /*++ Routine Description: Dumps the contents of the hardware buffer and discard it. Assume the hardware is already locked! Arguments: pHw - pointer to the device extension data Return Value: TRUE if we succeed. --*/ { int Count = 0; int i; // dump the current hardware midi input while(Count < 2048) // we should have no more than this { for(i = 1000; i > 0; i--) { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) { // do we have data waiting (bit 7 clear)? INPORT(pHw, MPU_DATA_PORT); // read and just discard the byte Count++; break; } KeStallExecutionProcessor(1); } // if we waited this long, we don't have anymore data to dump if(i == 0) break; } dprintf1(("Hardware buffer dump byte count %x", (ULONG)Count)); return TRUE; // always }
BOOLEAN mpuWrite( PSOUND_HARDWARE pHw, UCHAR value ) /*++ Routine Description: Write a command or data to the MPU Arguments: pHw - Pointer to the device extension data value - the value to be written Return Value: TRUE if written correctly , FALSE otherwise --*/ { ULONG uCount; ASSERT(pHw->Key == HARDWARE_KEY); uCount = 100; while (uCount--) { int InnerCount; HwEnter(pHw); // // Inner count loop protects against dynamic deadlock with // midi. // for (InnerCount = 0; InnerCount < 10; InnerCount++) { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x40)) { // is it ok to send data (bit 6 clear)? - drude OUTPORT(pHw, MPU_DATA_PORT, value); break; } KeStallExecutionProcessor(1); // 1 us } HwLeave(pHw); if (InnerCount < 10) { return TRUE; } } dprintf1(("mpuWrite:Failed to write %x to mpu", (ULONG)value)); return FALSE; }
BOOLEAN mpuWriteNoLock( PSOUND_HARDWARE pHw, UCHAR value ) /*++ Routine Description: Write a command or data to the MPU. The call assumes the caller has acquired the spin lock Arguments: pHw - Pointer to the device extension data value - the value to be written Return Value: TRUE if written correctly , FALSE otherwise --*/ { int uCount; ASSERT(pHw->Key == HARDWARE_KEY); uCount = 1000; while (uCount--) { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x40)) { // is it ok to send data (bit 6 clear)? - drude OUTPORT(pHw, MPU_DATA_PORT, value); break; } KeStallExecutionProcessor(1); // 1 us } if (uCount >= 0) { return TRUE; } dprintf1(("mpuWriteNoLock:Failed to write %x to mpu", (ULONG)value)); return FALSE; }
int vixConfigPlayback(vidix_playback_t *info) { int src_w, drw_w; int src_h, drw_h; int hscale,vscale; long base0; int y_pitch = 0, uv_pitch = 0; int protect=0; int layout=0; unsigned int i; if(!is_supported_fourcc(info->fourcc)) return -1; src_w = info->src.w; src_h = info->src.h; drw_w = info->dest.w; drw_h = info->dest.h; switch(info->fourcc) { case IMGFMT_YUY2: case IMGFMT_BGR16: y_pitch = (src_w*2 + 15) & ~15; uv_pitch = 0; YOffs=VOffs=UOffs=info->offset.y = info->offset.v = info->offset.u = 0; info->frame_size = y_pitch*src_h; layout=0x0; /* packed */ break; case IMGFMT_YV12: case IMGFMT_I420: y_pitch = (src_w+15) & ~15; uv_pitch = ((src_w/2)+7) & ~7; YOffs=info->offset.y = 0; VOffs=info->offset.v = y_pitch*src_h; UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/2); info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/2); layout=0x1; /* planar, 4:1:1 */ break; case IMGFMT_YVU9: y_pitch = (src_w+15) & ~15; uv_pitch = ((src_w/4)+3) & ~3; YOffs=info->offset.y = 0; VOffs=info->offset.v = y_pitch*src_h; UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/4); info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/4); layout=0x51; /* planar, 16:1:1 */ break; } /* Assume we have 2 MB to play with */ info->num_frames = 0x200000 / info->frame_size; if(info->num_frames > VID_PLAY_MAXFRAMES) info->num_frames = VID_PLAY_MAXFRAMES; /* Start at 6 MB. Let's hope it's not in use. */ base0 = 0x600000; info->dga_addr = cyberblade_mem + base0; info->dest.pitch.y = 16; info->dest.pitch.u = 16; info->dest.pitch.v = 16; for(i = 0; i < info->num_frames; i++) { info->offsets[i] = info->frame_size * i; frames[i] = base0+info->offsets[i]; } OUTPORT8(0x3d4,0x39); OUTPORT8(0x3d5,INPORT(0x3d5)|1); SRINB(0x0b); /* Select new mode */ /* Unprotect hardware registers... */ protect=SRINB(0x11); SROUTB(0x11, 0x92); SROUTB(0x57, 0xc0); /* Playback key function */ SROUTB(0x21, 0x34); /* Signature control */ SROUTB(0x37, 0x30); /* Video key mode */ vixSetGrKeys(&cyberblade_grkey); /* compute_scale_factor(&src_w, &drw_w, &shrink, &zoom); */ { int HTotal,VTotal,HSync,VSync,Overflow,HDisp,VDisp; int HWinStart,VWinStart; int tx1,ty1,tx2,ty2; HTotal=CRINB(0x00); HSync=CRINB(0x04); VTotal=CRINB(0x06); VSync=CRINB(0x10); Overflow=CRINB(0x07); HTotal <<=3; HSync <<=3; VTotal |= (Overflow & 1) <<8; VTotal |= (Overflow & 0x20) <<4; VTotal +=4; VSync |= (Overflow & 4) <<6; VSync |= (Overflow & 0x80) <<2; if(CRINB(0xd1)&0x80) { int TVHTotal,TVVTotal,TVHSyncStart,TVVSyncStart,TVOverflow; LOGWRITE("[cyberblade] Using TV-CRTC\n"); HDisp=(1+CRINB(0x01))*8; VDisp=1+CRINB(0x12); Overflow=CRINB(0x07); VDisp |= (Overflow & 2) <<7; VDisp |= (Overflow & 0x40) << 3; TVHTotal=CRINB(0xe0)*8; TVVTotal=CRINB(0xe6); TVOverflow=CRINB(0xe7); if(TVOverflow&0x20) TVVTotal|=512; if(TVOverflow&0x01) TVVTotal|=256; TVHTotal+=40; TVVTotal+=2; TVHSyncStart=CRINB(0xe4)*8; TVVSyncStart=CRINB(0xf0); if(TVOverflow&0x80) TVVSyncStart|=512; if(TVOverflow&0x04) TVVSyncStart|=256; HWinStart=(TVHTotal-HDisp)&15; HWinStart|=(HTotal-HDisp)&15; HWinStart+=(TVHTotal-TVHSyncStart)-49; } else { LOGWRITE("[cyberblade] Using Standard CRTC\n"); HWinStart=(HTotal-HSync)+15; } VWinStart=(VTotal-VSync)-8; printf("[cyberblade] HTotal: 0x%x, HSStart: 0x%x\n",HTotal,HSync); printf(" VTotal: 0x%x, VStart: 0x%x\n",VTotal,VSync); tx1=HWinStart+info->dest.x; ty1=VWinStart+info->dest.y; tx2=tx1+info->dest.w; ty2=ty1+info->dest.h; CROUTW(0x86,tx1); CROUTW(0x88,ty1); CROUTW(0x8a,tx2); CROUTW(0x8c,ty2+3); } if(src_w==drw_w) hscale=0; else if(src_w<drw_w) { hscale=((src_w<<10)/(drw_w-2)) & 0x1fff; } else { hscale=0x8000 | ((((src_w/drw_w)-1)&7)<<10) | (((drw_w<<10)/src_w) & 0x3ff); } vscale=(src_h<<10)/(drw_h); if(drw_h<src_h) vscale=0x8000|((drw_h<<10)/(src_h)); /* Write scale factors to hardware */ CROUTW(0x80,hscale); /* Horizontal Scale */ CROUTW(0x82,vscale); /* Vertical Scale */ /* Now set the start address and data layout */ { int lb = (y_pitch+2) >> 2; CROUTB(0x95, ((lb & 0x100)>>1) | 0x08 ); /* Linebuffer level bit 8 & threshold */ CROUTB(0x96, (lb & 0xFF)); /* Linebuffer level */ CROUTB(0x97, 0x00); /* VDE Flags */ CROUTB(0xBA, 0x00); /* Chroma key */ CROUTB(0xBB, 0x00); /* Chroma key */ CROUTB(0xBC, 0xFF); /* Chroma key */ CROUTB(0xBD, 0xFF); /* Chroma key */ CROUTB(0xBE, 0x04); /* Capture control */ if(src_w > 384) layout|=4; /* 2x line buffers */ SROUTB(0x97, layout); CROUTW(0x90,y_pitch); /* Y Bytes per row */ SROUTW(0x9A,uv_pitch); /* UV Bytes per row */ switch(info->fourcc) { case IMGFMT_BGR16: CROUTB(0x8F, 0x24); /* VDE Flags - Edge Recovery & CSC Bypass */ CROUTB(0xBF, 0x02); /* Video format - RGB16 */ SROUTB(0xBE, 0x0); /* HSCB disabled */ break; default: CROUTB(0x8F, 0x20); /* VDE Flags - Edge Recovery */ CROUTB(0xBF, 0x00); /* Video format - YUV */ SROUTB(0xBE, 0x00); /* HSCB disable - was 0x03*/ break; } CROUTB(0x92, ((base0+info->offset.y) >> 3) &0xff); /* Lower 8 bits of start address */ CROUTB(0x93, ((base0+info->offset.y) >> 11) &0xff); /* Mid 8 bits of start address */ CROUTB(0x94, ((base0+info->offset.y) >> 19) &0xf); /* Upper 4 bits of start address */ SROUTB(0x80, ((base0+info->offset.v) >> 3) &0xff); /* Lower 8 bits of start address */ SROUTB(0x81, ((base0+info->offset.v) >> 11) &0xff); /* Mid 8 bits of start address */ SROUTB(0x82, ((base0+info->offset.v) >> 19) &0xf); /* Upper 4 bits of start address */ SROUTB(0x83, ((base0+info->offset.u) >> 3) &0xff); /* Lower 8 bits of start address */ SROUTB(0x84, ((base0+info->offset.u) >> 11) &0xff); /* Mid 8 bits of start address */ SROUTB(0x85, ((base0+info->offset.u) >> 19) &0xf); /* Upper 4 bits of start address */ } vixPlaybackSetEq(&equal); /* Protect hardware registers again */ SROUTB(0x11, protect); return 0; }
/*========================================================= Name: pwm_wave_gen Description: This thread outputs the PWM duty cycle through the GPIO to generate square wave. *=========================================================*/ void pwm_wave_gen(unsigned int pwm_period) { unsigned int i = 0; /* Configure GPIO18 as PWM1 output (ALT 5) to generate square wave */ INPORT(18u); PORT_CONFIG(18u, 2u); /* Configure PWM clock */ /* Stop the PWM first before changing the clock */ PWM_CTL1 = 0x00u; usleep(10u); /* Stop the PWM clock; ENAB=0 */ PWM_CLK_CTL = 0x5A000001u; usleep(110u); /* Wait till busy flag is cleared */ while ((PWM_CLK_CTL & 0x80u) != 0u); /* Set the clock divider */ PWM_CLK_DIV = (0x5A000000u) | (1u << 12u); usleep(10u); /* Wait till busy flag is cleared */ while ((PWM_CLK_CTL & 0x80u) != 0u); usleep(10u); /* Start the clock; ENAB=1 */ PWM_CLK_CTL = 0x5A000011u; usleep(10u); /* Example: PWM Base Clock Frequency = 19.2 MHz, Clock Divider = 32, Range = 1024. Hence PWM clock = 19.2MHz/32 = 600kHz or 1.7us; PWM period: 600kHz/1024 = 585.9375Hz or 1.7ms PWM duty cycle = (DATA/1024) * 585.9375Hz Duty cycle 50% = 512/1024 * 585.9375Hz = 292.96875Hz or 0.85ms ON/OFF */ /* Configure PWM1, Enable, PWM mode, Polarity:0, Data register used Mark:Space used */ PWM_CTL1 = 0x81u; usleep(10u); /* Set period of the PWM output */ PWM_RNG1 = pwm_period; /* 75Hz; 1024 = 10 bit resolution */ usleep(10u); for (i = 0; i < 3; i++) { /* Check PWM is transmitting */ if ((PWM_STA1 & 0x200u) == 0x200u) { /* Set duty cycle */ PWM_DAT1 = PWM_RNG1/2; } /* Generate the PWM pulse for 240ms */ usleep(240000); /* Inter frame signal for 2 seconds */ PWM_DAT1 = 0u; sleep(2); } /* Stop the PWM; ENAB=0 */ PWM_CTL1 = 0x80u; usleep(10u); /* Tri state output port */ INPORT(18u); }
NTSTATUS SoundCardInstanceInit( IN PWSTR RegistryPathName, IN PVOID Context ) { /* ** Instance data */ PSOUND_CARD_INSTANCE CardInstance; // // Return code from last function called // NTSTATUS Status; // // Configuration data : // SB_CONFIG_DATA ConfigData; // // Where we keep all general driver information // We avoid using static data because : // 1. Accesses are slower with 32-bit offsets // 2. We support more than one card instance // PGLOBAL_DEVICE_INFO pGDI; // // The number of devices we actually create // int NumberOfDevicesCreated; // // The context is the global device info pointer from the previous // instance // CardInstance = Context; /******************************************************************** * * Allocate our global info * ********************************************************************/ pGDI = (PGLOBAL_DEVICE_INFO)ExAllocatePool( NonPagedPool, sizeof(GLOBAL_DEVICE_INFO)); if (pGDI == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } dprintf4((" DriverEntry(): GlobalInfo : %08lXH", pGDI)); RtlZeroMemory(pGDI, sizeof(GLOBAL_DEVICE_INFO)); pGDI->Key = GDI_KEY; pGDI->Hw.Key = HARDWARE_KEY; pGDI->RegistryPathName = RegistryPathName; pGDI->Usage = 0xFF; // Free pGDI->DriverObject = CardInstance->pDriverObject; // // Mutual exclusion : // // Everything is synchronized on the DeviceMutex (except for // some stuff inside the wave device) except // // Midi external output which takes too long and so is synchronized // separately but grabs the DeviceMutex every time it actually // writes anything and // // Synth output where the hardware is separate but callbacks to the // mixer must grab the DeviceMutex. // KeInitializeMutex(&pGDI->DeviceMutex, 2 // High level ); KeInitializeMutex(&pGDI->MidiMutex, 1 // Low level ); KeInitializeMutex(&pGDI->Hw.DSPMutex, 3 // Highest level ); /******************************************************************** * * Add ourselves to the ring of cards * ********************************************************************/ if (CardInstance->PrevGDI == NULL) { pGDI->Next = pGDI; } else { PGLOBAL_DEVICE_INFO pNext; pNext = CardInstance->PrevGDI->Next; CardInstance->PrevGDI->Next = pGDI; pGDI->Next = pNext; } CardInstance->PrevGDI = pGDI; /******************************************************************** * * See if we can find our bus. We run on both ISA and EISA * We ASSUME that if there's an ISA bus we're on that * ********************************************************************/ Status = SoundGetBusNumber(Isa, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { // // Cound not find an ISA bus so try EISA // Status = SoundGetBusNumber(Eisa, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { Status = SoundGetBusNumber(MicroChannel, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { dprintf1(("driver does not work on non-Isa/Eisa/Mca")); return Status; } pGDI->BusType = MicroChannel; } else { pGDI->BusType = Eisa; } } else { pGDI->BusType = Isa; } // // Set configuration to default in case we don't get all the // values back from the registry. // // Also set default volume for all devices // ConfigData.Port = SOUND_DEF_PORT; ConfigData.InterruptNumber = SOUND_DEF_INT; ConfigData.DmaChannel = SOUND_DEF_DMACHANNEL; ConfigData.DmaChannel16 = SOUND_DEF_DMACHANNEL16; ConfigData.DmaBufferSize = DEFAULT_DMA_BUFFERSIZE; ConfigData.MPU401Port = SOUND_DEF_MPU401_PORT; ConfigData.LoadType = SOUND_LOADTYPE_NORMAL; ConfigData.MixerSettingsFound = FALSE; // // Get the system configuration information for this driver. // // // Port, Interrupt, DMA channel, DMA 16-bit channel DMA buffer size // { RTL_QUERY_REGISTRY_TABLE Table[2]; RtlZeroMemory(Table, sizeof(Table)); Table[0].QueryRoutine = SoundReadConfiguration; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, pGDI->RegistryPathName, Table, &ConfigData, NULL ); if (!NT_SUCCESS(Status)) { dprintf1(("ERROR: DriverEntry(): RtlQueryRegistryValues() Failed with Status = %XH", Status)); return Status; } // End IF (!NT_SUCCESS(Status)) } // End Query Resistry Values // // Save additional Config data // pGDI->InterruptNumber = ConfigData.InterruptNumber; pGDI->DmaChannel = ConfigData.DmaChannel; pGDI->DmaChannel16 = ConfigData.DmaChannel16; // // Verify the DMA Buffer Size // if ( ConfigData.DmaBufferSize < MIN_DMA_BUFFERSIZE ) { ConfigData.DmaBufferSize = MIN_DMA_BUFFERSIZE; dprintf1((" DriverEntry(): Adjusting the DMA Buffer size, size in Registry was too small")); } // // print out some info about the configuration // dprintf2((" DriverEntry(): Base I/O Port = %XH", ConfigData.Port)); dprintf2((" DriverEntry(): Interrupt = %u", ConfigData.InterruptNumber)); dprintf2((" DriverEntry(): DMA Channel = %u", ConfigData.DmaChannel)); dprintf2((" DriverEntry(): DMA Channel (16 bit) = %u", ConfigData.DmaChannel16)); dprintf2((" DriverEntry(): DMA Buffer Size = %XH", ConfigData.DmaBufferSize)); dprintf2((" DriverEntry(): MPU 401 port = %XH", ConfigData.MPU401Port)); /* ** Create our wave devices to ease reporting problems */ Status = SBCreateDevice(pGDI, WaveInDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, WaveOutDevice); if (!NT_SUCCESS(Status)) { return Status; } /* ** Say we want to be called at shutdown time */ Status = IoRegisterShutdownNotification(pGDI->DeviceObject[WaveInDevice]); if (!NT_SUCCESS(Status)) { return Status; } pGDI->ShutdownRegistered = TRUE; /* ** Check the configuration and acquire the resources */ Status = SoundInitHardwareConfig(pGDI, &ConfigData); if (!NT_SUCCESS(Status)) { dprintf1(("ERROR: DriverEntry(): SoundInitHardwareConfig() Failed with Status = %XH", Status)); return Status; } /* ** Initialize generic device environments - first get the ** hardware routines in place. ** We do this here after we've found out what hardware we've got */ HwInitialize(pGDI); SoundInitMidiIn(&pGDI->MidiInfo, &pGDI->Hw); /* ** Register most of our resources. Some may be registered on ** the wave output device : ** 16-bit dma channel ** ** We wipe out the registration of the MPU401 port when we do this ** but this is OK. */ { ULONG PortToReport; PortToReport = ConfigData.Port + MIX_ADDR_PORT; Status = SoundReportResourceUsage( pGDI->DeviceObject[WaveInDevice], // As good as any device to own // it pGDI->BusType, pGDI->BusNumber, &ConfigData.InterruptNumber, INTERRUPT_MODE, (BOOLEAN)(SB16(&pGDI->Hw) ? TRUE : FALSE), // Sharable for SB16 &ConfigData.DmaChannel, &PortToReport, NUMBER_OF_SOUND_PORTS - MIX_ADDR_PORT); } if (!NT_SUCCESS(Status)) { dprintf1(("Error - failed to claim resources - code %8X", Status)); pGDI->LoadStatus = SOUND_CONFIG_ERROR; return Status; } /* ** Now we know what device we've got we can create the appropriate ** devices */ /* ** Thuderboard has no external midi and we're going to ** drive the SB16 in MPU401 mode if we can */ if (!pGDI->Hw.ThunderBoard) { // // Don't create the MPU401 device if it is disabled // if (!SB16(&pGDI->Hw) || (ULONG)-1 != ConfigData.MPU401Port) { Status = SBCreateDevice(pGDI, MidiOutDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, MidiInDevice); if (!NT_SUCCESS(Status)) { return Status; } } } /* ** Create volume control stuff for those devices which have it */ if (SBPRO(&pGDI->Hw) || SB16(&pGDI->Hw) #ifdef SB_CD || pGDI->Hw.SBCDBase != NULL #endif // SB_CD ) { Status = SBCreateDevice(pGDI, LineInDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, CDInternal); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, MixerDevice); if (!NT_SUCCESS(Status)) { return Status; } } else { /* Volume setting not supported for our wave device */ ((PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension)->CreationFlags |= SOUND_CREATION_NO_VOLUME; } /* ** Init the WaveInfo structure */ SoundInitializeWaveInfo(&pGDI->WaveInfo, (UCHAR)(SB1(&pGDI->Hw) ? SoundReprogramOnInterruptDMA : SoundAutoInitDMA), SoundQueryFormat, &pGDI->Hw); if (ConfigData.SynthType == SOUND_SYNTH_TYPE_NONE) { /* ** This will happen if the user selected a basic config without ** a synthesizer. */ dprintf2(("No synth!")); } else { Status = SynthInit(CardInstance->pDriverObject, pGDI->RegistryPathName, &pGDI->Synth, SB16(&pGDI->Hw) || SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0 ? ConfigData.Port : SYNTH_PORT, FALSE, // Interrupt not enabled pGDI->BusType, pGDI->BusNumber, NULL, SOUND_MIXER_INVALID_CONTROL_ID,// Set volume later TRUE, // Allow multiple SoundMidiOutGetSynthCaps ); if (!NT_SUCCESS(Status)) { /* ** OK - we can get along without a synth */ dprintf2(("No synth!")); } else { if (!pGDI->Synth.IsOpl3) { dprintf2(("Synth is Adlib")); } else { /* ** Bad aliasing in early sound blasters means we can ** guess wrong. */ if (!(SB16(&pGDI->Hw) || SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0)) { pGDI->Synth.IsOpl3 = FALSE; } dprintf2(("Synth is Opl3")); } } } /* ** Set the mixer up. ** ** Note that the mixer info depends on what hardware is present ** so this must be called after we have checked out the hardware. */ if (pGDI->DeviceObject[MixerDevice]) { Status = SoundMixerInit(pGDI->DeviceObject[MixerDevice]->DeviceExtension, &ConfigData.MixerSettings, ConfigData.MixerSettingsFound); if (!NT_SUCCESS(Status)) { return Status; } } /* ** Save new settings */ Status = SoundSaveConfig(pGDI->RegistryPathName, ConfigData.Port, ConfigData.DmaChannel, ConfigData.DmaChannel16, ConfigData.InterruptNumber, ConfigData.MPU401Port, (BOOLEAN)(pGDI->Synth.DeviceObject != NULL), pGDI->Synth.IsOpl3, pGDI->WaveInfo.DMABuf.BufferSize); if (!NT_SUCCESS(Status)) { return Status; } /* ** Finally test the PRO interrupt */ if (SBPRO(&pGDI->Hw)) { BOOLEAN Ok; SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension, TRUE); Ok = 0 == SoundTestWaveDevice(pGDI->DeviceObject[WaveOutDevice]); SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension, FALSE); if (!Ok) { pGDI->LoadStatus = SOUND_CONFIG_BADDMA; return STATUS_DEVICE_CONFIGURATION_ERROR; } } /* ** Exit OK Message */ pGDI->LoadStatus = SOUND_CONFIG_OK; return STATUS_SUCCESS; }
BOOLEAN mpuRead( IN PSOUND_HARDWARE pHw, OUT PUCHAR pValue ) /*++ Routine Description: Read the MPU data port Time out occurs after about 1ms Arguments: pHw - Pointer to the device extension data. pValue - Pointer to the UCHAR to receive the result Return Value: Value read --*/ { USHORT uCount; BOOLEAN Status = FALSE; ASSERT(pHw->Key == HARDWARE_KEY); uCount = 100; while (uCount--) { int InnerCount; // // Protect all reads and writes with a spin lock // HwEnter(pHw); // // Inner count loop protects against dynamic deadlock with // midi. // for (InnerCount = 0; InnerCount < 10; InnerCount++) { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) { // do we have data waiting (bit 7 clear)? - drude *pValue = INPORT(pHw, MPU_DATA_PORT); uCount = 0; Status = TRUE; // flag as data read break; } KeStallExecutionProcessor(1); } HwLeave(pHw); } // did we time out if(Status) return TRUE; // data was read else return FALSE; // timed out }
BOOLEAN mpuReset( PSOUND_HARDWARE pHw ) /*++ Routine Description: Reset the MPU to UART mode. Arguments: pHw - pointer to the device extension data Return Value: TRUE if we succeeded, FALSE if we failed. --*/ { // // try for a reset - note that midi output may be running at this // point so we need the spin lock while we're trying to reset // BYTE Ack = 0; int i; HwEnter(pHw); // dump the current hardware midi input buffer // (We might have data availible if the midi devices // connected have sent anything at all.) mpuDumpBufferNoLock(pHw); // reset the card OUTPORT(pHw, MPU_COMMAND_PORT, 0xFF); // set to smart mode first // wait for the acknowledgement - drude // NOTE: When the Ack arrives, it will trigger an interrupt. // Normally the DPC routine would read in the ack byte and we // would never see it, however since we have the hardware locked (HwEnter), // we can read the port before the DPC can and thus we receive the // Ack. for(i = 10000; i > 0; i--) // some times it takes a really long time { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) { // do we have data waiting (bit 7 clear)? Ack = INPORT(pHw, MPU_DATA_PORT); // read the ack byte break; } KeStallExecutionProcessor(25); } // NOTE: We cannot check the ACK byte because if the card was already in // UART mode it will not send an ACK but it will reset. // reset the card again OUTPORT(pHw, MPU_COMMAND_PORT, 0x3F); // set to UART mode // wait for the acknowledgement Ack = 0; for(i = 10000; i > 0; i--) { if (!(INPORT(pHw, MPU_STATUS_PORT) & 0x80)) { // do we have data waiting (bit 7 clear)? Ack = INPORT(pHw, MPU_DATA_PORT); // read the ack byte break; } KeStallExecutionProcessor(25); } HwLeave(pHw); // did we succeed? - drude // (if we did not receive the second ACK, // something is wrong with the hardware.) if(Ack != 0xFE) { dprintf1(("mpuReset:reset hardware failed: %x", (ULONG)Ack)); return FALSE; } else { dprintf1(("mpuReset:reset hardware OK")); return TRUE; } }
NTSTATUS SoundPortValid( IN OUT PGLOBAL_DEVICE_INFO pGDI, IN OUT PULONG Port ) { NTSTATUS Status; // // Check we're going to be allowed to use this port or whether // some other device thinks it owns this hardware // Status = SoundReportResourceUsage( pGDI->DeviceObject[WaveInDevice], // As good as any device to own // it pGDI->BusType, pGDI->BusNumber, NULL, 0, FALSE, NULL, Port, NUMBER_OF_SOUND_PORTS); if (!NT_SUCCESS(Status)) { return Status; } // // Find where our device is mapped // pGDI->Hw.PortBase = SoundMapPortAddress( pGDI->BusType, pGDI->BusNumber, *Port, NUMBER_OF_SOUND_PORTS, &pGDI->MemType); // // Finally we can check and see if the hardware is happy // if (HwIsIoValid(&pGDI->Hw)) { // // Check if it's compaq Business Audio // #if !(_ON_PLANNAR_) if ((INPORT(&pGDI->Hw, BOARD_ID) & 0x3F) != FH_PAL_PRODUCTREV_RQD) { SoundCheckCompaqBA(pGDI, *Port); } #endif return STATUS_SUCCESS; } // // Free any resources. (note we don't have to do // IoReportResourceUsage again because each one overwrites the // previous). // if (pGDI->MemType == 0) { MmUnmapIoSpace(pGDI->Hw.PortBase, NUMBER_OF_SOUND_PORTS); } pGDI->Hw.PortBase = NULL; return STATUS_DEVICE_CONFIGURATION_ERROR; }
NTSTATUS SoundCheckCompaqBA(PGLOBAL_DEVICE_INFO pGDI, ULONG SoundPort) { NTSTATUS Status; ULONG Port; UCHAR CompaqPCR; // // Only 530 and 604 supported // if (SoundPort != 0x530 && SoundPort != 0x604) { return STATUS_DEVICE_CONFIGURATION_ERROR; } Port = 0xC44; // // Go and search at C44 - attach it to the wave in device so it will be // overwritten later since we don't want to keep it // Status = SoundReportResourceUsage( pGDI->DeviceObject[WaveInDevice], pGDI->BusType, pGDI->BusNumber, NULL, 0, FALSE, NULL, &Port, 1); if (!NT_SUCCESS(Status)) { return Status; } // // Find where our device is mapped and map 4 bytes to cover // C44 and C47 // pGDI->Hw.CompaqBA = SoundMapPortAddress( pGDI->BusType, pGDI->BusNumber, Port, 4, &pGDI->MemType); // // Read the peripheral Configuration Register (PCR) // CompaqPCR = READ_PORT_UCHAR(pGDI->Hw.CompaqBA); // // See if the PCR agress with where we think the hardware is // // 0x10 bit says sound enabled // 0x20 bit says it's at 604 (rather than 530) // if (CompaqPCR != 0xFF && ((CompaqPCR & 0x30) == 0x10 && SoundPort == 0x530 || (CompaqPCR & 0x30) == 0x30 && SoundPort == 0x604)) { // // Looks like the base address is really at C44. In // this case we re-report so that we don't prevent others // looking at the PCR since from now on we're only interested // in 0xC47 // Port += BOARD_ID; Status = SoundReportResourceUsage( pGDI->DeviceObject[WaveOutDevice], pGDI->BusType, pGDI->BusNumber, NULL, 0, FALSE, NULL, &Port, 1); } else { // // Unmap - we don't need to unreport because our final declaration // of what we use will overwrite our reporting of C44 // if (pGDI->MemType == 0) { MmUnmapIoSpace(pGDI->Hw.CompaqBA, 4); } pGDI->Hw.CompaqBA = NULL; // // It might be the old Compaq Business Audio 1 // The Red I (early Prolinea/I boxes) did not use the C44 // port but instaed used the actual ports, so lets try again // CompaqPCR = INPORT(&pGDI->Hw, BOARD_CONFIG); if (CompaqPCR == 0xFF) { // // Must be one of the really old machines // We'll test the interrupt and DMA later // pGDI->Hw.CompaqBA = pGDI->Hw.PortBase; pGDI->Hw.NoPCR = TRUE; return STATUS_SUCCESS; } if ((CompaqPCR & 0x30) == 0x10 && SoundPort == 0x530 || (CompaqPCR & 0x30) == 0x30 && SoundPort == 0x604) { pGDI->Hw.CompaqBA = pGDI->Hw.PortBase; Status = STATUS_SUCCESS; } else { Status = STATUS_DEVICE_CONFIGURATION_ERROR; } } return Status; }