|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: config.c
8:
9: Abstract:
10:
11: This module contains code configuration code for the initialization phase
12: of the Microsoft Sound System device driver.
13:
14: Author:
15:
16: Robin Speed (RobinSp) 17-Oct-1992
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History:
23:
24: --*/
25:
26:
27: #include "sound.h"
28:
29: //
30: // Internal routines
31: //
32: NTSTATUS
33: SoundInitIoPort(
34: IN OUT PGLOBAL_DEVICE_INFO pGDI,
35: IN OUT PSB_CONFIG_DATA ConfigData
36: );
37: NTSTATUS
38: SoundPortValid(
39: IN OUT PGLOBAL_DEVICE_INFO pGDI,
40: IN OUT PULONG Port
41: );
42: NTSTATUS
43: SoundInitDmaChannel(
44: IN OUT PGLOBAL_DEVICE_INFO pGDI,
45: IN OUT PULONG DmaChannel,
46: IN ULONG DmaBufferSize
47: );
48: NTSTATUS
49: SoundDmaChannelValid(
50: IN OUT PGLOBAL_DEVICE_INFO pGDI,
51: IN OUT PULONG DmaChannel
52: );
53: NTSTATUS
54: SoundInitInterrupt(
55: IN OUT PGLOBAL_DEVICE_INFO pGDI,
56: IN OUT PULONG Interrupt
57: );
58: NTSTATUS
59: SoundInterruptValid(
60: IN OUT PGLOBAL_DEVICE_INFO pGDI,
61: IN OUT PULONG Interrupt
62: );
63: VOID
64: SoundSetVersion(
65: IN PGLOBAL_DEVICE_INFO pGlobalInfo,
66: IN ULONG DSPVersion
67: );
68:
69: #ifdef ALLOC_PRAGMA
70: #pragma alloc_text(init,SoundSetVersion)
71: #pragma alloc_text(init,SoundInitHardwareConfig)
72: #pragma alloc_text(init,SoundInitIoPort)
73: #pragma alloc_text(init,SoundInitDmaChannel)
74: #pragma alloc_text(init,SoundInitInterrupt)
75: #pragma alloc_text(init,SoundSaveConfig)
76: #pragma alloc_text(init,SoundReadConfiguration)
77: #endif
78:
79:
80: VOID
81: SoundSetVersion(
82: IN PGLOBAL_DEVICE_INFO pGlobalInfo,
83: IN ULONG DSPVersion
84: )
85: /*++
86:
87: Routine Description :
88:
89: Sets a version DWORD into the registry as a pseudo return code
90: to sndblst.drv
91:
92: As a side effect the key to the registry entry is closed.
93:
94: Arguments :
95:
96: pGlobalInfo - Our driver global info
97:
98: DSPVersion - the version number we want to set
99:
100: Return Value :
101:
102: None
103:
104: --*/
105: {
106: UNICODE_STRING VersionString;
107:
108: RtlInitUnicodeString(&VersionString, L"DSP Version");
109: if (pGlobalInfo->RegistryPathName) {
110: NTSTATUS SetStatus;
111:
112: SetStatus =
113:
114: SoundWriteRegistryDWORD(pGlobalInfo->RegistryPathName,
115: L"DSP Version",
116: DSPVersion);
117:
118: if (!NT_SUCCESS(SetStatus)) {
119: dprintf1(("Failed to write version - status %x", SetStatus));
120: }
121: }
122: }
123:
124:
125: NTSTATUS
126: SoundInitHardwareConfig(
127: IN OUT PGLOBAL_DEVICE_INFO pGDI,
128: IN PSB_CONFIG_DATA ConfigData
129: )
130: {
131:
132: NTSTATUS Status;
133:
134: //
135: // Check the input source
136: //
137:
138: if (ConfigData->InputSource > INPUT_OUTPUT) {
139: return STATUS_DEVICE_CONFIGURATION_ERROR;
140: }
141:
142: pGDI->Hw.InputSource = ConfigData->InputSource;
143:
144: //
145: // Find port
146: //
147:
148: Status = SoundInitIoPort(pGDI, ConfigData);
149:
150: if (!NT_SUCCESS(Status)) {
151: return Status;
152: }
153:
154: //
155: // Find interrupt
156: //
157:
158: Status = SoundInitInterrupt(pGDI, &ConfigData->InterruptNumber);
159:
160: if (!NT_SUCCESS(Status)) {
161: return Status;
162: }
163:
164: //
165: // Find DMA channel
166: //
167:
168: Status = SoundInitDmaChannel(pGDI, &ConfigData->DmaChannel,
169: ConfigData->DmaBufferSize);
170:
171: if (!NT_SUCCESS(Status)) {
172: return Status;
173: }
174:
175: //
176: // Report the sound-blaster version number (and a flag
177: // to say if it's a Thunderboard.
178: // We do this via an entry in our registry node - under
179: // our device-specific section. If this fails then configuration
180: // won't work so well but the driver will work fine.
181: //
182: // We use the registry handle generated by SoundReadConfiguration
183:
184: {
185: ULONG DSPVersion;
186:
187: DSPVersion = pGDI->Hw.DSPVersion;
188:
189: //
190: // If it's a pro audio spectrum set a bit to say it is
191: //
192:
193: if (pGDI->ProAudioSpectrum) {
194: DSPVersion |= 0x800;
195: } else {
196: //
197: // If it's a Thunderboard following comparison will fail.
198: // There's not much point having a constant for a flag
199: // because there's no logical way to share info between
200: // sndblst.sys and sndblst.drv
201: //
202:
203: if (pGDI->Hw.ThunderBoard) {
204: DSPVersion |= 0x8000;
205:
206: //
207: // Note - it MAY be a pro spectrum !
208: //
209: }
210: }
211:
212: //
213: // Put the version number in the registry (if we can)
214: //
215:
216: SoundSetVersion(pGDI, DSPVersion);
217: }
218:
219:
220: //
221: // turn on the speaker
222: //
223:
224: dspSpeakerOn(&pGDI->Hw);
225:
226: return STATUS_SUCCESS;
227:
228: }
229:
230:
231:
232:
233: NTSTATUS
234: SoundInitIoPort(
235: IN OUT PGLOBAL_DEVICE_INFO pGDI,
236: IN OUT PSB_CONFIG_DATA ConfigData
237: )
238: {
239: NTSTATUS Status;
240:
241: //
242: // Find where our device is mapped
243: //
244:
245: pGDI->Hw.PortBase = SoundMapPortAddress(
246: pGDI->BusType,
247: pGDI->BusNumber,
248: ConfigData->Port,
249: NUMBER_OF_SOUND_PORTS,
250: &pGDI->MemType);
251:
252: //
253: // Check and see if the hardware is happy
254: //
255:
256: //
257: // Check the SoundBlaster is where we think it is and get
258: // the dsp version code.
259: //
260:
261: if (!dspReset(&pGDI->Hw)) {
262: NTSTATUS PasStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
263:
264: #ifdef PAS16 // There's a proper driver now
265:
266: //
267: // Try to wake up any lurking Pro audio spectrums
268: // that are asleep
269: //
270:
271: PasStatus = FindPasHardware(pGDI, ConfigData);
272:
273: #endif // PAS16
274:
275: if (!NT_SUCCESS(PasStatus) || !dspReset(&pGDI->Hw)) {
276: pGDI->Hw.DSPVersion = 0;
277: SoundSetVersion(pGDI, 0x4000); // Means port was wrong
278: return STATUS_DEVICE_CONFIGURATION_ERROR;
279: }
280:
281: pGDI->ProAudioSpectrum = TRUE;
282: }
283:
284: pGDI->Hw.DSPVersion = dspGetVersion(&pGDI->Hw);
285:
286: //
287: // Check for Thunderboards and Pro Spectrums
288: //
289:
290: if (dspGetVersion(&pGDI->Hw) != pGDI->Hw.DSPVersion) {
291: pGDI->Hw.ThunderBoard = TRUE;
292:
293: #ifdef PAS16 // We now have a proper driver for this
294: //
295: // See if this guy is a Pro audio spectrum. By this
296: // stage it will be woken up but we still need to tell if
297: // it is one and set its features and mixer.
298: //
299:
300: if (pGDI->ProAudioSpectrum ||
301: NT_SUCCESS(FindPasHardware(pGDI, ConfigData))) {
302:
303: pGDI->ProAudioSpectrum = TRUE;
304: InitPasAndMixer(&pGDI->PASInfo, ConfigData);
305: }
306: #endif // PAS16
307: }
308:
309:
310: //
311: // Set up version - dependent stuff
312: //
313: if (pGDI->Hw.DSPVersion >= MIN_DSP_VERSION) {
314:
315: pGDI->MinHz = 4000;
316:
317: if (SB1(&pGDI->Hw)) {
318: pGDI->MaxInHz = 12000;
319: pGDI->MaxOutHz = 23000;
320: } else {
321: if (!SBPRO(&pGDI->Hw)) {
322: pGDI->MaxInHz = 13000;
323: pGDI->MaxOutHz = 23000;
324: } else {
325: pGDI->MaxInHz = 23000;
326: pGDI->MaxOutHz = 23000;
327: }
328: }
329: return STATUS_SUCCESS;
330: } else {
331: return STATUS_DEVICE_CONFIGURATION_ERROR;
332: }
333: }
334:
335:
336:
337: NTSTATUS
338: SoundInitDmaChannel(
339: IN OUT PGLOBAL_DEVICE_INFO pGDI,
340: IN OUT PULONG DmaChannel,
341: IN ULONG DmaBufferSize
342: )
343: {
344: NTSTATUS Status;
345:
346: DEVICE_DESCRIPTION DeviceDescription; // DMA adapter object
347:
348: //
349: // See if we can get this channel
350: //
351:
352: //
353: // Zero the device description structure.
354: //
355:
356: RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
357:
358: //
359: // Get the adapter object for this card.
360: //
361:
362: DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
363: DeviceDescription.AutoInitialize = !SB1(&pGDI->Hw);
364: DeviceDescription.ScatterGather = FALSE;
365: DeviceDescription.DmaChannel = *DmaChannel;
366: DeviceDescription.InterfaceType = Isa; // Must use Isa DMA
367: DeviceDescription.DmaWidth = Width8Bits;
368: DeviceDescription.DmaSpeed = Compatible;
369: DeviceDescription.MaximumLength = DmaBufferSize;
370: DeviceDescription.BusNumber = pGDI->BusNumber;
371:
372: return SoundGetCommonBuffer(&DeviceDescription, &pGDI->WaveInfo.DMABuf);
373: }
374:
375:
376:
377: NTSTATUS
378: SoundInitInterrupt(
379: IN OUT PGLOBAL_DEVICE_INFO pGDI,
380: IN OUT PULONG Interrupt
381: )
382: {
383: NTSTATUS Status;
384:
385: //
386: // See if we can get this interrupt
387: //
388:
389:
390: Status = SoundConnectInterrupt(
391: *Interrupt,
392: pGDI->BusType,
393: pGDI->BusNumber,
394: SoundISR,
395: (PVOID)pGDI,
396: INTERRUPT_MODE,
397: IRQ_SHARABLE,
398: &pGDI->WaveInfo.Interrupt);
399:
400: if (!NT_SUCCESS(Status)) {
401: return Status;
402: }
403:
404: //
405: // Check if our interrupts are working.
406: // To do this we write a special code to make the card generate
407: // an interrupt. We wait a reasonable amount of time for
408: // this to happen. This is tried 10 times.
409: //
410: {
411: int i;
412: int j;
413: ULONG CurrentCount;
414: CurrentCount = pGDI->InterruptsReceived + 1;
415:
416: for (i = 0; i < 10; i++, CurrentCount++) {
417:
418: // Tell the card to generate an interrupt
419:
420: dspWrite(&pGDI->Hw, DSP_GENERATE_INT);
421:
422: //
423: // The interrupt routine will increment the InterruptsReceived
424: // field if we get an interrupt.
425: //
426:
427: for (j = 0; j < 1000; j++) {
428: if (CurrentCount == pGDI->InterruptsReceived) {
429: break;
430: }
431: KeStallExecutionProcessor(10);
432: }
433:
434: //
435: // This test catches both too many and too few interrupts
436: //
437:
438: if (CurrentCount != pGDI->InterruptsReceived) {
439:
440: dprintf1(("Sound blaster configured at wrong interrupt"));
441:
442: SoundSetVersion(pGDI, 0x2000); // Means wrong interrupt
443: return STATUS_DEVICE_CONFIGURATION_ERROR;
444: }
445: }
446: }
447:
448: return STATUS_SUCCESS;
449: }
450:
451:
452:
453: NTSTATUS
454: SoundSaveConfig(
455: IN PWSTR DeviceKey,
456: IN ULONG Port,
457: IN ULONG DmaChannel,
458: IN ULONG Interrupt,
459: IN ULONG InputSource
460: )
461: {
462: NTSTATUS Status;
463:
464: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_PORT, Port);
465:
466: if (!NT_SUCCESS(Status)) {
467: return Status;
468: }
469:
470: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_DMACHANNEL, DmaChannel);
471:
472: if (!NT_SUCCESS(Status)) {
473: return Status;
474: }
475:
476: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INTERRUPT, Interrupt);
477:
478: if (!NT_SUCCESS(Status)) {
479: return Status;
480: }
481:
482: Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INPUTSOURCE, InputSource);
483:
484: if (!NT_SUCCESS(Status)) {
485: return Status;
486: }
487:
488: //
489: // Make sure the config routine sees the data
490: //
491: }
492:
493:
494: VOID
495: SoundSaveVolume(
496: PGLOBAL_DEVICE_INFO pGDI
497: )
498: {
499: NTSTATUS Status;
500:
501: //
502: // Write out left and right volume settings for each device
503: //
504:
505: int i;
506: for (i = 0; i < NumberOfDevices; i++) {
507: PLOCAL_DEVICE_INFO pLDI;
508:
509: if (pGDI->DeviceObject[i]){
510: pLDI = (PLOCAL_DEVICE_INFO)pGDI->DeviceObject[i]->DeviceExtension;
511: SoundSaveDeviceVolume(pLDI, pGDI->RegistryPathName);
512: }
513:
514: }
515:
516: //
517: // Make sure the volume settings make it do disk
518: //
519:
520: SoundFlushRegistryKey(pGDI->RegistryPathName);
521: }
522:
523:
524:
525: NTSTATUS
526: SoundReadConfiguration(
527: IN PWSTR ValueName,
528: IN ULONG ValueType,
529: IN PVOID ValueData,
530: IN ULONG ValueLength,
531: IN PVOID Context,
532: IN PVOID EntryContext
533: )
534: /*++
535:
536: Routine Description :
537:
538: Return configuration information for our device
539:
540: Arguments :
541:
542: ConfigData - where to store the result
543:
544: Return Value :
545:
546: NT status code - STATUS_SUCCESS if no problems
547:
548: --*/
549: {
550: PSB_CONFIG_DATA ConfigData;
551:
552: ConfigData = Context;
553:
554: if (ValueType == REG_DWORD) {
555:
556: if (wcsicmp(ValueName, SOUND_REG_PORT) == 0) {
557: ConfigData->Port = *(PULONG)ValueData;
558: dprintf3(("Read Port Base : %x", ConfigData->Port));
559: }
560:
561: else if (wcsicmp(ValueName, SOUND_REG_INTERRUPT) == 0) {
562: ConfigData->InterruptNumber = *(PULONG)ValueData;
563: dprintf3(("Read Interrupt : %x", ConfigData->InterruptNumber));
564: }
565:
566: else if (wcsicmp(ValueName, SOUND_REG_DMACHANNEL) == 0) {
567: ConfigData->DmaChannel = *(PULONG)ValueData;
568: dprintf3(("Read DMA Channel : %x", ConfigData->DmaChannel));
569: }
570:
571: else if (wcsicmp(ValueName, SOUND_REG_DMABUFFERSIZE) == 0) {
572: ConfigData->DmaBufferSize = *(PULONG)ValueData;
573: dprintf3(("Read DMA Channel : %x", ConfigData->DmaBufferSize));
574: }
575:
576: else if (wcsicmp(ValueName, SOUND_REG_INPUTSOURCE) == 0) {
577: ConfigData->InputSource = *(PULONG)ValueData;
578: dprintf3(("Read Input Source : %s",
579: ConfigData->InputSource == INPUT_LINEIN ? "Line in" :
580: ConfigData->InputSource == INPUT_AUX ? "Aux" :
581: ConfigData->InputSource == INPUT_MIC ? "Microphone" :
582: ConfigData->InputSource == INPUT_OUTPUT ? "Output" :
583: "Invalid input source"
584: ));
585: }
586:
587: else {
588: int i;
589: for (i = 0; i < NumberOfDevices; i++) {
590: if (DeviceInit[i].LeftVolumeName != NULL &&
591: wcsicmp(ValueName, DeviceInit[i].LeftVolumeName) == 0) {
592: ConfigData->Volume[i].Left = *(PULONG)ValueData;
593:
594: dprintf3(("%ls = %8X", DeviceInit[i].LeftVolumeName,
595: ConfigData->Volume[i].Left));
596: break;
597: }
598: if (DeviceInit[i].RightVolumeName != NULL &&
599: wcsicmp(ValueName, DeviceInit[i].RightVolumeName) == 0) {
600: ConfigData->Volume[i].Right = *(PULONG)ValueData;
601:
602: dprintf3(("%ls = %8X", DeviceInit[i].RightVolumeName,
603: ConfigData->Volume[i].Right));
604: break;
605: }
606: }
607: }
608:
609: }
610:
611: return STATUS_SUCCESS;
612: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.