/*++ ******************************************************************************* * Copyright (c) 1995 IBM Corporation * * Module Name: cs423x.c * * Abstract: contains device specific routines for the CS4232 Codec * * Author: jim bozek * * Environment: * * Comments: HW_CLAIM() and HW_DISCLAIM() are used to protect access to * both the actual hardware registers, in order to frame atomic * operations from read/write/modify sequences AND to access * the SOUND HARDWARE internal data structure. This is done * during the initialization phase as well as normal operation. * * Rev History: creation 10.03.95 * ******************************************************************************* --*/ #include "common.h" WAVE_INTERFACE_ROUTINE cs423xSetupDMA; WAVE_INTERFACE_ROUTINE cs423xStopDMA; WAVE_INTERFACE_ROUTINE cs423xSetFormat; BOOLEAN cs423xReady(PUCHAR); BOOLEAN cs423xResetMCEAndWait(PUCHAR, ULONG, UCHAR); NTSTATUS cs423xCalibrate(PGLOBAL_DEVICE_INFO); NTSTATUS cs423xDownloadUcode(PGLOBAL_DEVICE_INFO); VOID cs423xSlam(PGLOBAL_DEVICE_INFO); VOID cs423xDisplayRegs(PGLOBAL_DEVICE_INFO); VOID cs423xProgramLogicalDevices(PGLOBAL_DEVICE_INFO); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, cs423xConvertHwtype) #pragma alloc_text(INIT, cs423xConfig) #pragma alloc_text(PAGE, cs423xQueryFormat) #endif /* ********************************************************************************* * This function convertd the input value from a wide string into a CS423X_HWTYPE ********************************************************************************* */ CS423X_HWTYPE cs423xConvertHwtype(PWSTR name) { CS423X_HWTYPE rval; _dbgprint((_PRT_DBUG, "cs423xConvertHwtype(enter)\n")); if (name) { if (_wcsicmp(name, CH_CS4231_HWTYPE) == 0) { rval = hwtype_cs4231; _dbgprint((_PRT_STAT, "HW type: %ls\n", CH_CS4231_HWTYPE)); } else if (_wcsicmp(name , CH_CS4232_HWTYPE) == 0) { rval = hwtype_cs4232; _dbgprint((_PRT_STAT, "HW type: %ls\n", CH_CS4232_HWTYPE)); } else if (_wcsicmp(name, CH_CS4236_HWTYPE) == 0) { rval = hwtype_undefined; _dbgprint((_PRT_STAT, "HW type: %ls\n", CH_CS4236_HWTYPE)); } else if (_wcsicmp(name, SC_CS4231_HWTYPE) == 0) { rval = hwtype_cs4231x; _dbgprint((_PRT_STAT, "Sound Card: %ls\n", SC_CS4231_HWTYPE)); } else if (_wcsicmp(name, SC_CS4232_HWTYPE) == 0) { rval = hwtype_cs4232x; _dbgprint((_PRT_STAT, "Sound Card: %ls\n", SC_CS4232_HWTYPE)); } else if (_wcsicmp(name, SC_CS4236_HWTYPE) == 0) { rval = hwtype_undefined; _dbgprint((_PRT_STAT, "Sound Card: %ls\n", SC_CS4232_HWTYPE)); } else { rval = hwtype_undefined; _dbgprint((_PRT_STAT, "undefined chip type: %ls\n", name)); } } else { rval = hwtype_null; _dbgprint((_PRT_STAT, "NULL chip type\n")); } _dbgprint((_PRT_DBUG, "cs423xConvertHwtype(exit: [rval:0x%08x])\n", rval)); return(rval); } /* ********************************************************************************* * external interface to configure a crystal 423x chip * we expect no more tha one thread in here since this is during driver entry ********************************************************************************* */ NTSTATUS cs423xConfigureHardware(PGLOBAL_DEVICE_INFO pGDI) { NTSTATUS status; UCHAR ucVal; PSOUND_HARDWARE pHW = &pGDI->Hw; PUCHAR base = pHW->WssPortbase; PKMUTEX pKM = &pHW->HwMutex; _dbgprint((_PRT_DBUG, "cs423xConfig(entry)\n")); /* setup callbacks for soundlib wave INPUT functions */ pGDI->WaveInInfo.HwSetupDMA = cs423xSetupDMA; pGDI->WaveInInfo.HwStopDMA = cs423xStopDMA; pGDI->WaveInInfo.HwSetWaveFormat = cs423xSetFormat; /* setup callbacks for soundlib wave OUTPUT functions */ pGDI->WaveOutInfo.HwSetupDMA = cs423xSetupDMA; pGDI->WaveOutInfo.HwStopDMA = cs423xStopDMA; pGDI->WaveOutInfo.HwSetWaveFormat = cs423xSetFormat; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* initialize Hardware Context elements */ pGDI->Hw.PCEnabled = FALSE; pGDI->Hw.PlayFormat = CS423x_BIT_MONO | CS423x_BIT_8BIT; pGDI->Hw.CaptureFormat = CS423x_BIT_MONO | CS423x_BIT_8BIT; pGDI->Hw.SampleRate = CS423x_MAP_5KH; /* ********************************************************************************* * initializing the actual hardware device - * for the preliminary part of the initialization we use the physical HW port- * This part is for 4232 and 4236. 4231 doesn't need to be programmed. ********************************************************************************* */ switch (pGDI->Hw.Type) { case hwtype_cs4232: case hwtype_cs4236: case hwtype_cs4232x: _dbgprint((_PRT_DBUG, "pGDI->HwPort: 0x%08x\n", pGDI->HwPort)); /* map the physical HW port address, acquiring the full 32 bit address */ if (!(pGDI->Hw.PhysPortbase = SoundMapPortAddress(pGDI->BusType, pGDI->BusNumber, pGDI->HwPort, NUMBER_OF_SOUND_PORTS, &pGDI->HwMemType))) { /* release the hardware mutex */ HW_DISCLAIM(pKM); if (pGDI->HwMemType == 0) MmUnmapIoSpace(pGDI->Hw.PhysPortbase, NUMBER_OF_SOUND_PORTS); _dbgprint((_PRT_DBUG, "cs423xConfig(exit:STATUS_INFO_LENGTH_MISMATCH])\n")); return(STATUS_INFO_LENGTH_MISMATCH); } _dbgprint((_PRT_DBUG, "pGDI->Hw.PhysPortbase: 0x%08x\n", pGDI->Hw.PhysPortbase)); /* send the crystal key */ cs423xSlam(pGDI); _dbgprint((_PRT_DBUG, "after slamming the chip\n")); /* program the logical devices */ cs423xProgramLogicalDevices(pGDI); _dbgprint((_PRT_DBUG, "after programming logical devices\n")); /* unmap the physical HW IO port */ if (pGDI->HwMemType == 0) MmUnmapIoSpace(pGDI->Hw.PhysPortbase, NUMBER_OF_SOUND_PORTS); pGDI->Hw.PhysPortbase = (PUCHAR)NULL; /* download micro code - required to support Sound Blaster on current cs423x rev */ status = cs423xDownloadUcode(pGDI); if (!(NT_SUCCESS(status))) { /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "after download: FAILURE [status:0x%08x]\n", status)); return(status); } _dbgprint((_PRT_DBUG, "after downloading ucode\n")); break; default: break; } /* ********************************************************************************* * finish initializing the actual hardware device - * for the rest of the initialization and normal operation use the logical WSS port ********************************************************************************* */ /* set mode 2 - this will be in effect for the life of the driver */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_MODID); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_MODE2); /* calibrate the chip */ status = cs423xCalibrate(pGDI); if (!(NT_SUCCESS(status))) { /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "after calibration: FAILURE [status:0x%08x]\n", status)); return(status); } _dbgprint((_PRT_DBUG, "after calibration: SUCCESS\n")); /* reset (clear) all interrupts */ HW_OUTPORT(base, CS423x_WSS_DMR_STATUS, 0x00); _dbgprint((_PRT_DBUG, "after resetting interrupts\n")); /* enable interrupts */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PIN); ucVal = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucVal | CS423x_BIT_IEN)); _dbgprint((_PRT_DBUG, "after enabling interrupts\n")); /* release the hardware mutex */ HW_DISCLAIM(pKM); (void)cs423xSetOutputMute(pHW, TRUE); _dbgprint((_PRT_DBUG, "after muting output\n")); cs423xSetHPF(pHW, TRUE); _dbgprint((_PRT_DBUG, "after enabling High Pass Filter\n")); cs423xSetMicBoost(pHW, FALSE); _dbgprint((_PRT_DBUG, "after enabling Mic Boost\n")); cs423xSetMuxSelect(pHW, 3); _dbgprint((_PRT_DBUG, "after selecting mux\n")); cs423xSetCaptureFormat(pHW, (CS423x_BIT_MONO | CS423x_BIT_16BIT)); cs423xSetPBFormatSRate(pHW, (CS423x_BIT_MONO | CS423x_BIT_16BIT), CS423x_MAP_11KH); _dbgprint((_PRT_DBUG, "after setting format\n")); (void) cs423xSetOutputMute(pHW, FALSE); _dbgprint((_PRT_DBUG, "after unmuting output\n")); #ifdef CS423X_DEBUG_ON cs423xDisplayRegs(pGDI); #endif _dbgprint((_PRT_DBUG, "cs423xConfig(exit [status:0x%08x])\n", status)); return(status); } /* cs423xConfig */ /* ********************************************************************************* * check if HW is ready with (possible) delay in milliseconds ********************************************************************************* */ #define CS423x_READY_RETRIES 10 BOOLEAN cs423xReady(PUCHAR base) { INT i; UCHAR result; _dbgprint((_PRT_DBUG, "cs423xReady(entry)\n")); /* check for HW ready to respond at parallel interface */ i = CS423x_READY_RETRIES; result = HW_INPORT(base, CS423x_WSS_DMR_INDEX); while ((i-- > 0) && (result & CS423x_BIT_IAR_INIT)) { DELAY_50US; result = HW_INPORT(base, CS423x_WSS_DMR_INDEX); } if (result & CS423x_BIT_IAR_INIT) { _dbgprint((_PRT_DBUG, "cs423xReady(exit:FALSE i: %d)\n", i)); return(FALSE); } _dbgprint((_PRT_DBUG, "cs423xReady(exit:TRUE i: %d)\n", i)); return(TRUE); } /* cs423xReady */ /* ********************************************************************************* * let's do the SLAM - pg 18 CS423x spec * use the HARDWARE port (probably 0x279) ********************************************************************************* */ UCHAR cs423x_key[] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC, 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; VOID cs423xSlam(PGLOBAL_DEVICE_INFO pGDI) { int i; PUCHAR base; _dbgprint((_PRT_DBUG, "cs423xSlam(entry)\n")); /* use the physical HW port - one chip per system */ base = pGDI->Hw.PhysPortbase; _dbgprint((_PRT_DBUG, "physical base: 0x%08x\n", base)); /* undocumented requirement */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_SLEEP); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_SLEEP); /* wait 10 us */ DELAY_10US; /* send the 32 byte SLAM key */ for (i = 0; i < sizeof(cs423x_key); i++) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, cs423x_key[i]); /* wait 1 us */ DELAY_1US; } /* wait 10 us */ DELAY_10US; _dbgprint((_PRT_DBUG, "after slam loop\n")); /* program the chip select number */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_CHIPSEL); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DFLTCS); _dbgprint((_PRT_DBUG, "after programming chip select\n")); _dbgprint((_PRT_DBUG, "cs423xSlam(exit:VOID)\n")); return; } /* cs423xSlam */ /* ********************************************************************************* * program the logical devices * this routine uses the hardware port address (probably 0x279) ********************************************************************************* */ VOID cs423xProgramLogicalDevices(PGLOBAL_DEVICE_INFO pGDI) { PUCHAR base; ULONG low; ULONG high; PKMUTEX pkm; _dbgprint((_PRT_DBUG, "cs423xProgramLogicalDevices(entry)\n")); pkm = &pGDI->Hw.HwMutex; /* use the physical HW port - one chip per system */ base = pGDI->Hw.PhysPortbase; _dbgprint((_PRT_DBUG, "physical base: 0x%08x\n", base)); /* ***************************************************************************** ** logical device 0 - WSS, Synth, Sound Blaster ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCID); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x00); /* WSS Port */ high = (pGDI->WssPort >> 8) & 0xff; low = pGDI->WssPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* Synth Port */ high = (pGDI->SynPort >> 8) & 0xff; low = pGDI->SynPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB1); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* Sound Blaster Port */ high = (pGDI->SBPort >> 8) & 0xff; low = pGDI->SBPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB2); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* WSS/SB IRQ */ low = pGDI->WssIrq & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_INTSEL0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* WSS/SB Playback DMA */ low = pGDI->DmaPlayChannel & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DMASEL0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* WSS/SB Capture DMA */ low = pGDI->DmaCaptureChannel & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DMASEL1); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* activate device or not */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCACT); if (pGDI->WssEnable) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_ENABLE); } else { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DISABLE); } /* ***************************************************************************** ** logical device 1 - Game Port ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCID); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x01); high = (pGDI->GamePort >> 8) & 0xff; low = pGDI->GamePort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* activate device */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCACT); if (pGDI->GameEnable) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_ENABLE); } else { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DISABLE); } /* ***************************************************************************** ** logical device 2 - cs423x Control Port ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCID); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x02); /* port */ high = (pGDI->CtrlPort >> 8) & 0xff; low = pGDI->CtrlPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* no interrupt */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_INTSEL0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x00); /* activate device */ if (pGDI->CtrlEnable) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_ENABLE); } else { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DISABLE); } /* ***************************************************************************** ** logical device 3 - MPU401 ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCID); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x03); /* port */ high = (pGDI->MpuPort >> 8) & 0xff; low = pGDI->MpuPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* interrupt */ low = pGDI->MpuIrq & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_INTSEL0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* activate device */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCACT); if (pGDI->MpuEnable) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_ENABLE); } else { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DISABLE); } /* ***************************************************************************** ** logical device 4 - CDrom ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCID); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, 0x04); /* port */ high = (pGDI->CDRomPort >> 8) & 0xff; low = pGDI->CDRomPort & 0xff; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_PORTB0); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)high); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (UCHAR)low); /* activate device */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DVCACT); if (pGDI->CDRomEnable) { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_ENABLE); } else { HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_DISABLE); } /* ***************************************************************************** ** Activate the Chip ***************************************************************************** */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MISC_CHIPACT); _dbgprint((_PRT_DBUG, "cs423xProgramLogicalDevices(exit:VOID)\n")); return; } /* cs423xProgramLogicalDevices */ /* ********************************************************************************* * cs423xDownloadUcode() - download microcode to the chip * THIS ROUTINE IS DEPENDENT ON THE CONTENTS OF RAM423x.C. IF RAM423x.C CHANGES, * THIS ROUTINE MIGHT ALSO REQUIRE CHANGES. ********************************************************************************* */ UCHAR sbtestcode[] = {0x70, 0xF9, 0x22}; UCHAR resourcecode[]= {0xc2, 0x53, 0x02, 0x12, 0x86}; UCHAR sbpatchcode[] = {0x78, 0x00, 0xf2, 0xc2, 0x53, 0x74, 0x86, 0xc0, 0xe0, 0x74, 0x12, 0xc0, 0xe0, 0x32}; /* external references to ram423x.c */ extern int number_of_regions; extern unsigned char ramcode[]; extern unsigned short ramRegion[][2]; NTSTATUS cs423xDownloadUcode(PGLOBAL_DEVICE_INFO pGDI) { PUCHAR ctrlbase; ULONG ctrlmemtype; PUCHAR sbbase; ULONG sbmemtype; USHORT addr; BOOLEAN sbprepare; UCHAR ucValue; int i; int j; _dbgprint((_PRT_DBUG, "entry cs423xDownloadUcode(pGDI: 0x%08x)\n", pGDI)); /**********************************************************************************/ /* map the HW physical Control Port address, acquiring the full 32 bit address */ if (!(ctrlbase = SoundMapPortAddress(pGDI->BusType, pGDI->BusNumber, pGDI->CtrlPort, NUMBER_OF_CONTROL_PORTS, &ctrlmemtype))) { if (ctrlmemtype == 0) MmUnmapIoSpace(ctrlbase, NUMBER_OF_CONTROL_PORTS); _dbgprint((_PRT_DBUG, "exit cs423xDownloadUcode(STATUS_INFO_LENGTH_MISMATCH)\n")); return(STATUS_INFO_LENGTH_MISMATCH); } /* map the HW physical SoundBlaster Port address, acquiring the full 32 bit address */ if (!(sbbase = SoundMapPortAddress(pGDI->BusType, pGDI->BusNumber, pGDI->SBPort, NUMBER_OF_SB_PORTS, &sbmemtype))) { if (ctrlmemtype == 0) MmUnmapIoSpace(ctrlbase, NUMBER_OF_CONTROL_PORTS); if (sbmemtype == 0) MmUnmapIoSpace(sbbase, NUMBER_OF_SB_PORTS); _dbgprint((_PRT_DBUG, "exit cs423xDownloadUcode(STATUS_INFO_LENGTH_MISMATCH)\n")); return(STATUS_INFO_LENGTH_MISMATCH); } /**********************************************************************************/ /* set up the chip to accept the ucode */ /* download the resource data to the specified address */ HW_OUTPORT(ctrlbase, 0x05, 0xaa); HW_OUTPORT(ctrlbase, 0x05, 0x99); HW_OUTPORT(ctrlbase, 0x05, 0x2a); /* send the resource data */ for (i = 0; i < sizeof(resourcecode); i++) { HW_OUTPORT(ctrlbase, 0x05, resourcecode[i]); } /* terminate download of resource data section */ HW_OUTPORT(ctrlbase, 0x06, 0x00); /* wait 1 ms */ DELAY_1MS; /**********************************************************************************/ /* test if we need to load the prep code */ HW_OUTPORT(ctrlbase, 0x05, 0xaa); HW_OUTPORT(ctrlbase, 0x05, 0x9e); HW_OUTPORT(ctrlbase, 0x05, 0x2a); for (i = 0, sbprepare = FALSE; i < sizeof(sbtestcode); i++) { ucValue = HW_INPORT(ctrlbase, 0x05); if (ucValue != sbtestcode[i]) { sbprepare = TRUE; break; } } /* terminate sequence */ HW_OUTPORT(ctrlbase, 0x06, 0x00); /* wait 1 ms */ DELAY_1MS; /**********************************************************************************/ /* if required, prepare chip for SoundBlaster code reload */ if (sbprepare) { HW_OUTPORT(ctrlbase, 0x05, 0xaa); HW_OUTPORT(ctrlbase, 0x05, 0x36); HW_OUTPORT(ctrlbase, 0x05, 0x28); for (i = 0; i < sizeof(sbpatchcode); i++) { HW_OUTPORT(ctrlbase, 0x05, sbpatchcode[i]); } /* terminate download of data */ HW_OUTPORT(ctrlbase, 0x06, 0x00); DELAY_1MS; /* set SoundBlaster to known state */ HW_OUTPORT(sbbase, 0x0c, 0xff); DELAY_10US; } /**********************************************************************************/ /* download each ucode region */ for (i = 0; i < number_of_regions; ++i) { addr = ramRegion[i][0] + 0x2000; HW_OUTPORT(ctrlbase, 0x05, 0xaa); HW_OUTPORT(ctrlbase, 0x05, (addr & 0xff)); HW_OUTPORT(ctrlbase, 0x05, ((addr >> 8) & 0xff)); for (j = ramRegion[i][0]; j < (ramRegion[i][0] + ramRegion[i][1]); j++) { HW_OUTPORT(ctrlbase, 0x05, ramcode[j]); } /* terminate download of data */ HW_OUTPORT(ctrlbase, 0x06, 0x00); DELAY_1MS; } /**********************************************************************************/ /* unmap the IO ports */ if (ctrlmemtype == 0) MmUnmapIoSpace(ctrlbase, NUMBER_OF_CONTROL_PORTS); if (sbmemtype == 0) MmUnmapIoSpace(sbbase, NUMBER_OF_SB_PORTS); _dbgprint((_PRT_DBUG, "exit cs423xDownloadUcode(STATUS_SUCCESS)\n")); return(STATUS_SUCCESS); } /* cs423xDownloadUcode */ /* ********************************************************************************* * soundlib wave callback for setting format * see pg 54 of the CS423x Data book - Changing Sample Rate and Audio Format ********************************************************************************* */ BOOLEAN cs423xResetMCEAndWait(PUCHAR base, ULONG caltype, UCHAR srate) { int t; UCHAR val; ULONG usec; _dbgprint((_PRT_DBUG, "cs423xResetMCEAndWait(srate: %d)\n", srate)); /* convert from CS423x encoded sample rate to microseconds */ switch (srate) { case CS423x_MAP_8KH: usec = 1000000 / 8000; break; case CS423x_MAP_16KH: usec = 1000000 / 16000; break; case CS423x_MAP_11KH: usec = 1000000 / 11025; break; case CS423x_MAP_27KH: usec = 1000000 / 27420; break; case CS423x_MAP_18KH: usec = 1000000 / 18900; break; case CS423x_MAP_32KH: usec = 1000000 / 32000; break; case CS423x_MAP_22KH: usec = 1000000 / 22050; break; case CS423x_MAP_37KH: usec = 1000000 / 37800; break; case CS423x_MAP_44KH: usec = 1000000 / 44100; break; case CS423x_MAP_48KH: usec = 1000000 / 48000; break; case CS423x_MAP_33KH: usec = 1000000 / 33075; break; case CS423x_MAP_9KH: usec = 1000000 / 9600; break; case CS423x_MAP_6KH: usec = 1000000 / 6620; break; default: usec = 1000000 / 5510; break; } /* calculate iteration count (maximum time) from type of calibaration */ switch (caltype) { case CS423x_BIT_CAL0: t = ((usec * 136) / 50) + 10; break; case CS423x_BIT_FULLCAL: t = ((usec * 168) / 50) + 10; break; default: t = ((usec * 40) / 50) + 10; break; } _dbgprint((_PRT_DBUG, "cs423xResetMCEAndWait(t: %d)\n", t)); /* set up to read the Error/Init/Test Register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_ERRINIT); /* wait for device readiness due to state change of MCE */ (void)cs423xReady(base); /* read the contents of the Error/Init/Test Register */ /* and look for ACI until we can make a decision */ val = HW_INPORT(base, CS423x_WSS_DMR_DATA); while ((t >= 0) && (val & CS423x_BIT_ACI)) { DELAY_50US; val = HW_INPORT(base, CS423x_WSS_DMR_DATA); t--; } _dbgprint((_PRT_DBUG, "cs423xResetMCEAndWait(val: 0x%02x t: %d)\n\n", val, t)); if (val & CS423x_BIT_ACI) return(FALSE); return(TRUE); } typedef struct _rate_conversion_item { ULONG sr; UCHAR format; } RATE_CONVERSION_ITEM; RATE_CONVERSION_ITEM rate_table[] = { {(5510+6620)/2, CS423x_MAP_5KH}, {(6620+8000)/2, CS423x_MAP_6KH}, {(8000+9600)/2, CS423x_MAP_8KH}, {(9600+11025)/2, CS423x_MAP_9KH}, {(11025+16000)/2, CS423x_MAP_11KH}, {(16000+18900)/2, CS423x_MAP_16KH}, {(18900+22050)/2, CS423x_MAP_18KH}, {(22050+27420)/2, CS423x_MAP_22KH}, {(27420+32000)/2, CS423x_MAP_27KH}, {(32000+33075)/2, CS423x_MAP_32KH}, {(33075+37800)/2, CS423x_MAP_33KH}, {(37800+44100)/2, CS423x_MAP_37KH}, {(44100+48000)/2, CS423x_MAP_44KH}, { 48000, CS423x_MAP_48KH} }; #define NUMRATES (sizeof(rate_table) / sizeof(RATE_CONVERSION_ITEM)) BOOLEAN cs423xSetFormat(PWAVE_INFO pWI) { INT i; UCHAR format; UCHAR result; BOOLEAN rval; PSOUND_HARDWARE pHW = pWI->HwContext; PUCHAR base = pHW->WssPortbase; PKMUTEX pKM = &pHW->HwMutex; _dbgprint((_PRT_DBUG, "\n---\n")); _dbgprint((_PRT_DBUG, "enter cs423xSetFormat(pWI: 0x%08x)\n", pWI)); _dbgprint((_PRT_DBUG, "--- pWI->Direction: 0x%08x\n", pWI->Direction)); _dbgprint((_PRT_DBUG, "pWI->SamplesPerSec: 0x%08x (%d)\n", pWI->SamplesPerSec, pWI->SamplesPerSec)); _dbgprint((_PRT_DBUG, "pWI->Channels: 0x%08x\n", pWI->Channels)); _dbgprint((_PRT_DBUG, "pWI->BitsPerSample: 0x%08x (%d)\n", pWI->BitsPerSample, pWI->BitsPerSample)); _dbgprint((_PRT_DBUG, "---\n")); /* find the nearest sample rate supported on the HW */ format = rate_table[NUMRATES-1].format; for (i = 0; i < NUMRATES-1; i++) { if (pWI->SamplesPerSec < rate_table[i].sr) { format = rate_table[i].format; break; } } /* determine and set the mono/stereo mode */ if (pWI->Channels == 1) format |= CS423x_BIT_MONO; else format |= CS423x_BIT_STEREO; /* determine and set the sample size and/or compression format */ if (pWI->BitsPerSample == 8) format |= CS423x_BIT_8BIT; else format |= CS423x_BIT_16BIT; _dbgprint((_PRT_DBUG, "format: 0x%02x [i:%d] [NUMRATES: %d]\n", format, i, NUMRATES)); _dbgprint((_PRT_DBUG, "----------------------------\n")); /* ***************************************************************************** * this is touchy - we can set format at any time, but we can not set * internal clocks (sample rate) while a DMA transfer is in progress. * So, we keep track of some hardware state (pHW->PCEnabled) and check it * before we set sample rate. * pHW->PCEnabled is set and reset while we CLAIM the HwMutex in * cs423xSetupDMA() and cs423xStopDMA() ***************************************************************************** */ /* default return value == FALSE unless we are successful */ rval = FALSE; /* consider whether playback or capture is requested */ if (pWI->Direction == CAPTURE_DIRECTION) { if (pHW->SampleRate == (format & 0x0f)) { cs423xSetCaptureFormat(pHW, (UCHAR)(format & 0xf0)); rval = TRUE; } else { if (pHW->PCEnabled == FALSE) { cs423xSetCaptureFormat(pHW, (UCHAR)(format & 0xf0)); cs423xSetSampleRate(pHW, (UCHAR)(format & 0x0f)); rval = TRUE; } else rval = FALSE; } } else /* PLAYBACK_DIRECTION */ { #if 0 /* out with the old */ if (pHW->SampleRate == (format & 0x0f)) { cs423xSetPlaybackFormat(pHW, (UCHAR)(format & 0xf0)); rval = TRUE; } else { if (pHW->PCEnabled == FALSE) { cs423xSetPBFormatSRate(pHW, (UCHAR)(format & 0xf0), (UCHAR)(format & 0x0f)); rval = TRUE; } else rval = FALSE; } #else /* in with the new */ /* ********************************************** ** 03.07.96 - JJB ** This change was made to accomodate the difference between ** the 4231 (which has no PMCE/CMCE function) and the 4232 which ** has the PMCE/CMCE bit in register I16 ********************************************** */ if (pHW->PCEnabled == FALSE) { cs423xSetPBFormatSRate(pHW, (UCHAR)(format & 0xf0), (UCHAR)(format & 0x0f)); rval = TRUE; } else rval = FALSE; #endif /* Dangerous Creatures change */ } _dbgprint((_PRT_DBUG, "exit cs423xSetFormat(rval: 0x%08x)\n", rval)); return(rval); } /* cs423xSetFormat */ /* ********************************************************************************* * verify supported wave formats ********************************************************************************* */ NTSTATUS cs423xQueryFormat(PLOCAL_DEVICE_INFO pLDI, PPCMWAVEFORMAT pFormat) { NTSTATUS rval; _dbgprint((_PRT_DBUG, "enter cs423xQueryFormat(pLDI: 0x%08x pFormat: 0x%08x)\n", pLDI, pFormat)); rval = STATUS_SUCCESS; if (((pFormat->wBitsPerSample != 8) && (pFormat->wBitsPerSample != 16)) || ((pFormat->wf.nChannels != 1) && (pFormat->wf.nChannels != 2)) || (pFormat->wf.wFormatTag != WAVE_FORMAT_PCM) || ((pFormat->wf.nSamplesPerSec < 5510) || (pFormat->wf.nSamplesPerSec > 48000))) { rval = STATUS_NOT_SUPPORTED; } _dbgprint((_PRT_DBUG, "exit cs423xQueryFormat(rval: 0x%08x)\n", rval)); return(rval); } /* cs423xQueryFormat() */ BOOLEAN HwWaitForTxComplete( IN PWAVE_INFO pWI ) /*++ Routine Description : Wait until the device stops requesting so we don't shut off the DMA while it's still trying to request. Arguments : pWI - Waveinfo structure Return Value : None --*/ { ULONG ulCount ; if (ulCount = HalReadDmaCounter( pWI->DMABuf.AdapterObject[0] )) { ULONG i, ulLastCount = ulCount ; for (i = 0; (i < 4000) && (ulLastCount != (ulCount = HalReadDmaCounter( pWI->DMABuf.AdapterObject[0] ))); i++) { ulLastCount = ulCount; KeStallExecutionProcessor(10); } return (i < 4000); } else return TRUE ; } /* ********************************************************************************* * soundlib wave callback for stopping DMA ********************************************************************************* */ BOOLEAN cs423xStopDMA(PWAVE_INFO pWI) { UCHAR result; PGLOBAL_DEVICE_INFO pGDI; PSOUND_HARDWARE pHW = pWI->HwContext; PUCHAR base = pHW->WssPortbase; PKMUTEX pKM = &pHW->HwMutex; _dbgprint((_PRT_DBUG, "cs423xStopDMA(entry)\n")); _dbgprint((_PRT_DBUG, "Direction: 0x%08x\n", pWI->Direction)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the Interface Config Register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_IFCNFG); result = HW_INPORT(base, CS423x_WSS_DMR_DATA); /* reset CS423x_BIT_CEN or CS423x_BIT_PEN depending upon direction */ if (pWI->Direction == PLAYBACK_DIRECTION) { HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (result & ~CS423x_BIT_PEN)); pHW->PCEnabled = FALSE; } else /* CAPTURE_DIRECTION */ { HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (result & ~CS423x_BIT_CEN)); pHW->PCEnabled = FALSE; } HwWaitForTxComplete( pWI ); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "cs423xStopDMA(exit:TRUE)\n")); return(TRUE); } /* cs423xStopDMA */ /* ********************************************************************************* * soundlib wave callback for setting up DMA ********************************************************************************* */ BOOLEAN cs423xSetupDMA(PWAVE_INFO pWI) { UCHAR result; ULONG numsamples; PSOUND_HARDWARE pHW = pWI->HwContext; PUCHAR base = pHW->WssPortbase; PKMUTEX pKM = &pHW->HwMutex; _dbgprint((_PRT_DBUG, "cs423xSetupDMA(entry)\n")); _dbgprint((_PRT_DBUG, "Buffersize: %d (0x%08x)\n", pWI->DoubleBuffer.BufferSize, pWI->DoubleBuffer.BufferSize)); _dbgprint((_PRT_DBUG, "Direction: 0x%08x\n", pWI->Direction)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* calculate sample count */ numsamples = (pWI->DoubleBuffer.BufferSize << 2) / (pWI->Channels * pWI->BitsPerSample) - 1; _dbgprint((_PRT_DBUG, "numsamples: %d (0x%08x)\n", numsamples, numsamples)); if (pWI->Direction == PLAYBACK_DIRECTION) { /* program the playback count registers */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PBLOWER); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (UCHAR)(numsamples & 0xff)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PBUPPER); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (UCHAR)((numsamples >> 8) & 0xff)); /* start the transfer by hitting the playback enable bit */ /* no need to assert MCE for this bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_IFCNFG); result = HW_INPORT(base, CS423x_WSS_DMR_DATA); result = result & CS423x_BIT_FULLDUP; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (result | CS423x_BIT_PEN)); pHW->PCEnabled = TRUE; } else /* CAPTURE_DIRECTION */ { /* program the capture count registers */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CPLOWER); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (UCHAR)(numsamples & 0xff)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CPUPPER); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (UCHAR)((numsamples >> 8) & 0xff)); /* start the transfer by hitting the capture enable bit */ /* no need to assert MCE for this bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_IFCNFG); result = HW_INPORT(base, CS423x_WSS_DMR_DATA); result = result & CS423x_BIT_FULLDUP; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (result | CS423x_BIT_CEN)); pHW->PCEnabled = TRUE; } /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "cs423xSetupDMA(exit:TRUE)\n")); return(TRUE); } /* cs423xSetupDMA */ /* ********************************************************************************* * calibrate the chip - see CS423x data book - Mar 1995 - pg 53 ********************************************************************************* */ NTSTATUS cs423xCalibrate(PGLOBAL_DEVICE_INFO pGDI) { INT i; UCHAR result; PUCHAR base; BOOLEAN b; _dbgprint((_PRT_DBUG, "cs423xCalibrate(entry)\n")); /* use the WSS port */ base = pGDI->Hw.WssPortbase; _dbgprint((_PRT_DBUG, "WSS base: 0x%08x\n", base)); /* *********************************************************************************** * reset the state of the part and perform Full Calibration *********************************************************************************** */ /* set the Mode Change Enable bit and set the bits */ /* in the Interface Configuration register for full calibration */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_IFCNFG | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_FULLCAL); /* set a default sample rate - calibration time is related to sample rate */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE2_CAPTFMT | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, pGDI->Hw.CaptureFormat); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_PLAYFMT | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (pGDI->Hw.PlayFormat | pGDI->Hw.SampleRate)); /* test for device readiness due to change of sample rate */ (void)cs423xReady(base); /* do the MCE state change, calibrate, wait, and check result */ if (!cs423xResetMCEAndWait(base, CS423x_BIT_FULLCAL, pGDI->Hw.SampleRate)) { _dbgprint((_PRT_DBUG, "cs423xCalibrate(exit:STATUS_DEVICE_CONFIGURATION_ERROR 0)\n")); return(STATUS_DEVICE_CONFIGURATION_ERROR); } /* *********************************************************************************** * calibrate again using CS423x_BIT_NOCAL so that if or when we fiddle with * the MCE later during format or sample rate changes we won't incur the 40 * sample period overhead associated with a first time CS423x_BIT_NOCAL * Calibration. This precuationary code can be removed if the alternate * (non-MCE i.e., non-calibrate) method for format and sample rate chenges is used *********************************************************************************** */ /* start of CS423x_BIT_NOCAL Calibration precautionary code */ /* set the Mode Change Enable bit and set the bits */ /* in the Interface Configuration register for NO calibration */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_IFCNFG | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_NOCAL); /* end of CS423x_BIT_NOCAL Calibration precautionary code */ /* do the MCE state change, calibrate, wait, and check result */ if (!cs423xResetMCEAndWait(base, CS423x_BIT_NOCAL, pGDI->Hw.SampleRate)) { _dbgprint((_PRT_DBUG, "cs423xCalibrate(exit:STATUS_DEVICE_CONFIGURATION_ERROR 1)\n")); return(STATUS_DEVICE_CONFIGURATION_ERROR); } _dbgprint((_PRT_DBUG, "cs423xCalibrate(exit:STATUS_SUCCESS)\n")); return(STATUS_SUCCESS); } /* cs423xCalibrate */ /* ********************************************************************************* * ISR Routine ********************************************************************************* */ BOOLEAN cs423xISR(IN PKINTERRUPT pI, IN PVOID context) { BOOLEAN rval; PGLOBAL_DEVICE_INFO pGDI; PSOUND_HARDWARE pHW; PUCHAR base; UCHAR istate; UCHAR svindex; UCHAR svpin; pGDI = context; pHW = &pGDI->Hw; base = pHW->WssPortbase; _dbgprint((_PRT_DBUG, "cs423xISR(entry)\n")); /* save the state of the index register in case */ /* it was being used when the interrupt occurred */ svindex = HW_INPORT(base, CS423x_WSS_DMR_INDEX); /* disable interrupts while we are working on the problem */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PIN); svpin = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (svpin & ~CS423x_BIT_IEN)); /* set the return value to default */ rval = FALSE; /* read the alternate feature status register */ /* we use this to determine cause of interrupt */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEATS); /* test and reset any and each interrupt type individually */ while ((istate = HW_INPORT(base, CS423x_WSS_DMR_DATA)) & CS423x_BIT_ANYINT) { _dbgprint((_PRT_DBUG, "istate: 0x%02x\n", istate)); /* Playback Interrupt */ if (istate & CS423x_BIT_PI) { _dbgprint((_PRT_DBUG, "cs423xISR: PLAYBACK interrupt (DMABusy: 0x%0x)\n", pGDI->WaveOutInfo.DMABusy)); if (!pGDI->WaveOutInfo.DpcQueued) { pGDI->WaveOutInfo.DpcQueued = TRUE; IoRequestDpc(pGDI->DeviceObject[WaveOutDevice], NULL, NULL); } else { if (istate & CS423x_BIT_PU) pGDI->WaveOutInfo.Overrun++; } rval = TRUE; istate = istate & ~CS423x_BIT_PI; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, istate); } /* Capture Interrupt */ if (istate & CS423x_BIT_CI) { _dbgprint((_PRT_DBUG, "cs423xISR: CAPTURE 0 interrupt (DMABusy: 0x%0x)\n", pGDI->WaveInInfo.DMABusy)); if (!pGDI->WaveInInfo.DpcQueued) { pGDI->WaveInInfo.DpcQueued = TRUE; IoRequestDpc(pGDI->DeviceObject[WaveInDevice], NULL, NULL); } else { if (istate & CS423x_BIT_CU) pGDI->WaveInInfo.Overrun++; } rval = TRUE; istate = istate & ~CS423x_BIT_CI; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, istate); } /* Timer Interrupt - unexpected */ if (istate & CS423x_BIT_TI) { _dbgprint((_PRT_DBUG, "cs423xISR: TIMER interrupt\n")); rval = TRUE; istate = istate & ~CS423x_BIT_TI; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, istate); } } /* check for bogus interrupt */ if (!rval) { pGDI->InterruptCount++; pGDI->BogusInterrupts++; if (pGDI->BogusInterrupts % 20) { _dbgprint((_PRT_DBUG, "cs423xISR: [BOGUS: %05d COUNT: %05d]\n", pGDI->InterruptCount, pGDI->BogusInterrupts)); } } /* re-enable interrupts */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PIN); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (svpin | CS423x_BIT_IEN)); /* restore the state of the index register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, svindex); _dbgprint((_PRT_DBUG, "cs423xISR(exit:[rval:0x%08x])\n", rval)); return(rval); } /* cs423xISR */ /* ********************************************************************************* * Get the output device capabilities ********************************************************************************* */ VOID cs423xWaveOutGetCaps(PWAVEOUTCAPSW pWOC) { RtlZeroMemory(pWOC, sizeof(WAVEOUTCAPSW)); pWOC->wMid = MM_IBM; pWOC->wPid = MM_MSFT_GENERIC_WAVEOUT; pWOC->vDriverVersion = IBM_CS423X_DRIVER_VERSION; pWOC->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16; pWOC->wChannels = 2; pWOC->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; *(PULONG)(pWOC->szPname) = IDS_WAVEOUT_PNAME; return; } /* cs423xWaveOutGetCaps */ /* ********************************************************************************* * Get the input device capabilities ********************************************************************************* */ VOID cs423xWaveInGetCaps(PWAVEINCAPSW pWIC) { RtlZeroMemory(pWIC, sizeof(WAVEINCAPSW)); pWIC->wMid = MM_IBM; pWIC->wPid = MM_MSFT_GENERIC_WAVEIN; pWIC->vDriverVersion = IBM_CS423X_DRIVER_VERSION; pWIC->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16; pWIC->wChannels = 2; *(PULONG)(pWIC->szPname) = IDS_WAVEIN_PNAME; return; } /* cs423xWaveInGetCaps */ /* ********************************************************************************* * Get the Aux device capabilities ********************************************************************************* */ VOID cs423xAuxGetCaps(PAUXCAPSW pAC) { RtlZeroMemory(pAC, sizeof(AUXCAPSW)); pAC->wMid = MM_IBM; pAC->wPid = MM_MSFT_GENERIC_AUX_LINE; *(PULONG)pAC->szPname = IDS_AUX_PNAME; pAC->vDriverVersion = IBM_CS423X_DRIVER_VERSION; pAC->wTechnology = AUXCAPS_AUXIN; pAC->dwSupport = AUXCAPS_LRVOLUME | AUXCAPS_VOLUME; return; } /* cs423xAuxGetCaps */ /* ********************************************************************************* * Set the Capture Format - registers I16 and I28 ********************************************************************************* */ VOID cs423xSetCaptureFormat(PSOUND_HARDWARE pHW, UCHAR format) { PUCHAR base; PKMUTEX pKM; _dbgprint((_PRT_DBUG, "enter cs423xSetCaptureFormat(pHW: 0x%08x, f: 0x%02x)\n", pHW, format)); if (pHW->CaptureFormat == (format & 0xf0)) return; _dbgprint((_PRT_DBUG, "cs423xSetCaptureFormat: setting registers\n")); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* set internal memory representation of register state */ pHW->CaptureFormat = format & 0xf0; /* set the Capture Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN1); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_CMCE); /* set the Capture Data Format register to the specified value */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CAPTFMT); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, pHW->CaptureFormat); /* wait for device readiness after change of format */ (void)cs423xReady(base); /* reset (clear) the Capture Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN1); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, 0x00); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetCaptureFormat()\n")); return; } /* ********************************************************************************* * Set the Playback Format - registers I8 and I16 ********************************************************************************* */ VOID cs423xSetPlaybackFormat(PSOUND_HARDWARE pHW, UCHAR format) { PUCHAR base; PKMUTEX pKM; _dbgprint((_PRT_DBUG, "enter cs423xSetPlaybackFormat(pHW: 0x%08x, f: 0x%02x)\n", pHW, format)); if (pHW->PlayFormat == (format & 0xf0)) return; _dbgprint((_PRT_DBUG, "cs423xSetPlaybackFormat: setting registers\n")); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* set internal memory representation of register state */ pHW->PlayFormat = format & 0xf0; /* set the WSS Index Register with the Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN1); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_PMCE); /* set the Fs and Playback register to the specified SR */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PLAYFMT); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, pHW->PlayFormat); /* test for device readiness due to change of format */ (void)cs423xReady(base); /* reset (clear) the Playback Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN1); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, 0x00); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetPlaybackFormat()\n")); return; } /* ********************************************************************************* * Set the Sample Rate - registers I8 and I9 ********************************************************************************* */ VOID cs423xSetSampleRate(PSOUND_HARDWARE pHW, UCHAR ratecode) { PUCHAR base; PKMUTEX pKM; UCHAR ucValue; _dbgprint((_PRT_DBUG, "enter cs423xSetSampleRate(pHW: 0x%08x, f: 0x%02x)\n", pHW, ratecode)); if (pHW->SampleRate == (ratecode & 0x0f)) return; _dbgprint((_PRT_DBUG, "cs423xSetSampleRate: setting registers\n")); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* set internal memory representation of register state */ pHW->SampleRate = ratecode & 0x0f; /* set the WSS Index Register with the Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_IFCNFG | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_NOCAL); /* set the Fs and Playback register to the specified SR */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_PLAYFMT | CS423x_BIT_IAR_MCE)); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & 0xf0; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | pHW->SampleRate)); /* test for device readiness due to change of format */ (void)cs423xReady(base); /* reset (clear) the Mode Change Enable bit */ cs423xResetMCEAndWait(base, CS423x_BIT_NOCAL, pHW->SampleRate); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetSampleRate()\n")); return; } /* cs423xSetSampleRate() */ /* ********************************************************************************* * Set the Playback Format and the Sample Rate in one operation - registers I8 and I9 ********************************************************************************* */ VOID cs423xSetPBFormatSRate(PSOUND_HARDWARE pHW, UCHAR format, UCHAR ratecode) { PUCHAR base; PKMUTEX pKM; _dbgprint((_PRT_DBUG, "enter cs423xSetPBFormatSRate(pHW: 0x%08x, f: 0x%02x r: 0x%02x)\n", pHW, format, ratecode)); if ((pHW->PlayFormat == (format & 0xf0)) && (pHW->SampleRate == (ratecode & 0x0f))) return; _dbgprint((_PRT_DBUG, "cs423xSetPBFormatSRate: setting registers\n")); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* set internal memory representation of register states */ pHW->PlayFormat = format & 0xf0; pHW->SampleRate = ratecode & 0x0f; /* set the WSS Index Register with the Mode Change Enable bit */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_IFCNFG | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_NOCAL); /* set the Fs and Playback register to the specified SR */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, (CS423x_MODE1_PLAYFMT | CS423x_BIT_IAR_MCE)); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (pHW->PlayFormat | pHW->SampleRate)); /* test for device readiness due to change of format */ (void)cs423xReady(base); /* reset (clear) the Mode Change Enable bit */ cs423xResetMCEAndWait(base, CS423x_BIT_NOCAL, pHW->SampleRate); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetPBFormatSRate()\n")); return; } /* cs423xSetPBFormatSRate() */ /* ********************************************************************************* * Set the Mono Output Mute - register I26 ********************************************************************************* */ VOID cs423xSetSpeakerMute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetSpeakerMute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_MOM; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the Mono IO register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_MONOIO); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_MIM | CS423x_BIT_MBY | CS423x_MAP_OUTATT); /* output the new Mono IO register value */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetSpeakerMute\n")); return; } /* cs423xSetSpeakerMute() */ /* ********************************************************************************* * Set the Mixer AUX2 Input Gain - registers I4 and I5 ********************************************************************************* */ VOID cs423xSetMixerInputAux2Gain(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT lgain; USHORT rgain; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputAux2Gain(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 5-bit gain register values */ /* as defined for Left/Right Mixer AUX2 Input gain in table 8 of the CS423x data book */ lgain = ~((left >> 11) & CS423x_MAP_X2GAIN) & CS423x_MAP_X2GAIN; rgain = ~((right >> 11) & CS423x_MAP_X2GAIN) & CS423x_MAP_X2GAIN; _dbgprint((_PRT_DBUG, "cs423xSetMixerInputAux2Gain(l: 0x%02x, r: 0x%02x)\n", (UCHAR)lgain, (UCHAR)rgain)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX2); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_X2MUTE; /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)lgain)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX2); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_X2MUTE; /* output the new RIGHT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)rgain)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputAux2Gain\n")); return; } /* cs423xSetMixerInputAux2Gain() */ /* ********************************************************************************* * Set the Mixer AUX2 Input Mute - registers I4 and I5 ********************************************************************************* */ VOID cs423xSetMixerInputAux2Mute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputAux2Mute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_X2MUTE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX2); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_X2GAIN; /* output the new LEFT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX2); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_X2GAIN; /* output the new RIGHT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputAux2Mute\n")); return; } /* cs423xSetMixerInputAux2Mute() */ /* ********************************************************************************* * Set the Mixer Waveout/DAC Input Attenuation - registers I6 and I7 ********************************************************************************* */ VOID cs423xSetMixerInputWaveoutAttenuation(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT latten; USHORT ratten; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputWaveoutAttenuation(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 6-bit attenuation register values */ /* as defined for Left/Right DAC Output Attenuation in table 7 of the CS423x data book */ latten = ~((left >> 10) & CS423x_MAP_DACATT) & CS423x_MAP_DACATT; ratten = ~((right >> 10) & CS423x_MAP_DACATT) & CS423x_MAP_DACATT; _dbgprint((_PRT_DBUG, "cs423xSetMixerInputWaveoutAttenuation(l: 0x%02x, r: 0x%02x)\n", (UCHAR)latten, (UCHAR)ratten)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LDAC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_DACMUTE; /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)latten)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RDAC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_DACMUTE; /* output the new RIGHT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)ratten)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputWaveoutAttenuation\n")); return; } /* cs423xSetMixerInputWaveoutAttenuation() */ /* ********************************************************************************* * Set the Mixer Waveout/DAC Input Mute - registers I6 and I7 ********************************************************************************* */ VOID cs423xSetMixerInputWaveoutMute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputWaveoutMute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_OAMUTE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LDAC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_DACATT; /* output the new LEFT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RDAC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_DACATT; /* output the new RIGHT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputWaveoutMute\n")); return; } /* cs423xSetMixerInputWaveoutMute() */ /* ********************************************************************************* * Set the Mixer Linein Input Gain - registers I18 and I19 ********************************************************************************* */ VOID cs423xSetMixerInputLineinGain(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT lgain; USHORT rgain; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputLineinGain(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 5-bit gain register values */ /* as defined for Left/Right Mixer Linein Input gain in table 8 of the CS423x data book */ lgain = ~((left >> 11) & CS423x_MAP_LIGAIN) & CS423x_MAP_LIGAIN; rgain = ~((right >> 11) & CS423x_MAP_LIGAIN) & CS423x_MAP_LIGAIN; _dbgprint((_PRT_DBUG, "cs423xSetMixerInputLineinGain(l: 0x%02x, r: 0x%02x)\n", (UCHAR)lgain, (UCHAR)rgain)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LLINE); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_LIMUTE; /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)lgain)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_RLINE); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_LIMUTE; /* output the new RIGHT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)rgain)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputLineinGain\n")); return; } /* cs423xSetMixerInputLineinGain() */ /* ********************************************************************************* * Set the Mixer Linein Input Mute - registers I18 and I19 ********************************************************************************* */ VOID cs423xSetMixerInputLineinMute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputLineinMute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_X2MUTE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LLINE); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_LIGAIN; /* output the new LEFT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_RLINE); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_LIGAIN; /* output the new RIGHT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputLineinMute\n")); return; } /* cs423xSetMixerInputLineinMute() */ /* ********************************************************************************* * Set the Mixer AUX1 Input Gain - registers I2 and I3 ********************************************************************************* */ VOID cs423xSetMixerInputAux1Gain(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT lgain; USHORT rgain; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputAux1Gain(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 5-bit gain register values */ /* as defined for Left/Right Mixer AUX1 Input gain in table 8 of the CS423x data book */ lgain = ~((left >> 11) & CS423x_MAP_X1GAIN) & CS423x_MAP_X1GAIN; rgain = ~((right >> 11) & CS423x_MAP_X1GAIN) & CS423x_MAP_X1GAIN; _dbgprint((_PRT_DBUG, "cs423xSetMixerInputAux1Gain(l: 0x%02x, r: 0x%02x)\n", (UCHAR)lgain, (UCHAR)rgain)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX1); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_X1MUTE; /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)lgain)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX1); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_X1MUTE; /* output the new RIGHT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)rgain)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputAux1Gain\n")); return; } /* cs423xSetMixerInputAux1Gain() */ /* ********************************************************************************* * Set the Mixer AUX1 Input Mute - registers I2 and I3 ********************************************************************************* */ VOID cs423xSetMixerInputAux1Mute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputAux1Mute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_X1MUTE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX1); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_X1GAIN; /* output the new LEFT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX1); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_X1GAIN; /* output the new RIGHT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputAux1Mute\n")); return; } /* cs423xSetMixerInputAux1Mute() */ /* ********************************************************************************* * Set the Mixer Mono Input attenuation - register I26 ********************************************************************************* */ VOID cs423xSetMixerInputMonoinAttenuation(PSOUND_HARDWARE pHW, USHORT a) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT atten; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputMonoinAttenuation(pHW: 0x%08x, a: 0x%08x)\n", pHW, a)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 4-bit attenuation register values */ /* as defined for Mono Input Attenuation in table 6 of the CS423x data book */ atten = ~((a >> 12) & CS423x_MAP_OUTATT) & CS423x_MAP_OUTATT; _dbgprint((_PRT_DBUG, "cs423xSetMixerInputMonoinAttenuation(atten: 0x%02x\n", (UCHAR)atten)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_MONOIO); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_MIM | CS423x_BIT_MOM | CS423x_BIT_MBY); /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)atten)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputMonoinAttenuation\n")); return; } /* cs423xSetMixerInputMonoinAttenuation() */ /* ********************************************************************************* * Set the Mixer Mono Input Mute - register ********************************************************************************* */ VOID cs423xSetMixerInputMonoinMute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetMixerInputMonoinMute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_MIM; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_MONOIO); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_MOM | CS423x_BIT_MBY | CS423x_MAP_OUTATT); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMixerInputMonoinMute\n")); return; } /* cs423xSetMixerInputMonoinMute() */ /* ********************************************************************************* * Set the Internal Monitor Loopback attenuation - register I13 ********************************************************************************* */ VOID cs423xSetWaveinMonitorAttenuation(PSOUND_HARDWARE pHW, USHORT a) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT atten; _dbgprint((_PRT_DBUG, "enter cs423xSetWaveinMonitorAttenuation(pHW: 0x%08x, a: 0x%08x)\n", pHW, a)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 6-bit attenuation register values */ /* as defined for Loopback Monitor Attenuation in table 7 of the CS423x data book */ atten = ~((a >> 8) & CS423x_MAP_LBATTEN) & CS423x_MAP_LBATTEN; _dbgprint((_PRT_DBUG, "cs423xSetWaveinMonitorAttenuation(a: 0x%02x\n", (UCHAR)atten)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LOOP); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_LBE; /* output the new attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)atten)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetWaveinMonitorAttenuation\n")); return; } /* cs423xSetWaveinMonitorAttenuation() */ /* ********************************************************************************* * Set the Mixer Mono Input Mute - register ********************************************************************************* */ VOID cs423xSetWaveinMonitorEnable(PSOUND_HARDWARE pHW, BOOLEAN enable) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR eval; _dbgprint((_PRT_DBUG, "enter cs423xSetWaveinMonitorEnable(pHW: 0x%08x, enable: 0x%08x)\n", pHW, enable)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; eval = 0; if (enable) eval = CS423x_BIT_LBE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LOOP); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_LBATTEN; HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | eval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetWaveinMonitorEnable\n")); return; } /* cs423xSetWaveinMonitorEnable() */ /* ********************************************************************************* * Set the Output attenuation - registers I27 and I29 ********************************************************************************* */ VOID cs423xSetOutputAttenuation(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT latten; USHORT ratten; _dbgprint((_PRT_DBUG, "enter cs423xSetOutputAttenuation(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 4-bit attenuation register values */ /* as defined for Left/Right Output Attenuation in table 6 of the CS423x data book */ latten = ~((left >> 12) & CS423x_MAP_OUTATT) & CS423x_MAP_OUTATT; ratten = ~((right >> 12) & CS423x_MAP_OUTATT) & CS423x_MAP_OUTATT; _dbgprint((_PRT_DBUG, "cs423xSetOutputAttenuation(l: 0x%02x, r: 0x%02x)\n", (UCHAR)latten, (UCHAR)ratten)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LOUT); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_OAMUTE; /* output the new LEFT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)latten)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ROUT); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_BIT_OAMUTE; /* output the new RIGHT channel attenuation */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)ratten)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetOutputAttenuation\n")); return; } /* cs423xSetOutputAttenuation() */ /* ********************************************************************************* * Set the Output Mute - registers I27 and I29 ********************************************************************************* */ VOID cs423xSetOutputMute(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR mval; _dbgprint((_PRT_DBUG, "enter cs423xSetOutputMute(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; mval = 0; if (set) mval = CS423x_BIT_OAMUTE; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LOUT); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_OUTATT; /* output the new LEFT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ROUT); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & CS423x_MAP_OUTATT; /* output the new RIGHT channel Mute */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | mval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetOutputMute\n")); return; } /* cs423xSetOutputMute() */ /* ********************************************************************************* * Set the MUX Select - registers I0 and I1 ********************************************************************************* */ VOID cs423xSetMuxSelect(PSOUND_HARDWARE pHW, ULONG i) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR sel; _dbgprint((_PRT_DBUG, "enter cs423xSetMuxSelect(pHW: 0x%08x, i: 0x%08x)\n", pHW, i)); if (i > 3) return; base = pHW->WssPortbase; pKM = &pHW->HwMutex; sel = (UCHAR)((i << 6) & 0xc0); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left mux register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_MAP_ADCGAIN | CS423x_BIT_BOOST); /* output the new LEFT channel gain */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)sel)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_MAP_ADCGAIN | CS423x_BIT_BOOST); /* output the new RIGHT channel gain */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)sel)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMuxSelect\n")); return; } /* cs423xSetMuxSelect() */ /* ********************************************************************************* * Set the state of the 20db Microphone (input) boost - registers I0 and I1 ********************************************************************************* */ VOID cs423xSetMicBoost(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR bval; _dbgprint((_PRT_DBUG, "enter cs423xSetMicBoost(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; bval = 0; if (set) bval = CS423x_BIT_BOOST; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_SRC0 | CS423x_BIT_SRC1 | CS423x_MAP_ADCGAIN); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | bval)); /* fetch the current value of the register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_SRC0 | CS423x_BIT_SRC1 | CS423x_MAP_ADCGAIN); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | bval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetMicBoost\n")); return; } /* cs423xSetMicBoost */ /* ********************************************************************************* * Set the state of the on-chip High Pass Filter and DC Offset - Register I17 ********************************************************************************* */ VOID cs423xSetHPF(PSOUND_HARDWARE pHW, BOOLEAN set) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; UCHAR hpfval; _dbgprint((_PRT_DBUG, "enter cs423xSetHPF(pHW: 0x%08x, set: 0x%08x)\n", pHW, set)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; hpfval = 0; if (set) hpfval = CS423x_BIT_HPF; /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN2); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_APAR | CS423x_BIT_XTALE); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | hpfval)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetHPF\n")); return; } /* cs423xSetHPF */ /* ********************************************************************************* * Set the MUX Input Gain - registers I0 and I1 ********************************************************************************* */ VOID cs423xSetWaveinGain(PSOUND_HARDWARE pHW, USHORT left, USHORT right) { UCHAR ucValue; PUCHAR base; PKMUTEX pKM; USHORT lgain; USHORT rgain; _dbgprint((_PRT_DBUG, "enter cs423xSetWaveinGain(pHW: 0x%08x, l: 0x%08x, r: 0x%08x)\n", pHW, left, right)); base = pHW->WssPortbase; pKM = &pHW->HwMutex; /* translate the logical 16-bit input values to 4-bit gain register values */ /* as defined for Left/Right Input Gain in table 6 of the CS423x data book */ lgain = (left >> 12) & CS423x_MAP_ADCGAIN; rgain = (right >> 12) & CS423x_MAP_ADCGAIN; _dbgprint((_PRT_DBUG, "cs423xSetWaveinGain(l: 0x%02x, r: 0x%02x)\n", (UCHAR)lgain, (UCHAR)rgain)); /* serialize on the hardware mutex */ HW_CLAIM(pKM); /* fetch the current value of the left register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_BOOST | CS423x_BIT_SRC0 | CS423x_BIT_SRC1); /* output the new LEFT channel gain */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)lgain)); /* fetch the current value of the right register */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RADC); ucValue = HW_INPORT(base, CS423x_WSS_DMR_DATA); ucValue = ucValue & (CS423x_BIT_BOOST | CS423x_BIT_SRC0 | CS423x_BIT_SRC1); /* output the new RIGHT channel gain */ HW_OUTPORT(base, CS423x_WSS_DMR_DATA, (ucValue | (UCHAR)rgain)); /* release the hardware mutex */ HW_DISCLAIM(pKM); _dbgprint((_PRT_DBUG, "exit cs423xSetWaveinGain\n")); return; } /* cs423xSetWaveinGain() */ #ifdef CS423X_DEBUG_ON #define _DBSWITCH _PRT_WARN VOID cs423xDisplayRegs(PGLOBAL_DEVICE_INFO pGDI) { PKMUTEX pkm; PUCHAR base; UCHAR r0; UCHAR r1; UCHAR saveindex; UCHAR savemode; pkm = &pGDI->Hw.HwMutex; base = pGDI->Hw.WssPortbase; _dbgprint((_DBSWITCH, "\n")); _dbgprint((_DBSWITCH, "*======== -- CS423x (WSS) Registers -- =======*\n")); _dbgprint((_DBSWITCH, "| |\n")); r0 = saveindex = HW_INPORT(base, CS423x_WSS_DMR_INDEX); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_MODID); r1 = savemode = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| R00-Index: 0x%02x R01-Data: 0x%02x |\n", r0, r1)); r0 = HW_INPORT(base, CS423x_WSS_DMR_STATUS); r1 = HW_INPORT(base, CS423x_WSS_DMR_PIOD); _dbgprint((_DBSWITCH, "| R02-Status: 0x%02x R03-PIOD: 0x%02x |\n", r0, r1)); _dbgprint((_DBSWITCH, "\n")); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LADC); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RADC); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I00-L ADC: 0x%02x I01-R ADC: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX1); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX1); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I02-L AUX1: 0x%02x I03-R AUX1: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LAUX2); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RAUX2); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I04-L AUX2: 0x%02x I05-R AUX2: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LDAC); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_RDAC); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I06-L DAC: 0x%02x I07-R DAC: 0x%02x |\n", r0, r1)); _dbgprint((_DBSWITCH, "\n")); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PLAYFMT); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_IFCNFG); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I08-PLAYFMT: 0x%02x I09-IFCNFG: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PIN); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_ERRINIT); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I10-PIN: 0x%02x I11-ERRINIT: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_MODID); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); if (savemode & CS423x_BIT_MODE2) r0 |= CS423x_BIT_MODE2; HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_LOOP); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I12-MODID: 0x%02x I13-LOOP: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PBUPPER); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_PBLOWER); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I14-PBUPPER: 0x%02x I15-PBLOWER: 0x%02x |\n", r0, r1)); _dbgprint((_DBSWITCH, "\n")); if (!(savemode & CS423x_BIT_MODE2)) { /* switch to mode 2 */ HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_MODID); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, CS423x_BIT_MODE2); } HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN1); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN2); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I16-ALTFEN1: 0x%02x I17-ALTFEN2: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LLINE); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_RLINE); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I18-LLINE: 0x%02x I19-LLINE: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_TLBASE); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_TUBASE); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I20-TLBASE: 0x%02x I21-TUBASE: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTSFREQ); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEN3); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I22-ALTSFREQ: 0x%02x I23-ALTFEN3: 0x%02x |\n", r0, r1)); _dbgprint((_DBSWITCH, "\n")); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ALTFEATS); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_VERSID); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I24-ALTFEATS: 0x%02x I25-VERSID: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_MONOIO); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_LOUT); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I26-MONOIO: 0x%02x I27-LOUT: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CAPTFMT); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_ROUT); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I28-CAPTFMT: 0x%02x I29-ROUT: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CPUPPER); r0 = HW_INPORT(base, CS423x_WSS_DMR_DATA); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE2_CPLOWER); r1 = HW_INPORT(base, CS423x_WSS_DMR_DATA); _dbgprint((_DBSWITCH, "| I30-CUBASE: 0x%02x I31-ROUT: 0x%02x |\n", r0, r1)); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, CS423x_MODE1_MODID); HW_OUTPORT(base, CS423x_WSS_DMR_DATA, savemode); HW_OUTPORT(base, CS423x_WSS_DMR_INDEX, saveindex); _dbgprint((_DBSWITCH, "| |\n")); _dbgprint((_DBSWITCH, "*======== -- CS423x (WSS) Registers -- =======*\n")); _dbgprint((_DBSWITCH, "\n")); return; } /* cs423xDisplayRegs */ #endif