|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: hardware.c
8:
9: Abstract:
10:
11: This module contains code for communicating with the DSP
12: on the Soundblaster card.
13:
14: Author:
15:
16: Nigel Thompson (NigelT) 7-March-1991
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History:
23:
24: Robin Speed (RobinSp) 29-Jan-1992
25: Add MIDI, support for soundblaster 1,
26:
27: --*/
28:
29: #include "sound.h"
30:
31: //
32: // Remove initialization stuff from resident memory
33: //
34:
35: #ifdef ALLOC_PRAGMA
36: #pragma alloc_text(init,HwInitVolume)
37: #pragma alloc_text(init,HwInitialize)
38: #endif
39:
40:
41: UCHAR
42: dspRead(
43: IN PSOUND_HARDWARE pHw
44: )
45: /*++
46:
47: Routine Description:
48:
49: Read the DSP data port
50: Time out occurs after about 1ms
51:
52: Arguments:
53:
54: pHw - Pointer to the device extension data.
55: pvalue - Pointer to the UCHAR to receive the result
56:
57: Return Value:
58:
59: Value read
60:
61: --*/
62: {
63: USHORT uCount;
64: UCHAR Value;
65:
66: ASSERT(pHw->Key == HARDWARE_KEY);
67:
68: uCount = 100;
69:
70: Value = 0xFF; // If fail look like port not populated
71:
72: while (uCount--) {
73: int InnerCount;
74:
75: //
76: // Protect all reads and writes with a spin lock
77: //
78:
79: HwEnter(pHw);
80:
81: //
82: // Inner count loop protects against dynamic deadlock with
83: // midi.
84: //
85:
86: for (InnerCount = 0; InnerCount < 10; InnerCount++) {
87: if (INPORT(pHw, DATA_AVAIL_PORT) & 0x80) {
88: Value = INPORT(pHw, DATA_PORT);
89: uCount = 0;
90: break;
91: }
92: KeStallExecutionProcessor(1);
93: }
94:
95: HwLeave(pHw);
96: }
97: // timed out
98:
99: return Value;
100: }
101:
102:
103:
104: BOOLEAN
105: dspReset(
106: PSOUND_HARDWARE pHw
107: )
108: /*++
109:
110: Routine Description:
111:
112: Reset the DSP
113:
114: Arguments:
115:
116: pHw - pointer to the device extension data
117:
118: Return Value:
119:
120: The return value is TRUE if the dsp was reset, FALSE if an error
121: occurred.
122:
123: --*/
124: {
125: //
126: // When we reset we'll lose the format information so initialize it
127: // now. Also the speaker is nominally OFF after reset.
128: //
129:
130: pHw->Format = 0;
131: pHw->SpeakerOn = FALSE;
132:
133: //
134: // try for a reset - note that midi output may be running at this
135: // point so we need the spin lock while we're trying to reset
136: //
137:
138: HwEnter(pHw);
139:
140: OUTPORT(pHw, RESET_PORT, 1);
141: KeStallExecutionProcessor(3); // wait 3 us
142: OUTPORT(pHw, RESET_PORT, 0);
143:
144: HwLeave(pHw);
145:
146: // we should get 0xAA at the data port now
147:
148: if (dspRead(pHw) != 0xAA) {
149:
150: //
151: // timed out or other screw up
152: //
153:
154: // dprintf1(("Failed to reset DSP"));
155: return FALSE;
156: }
157: return TRUE;
158: }
159:
160:
161: BOOLEAN
162: dspWrite(
163: PSOUND_HARDWARE pHw,
164: UCHAR value
165: )
166: /*++
167:
168: Routine Description:
169:
170: Write a command or data to the DSP
171:
172: Arguments:
173:
174: pHw - Pointer to the device extension data
175: value - the value to be written
176:
177: Return Value:
178:
179: TRUE if written correctly , FALSE otherwise
180:
181: --*/
182: {
183: ULONG uCount;
184:
185: ASSERT(pHw->Key == HARDWARE_KEY);
186:
187: uCount = 100;
188:
189: while (uCount--) {
190: int InnerCount;
191:
192: HwEnter(pHw);
193:
194: //
195: // Inner count loop protects against dynamic deadlock with
196: // midi.
197: //
198:
199: for (InnerCount = 0; InnerCount < 10; InnerCount++) {
200: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) {
201: OUTPORT(pHw, DATA_STATUS_PORT, value);
202: break;
203: }
204: KeStallExecutionProcessor(1); // 1 us
205: }
206:
207: HwLeave(pHw);
208:
209: if (InnerCount < 10) {
210: return TRUE;
211: }
212: }
213:
214: dprintf1(("Failed to write %x to dsp", (ULONG)value));
215:
216: return FALSE;
217: }
218:
219: BOOLEAN
220: dspWriteNoLock(
221: PSOUND_HARDWARE pHw,
222: UCHAR value
223: )
224: /*++
225:
226: Routine Description:
227:
228: Write a command or data to the DSP. The call assumes the
229: caller has acquired the spin lock
230:
231: Arguments:
232:
233: pHw - Pointer to the device extension data
234: value - the value to be written
235:
236: Return Value:
237:
238: TRUE if written correctly , FALSE otherwise
239:
240: --*/
241: {
242: int uCount;
243:
244: ASSERT(pHw->Key == HARDWARE_KEY);
245:
246: uCount = 1000;
247:
248: while (uCount--) {
249: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) {
250: OUTPORT(pHw, DATA_STATUS_PORT, value);
251: break;
252: }
253: KeStallExecutionProcessor(1); // 1 us
254: }
255:
256: if (uCount >= 0) {
257: return TRUE;
258: }
259:
260: dprintf1(("Failed to write %x to dsp", (ULONG)value));
261:
262: return FALSE;
263: }
264:
265:
266:
267: USHORT
268: dspGetVersion(
269: PSOUND_HARDWARE pHw
270: )
271: /*++
272:
273: Routine Description:
274:
275: Get the DSP software version
276:
277: Arguments:
278:
279: pHw - pointer to the hardware data
280:
281: Return Value:
282:
283: The return value contains the major version in the high byte
284: and the minor version in the low byte. If an error occurs
285: then the return value is zero.
286:
287: --*/
288: {
289: UCHAR major, minor;
290:
291: // we have a card, try to read the version number
292:
293: if (dspWrite(pHw, DSP_GET_VERSION)) {
294: major = dspRead(pHw);
295: minor = dspRead(pHw);
296: return (((USHORT)major) << 8) + (USHORT)minor;
297: }
298: return 0;
299: }
300:
301:
302: BOOLEAN
303: dspSpeakerOn(
304: PSOUND_HARDWARE pHw
305: )
306: /*++
307:
308: Routine Description:
309:
310: Turn the speaker on
311:
312: Arguments:
313:
314: pHw - pointer to the device extension data
315:
316: Return Value:
317:
318: TRUE
319:
320: --*/
321: {
322: int i;
323:
324: if (!pHw->SpeakerOn) {
325:
326: //
327: // Thunderboard likes a gap
328: //
329:
330: KeStallExecutionProcessor(100);
331:
332: dspWrite(pHw, DSP_SPEAKER_ON);
333: pHw->SpeakerOn = TRUE;
334:
335: //
336: // Now wait until it's OK again (up to 112 ms)
337: //
338:
339: for (i = 0; i < 3; i++) {
340: SoundDelay(38);
341: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) {
342: break;
343: }
344: }
345:
346: dprintf4(("Waited %d ms for speaker to go on", i * 38));
347: }
348: return TRUE;
349: }
350:
351:
352: BOOLEAN
353: dspSpeakerOff(
354: PSOUND_HARDWARE pHw
355: )
356: /*++
357:
358: Routine Description:
359:
360: Turn the speaker on
361:
362: Arguments:
363:
364: pHw - pointer to the device extension data
365:
366: Return Value:
367:
368: TRUE
369:
370: --*/
371: {
372: int i;
373:
374: if (pHw->SpeakerOn) {
375: dspWrite(pHw, DSP_SPEAKER_OFF);
376: pHw->SpeakerOn = FALSE;
377:
378: //
379: // Now wait until it's OK again (up to 225 ms)
380: //
381:
382: for (i = 0; i < 6; i++) {
383: SoundDelay(38);
384: if (!(INPORT(pHw, DATA_STATUS_PORT) & 0x80)) {
385: break;
386: }
387: }
388:
389: dprintf4(("Waited %d ms for speaker to go off", i * 38));
390: }
391: return TRUE;
392: }
393:
394:
395:
396: BOOLEAN
397: dspSetSampleRate(
398: PSOUND_HARDWARE pHw,
399: ULONG rate
400: )
401: /*++
402:
403: Routine Description:
404:
405: Set the current dsp sample rate.
406: Note that this routine must only be called when a new transfer
407: is being set up or as a new packet is being set up.
408:
409: Arguments:
410:
411: pHw - pointer to the device extension data
412: rate - the sample rate to set in samples per second
413:
414: Return Value:
415:
416: TRUE if success, FALSE otherwise
417:
418: --*/
419: {
420: ULONG TimeFactor;
421:
422: //
423: // the card only does 4kHz up
424: //
425:
426: if (rate < 4000) {
427: dprintf1(("Attempt to set bogus DSP rate (%lu)", rate));
428: return FALSE;
429: }
430:
431: //
432: // Compute the timing factor as 256 - 1000000 / rate
433: // For 4kHz this is 6, for 23kHz it is 212.
434: //
435:
436: TimeFactor = 256 - (1000000 / rate);
437:
438: if ((UCHAR)TimeFactor != pHw->Format) {
439:
440: if (!dspWrite(pHw, DSP_SET_SAMPLE_RATE)) {
441: return FALSE;
442: }
443:
444: KeStallExecutionProcessor(10);
445: dspWrite(pHw, (UCHAR) TimeFactor);
446:
447: pHw->Format = (UCHAR)TimeFactor;
448:
449: return TRUE;
450: } else {
451: //
452: // No change
453: //
454:
455: return FALSE;
456: }
457: }
458:
459:
460: BOOLEAN
461: dspStartAutoDMA(
462: PSOUND_HARDWARE pHw,
463: ULONG Size,
464: BOOLEAN Direction
465: )
466: /*++
467:
468: Routine Description:
469:
470: This routine begins the output of a new set of dma
471: transfers. It sets up the dsp sample rate and
472: then programs the dsp to start making dma requests.
473: This routine completes the action started by
474: sndProgramOutputDMA
475:
476: Arguments:
477:
478: pHw - Pointer to global device data
479:
480: Return Value:
481:
482: TRUE if operation is sucessful, FALSE otherwise
483:
484: --*/
485: {
486: ULONG SampleRate;
487:
488: //
489: // Program the DSP to start the transfer by sending the
490: // block size command followed by the low
491: // byte and then the high byte of the block size - 1.
492: // Then send the start auto-init command.
493: // Note that the block size is half the dma buffer size.
494: //
495:
496: dspWrite(pHw, DSP_SET_BLOCK_SIZE);
497: dspWrite(pHw, (UCHAR)((Size/2 - 1) & 0x00FF));
498: dspWrite(pHw, (UCHAR)(((Size/2 - 1) >> 8) & 0x00FF));
499: if (!Direction) {
500: dspWrite(pHw, DSP_READ_AUTO);
501: } else {
502: dspWrite(pHw, DSP_WRITE_AUTO);
503: }
504: dprintf3(("DMA started"));
505:
506: //
507: // Return the power fail status
508: // BUGBUG Power fail status bogus
509: //
510:
511: return TRUE;
512: }
513:
514:
515: BOOLEAN
516: dspStartNonAutoDMA(
517: PSOUND_HARDWARE pHw,
518: ULONG Size,
519: BOOLEAN Direction
520: )
521: /*++
522:
523: Routine Description:
524:
525: This routine begins the output of a new set of dma
526: transfers. It sets up the dsp sample rate and
527: then programs the dsp to start making dma requests.
528: This routine completes the action started by
529: sndProgramOutputDMA.
530:
531: Soundblaster 1 only
532:
533: Arguments:
534:
535: pHw - Pointer to global device data
536:
537: Return Value:
538:
539: TRUE if operation is sucessful, FALSE otherwise
540:
541: --*/
542: {
543: ULONG SampleRate;
544:
545: //
546: // Program the DSP to start the transfer by sending the
547: // Read/Write command followed by the low
548: // byte and then the high byte of the block size - 1.
549: // Note that the block size is half the dma buffer size.
550: //
551:
552: if (!Direction) {
553: dspWrite(pHw, DSP_READ);
554: } else {
555: dspWrite(pHw, DSP_WRITE);
556: }
557: dspWrite(pHw, (UCHAR)((Size/2 - 1) & 0x00FF));
558: dspWrite(pHw, (UCHAR)(((Size/2 - 1) >> 8) & 0x00FF));
559: dprintf3(("DMA started"));
560:
561: //
562: // Initialize half we're doing next
563: //
564:
565: pHw->Half = UpperHalf;
566:
567: //
568: // Return the power fail status
569: // BUGBUG Power fail status bogus
570: //
571:
572: return TRUE;
573: }
574:
575: VOID
576: HwSetVolume(
577: IN PLOCAL_DEVICE_INFO pLDI
578: )
579: /*++
580:
581: Routine Description :
582:
583: Set the volume for the specified device
584:
585: Arguments :
586:
587: pLDI - pointer to device data
588:
589: Return Value :
590:
591: None
592:
593: --*/
594: {
595: PSOUND_HARDWARE pHw;
596: ULONG PortIndex;
597: WAVE_DD_VOLUME Volume;
598: PGLOBAL_DEVICE_INFO pGDI;
599:
600:
601: pHw = pLDI->HwContext;
602: Volume = pLDI->Volume;
603: pGDI = CONTAINING_RECORD(pHw, GLOBAL_DEVICE_INFO, Hw);
604:
605: #ifdef PAS16 // There's a proper driver now
606: if (pGDI->ProAudioSpectrum) {
607: UCHAR OutputMixer;
608: UCHAR InputNumber;
609:
610: switch (pLDI->DeviceIndex) {
611: #ifdef MICMIX
612: case MicDevice:
613: InputNumber = IN_MICROPHONE;
614: OutputMixer = OUT_PCM;
615: break;
616: #endif // MICMIX
617:
618: case LineInDevice:
619: InputNumber = IN_EXTERNAL;
620: OutputMixer = OUT_AMPLIFIER; //OUT_PCM;
621: break;
622:
623: case WaveOutDevice:
624: InputNumber = IN_SNDBLASTER;
625: OutputMixer = OUT_AMPLIFIER;
626: break;
627: }
628:
629: SetInput(&pGDI->PASInfo,
630: InputNumber,
631: (USHORT)(Volume.Left >> 16),
632: _LEFT,
633: MIXCROSSCAPS_NORMAL_STEREO,
634: OutputMixer);
635: SetInput(&pGDI->PASInfo,
636: InputNumber,
637: (USHORT)(Volume.Right >> 16),
638: _RIGHT,
639: MIXCROSSCAPS_NORMAL_STEREO,
640: OutputMixer);
641: } else
642: #endif // PAS16
643:
644: {
645:
646: //
647: // Only the 'pro' supports the mixer
648: //
649: if (!SBPRO(pHw)) {
650: return;
651: }
652:
653: //
654: // Find which mixer register to set
655: //
656:
657: switch (pLDI->DeviceIndex) {
658: #ifdef MICMIX
659: case MicDevice:
660: Volume.Right = Volume.Left;// Mono for this one
661: Volume.Left = 0;
662: PortIndex = MIC_MIX_REG;
663: break;
664: #endif // MICMIX
665:
666: case WaveOutDevice:
667: PortIndex = VOICE_VOL_REG;
668: break;
669:
670: case LineInDevice:
671: PortIndex = LINEIN_VOL_REG;
672: break;
673: }
674:
675: //
676: // Mutual exclusion is guaranteed by holding the device mutex
677: // (note that midi output does not have a volume control on the mixer).
678: //
679:
680: //
681: // Select voice control reg
682: //
683: OUTPORT(pHw, MIX_ADDR_PORT, (UCHAR)PortIndex);
684:
685: KeStallExecutionProcessor(10);
686:
687: //
688: // Set the volume
689: //
690: OUTPORT(pHw, MIX_DATA_PORT,
691: ((Volume.Left >> 24) & 0xF0) |
692: (Volume.Right >> 28));
693:
694: KeStallExecutionProcessor(10);
695: }
696: }
697:
698: VOID
699: HwInitVolume(
700: IN PGLOBAL_DEVICE_INFO pGDI
701: )
702: /*++
703:
704: Routine Description :
705:
706: Initialise volume settings on the hardware. Called at start-up
707: to initialise to max volume the mixer line for the midi synthesizer
708: (since volume for the synth is controlled by the synth driver itself
709: modifying the instrument parameters).
710:
711: Arguments :
712:
713: pGDI - pointer to device data
714:
715: Return Value :
716:
717: None
718:
719: --*/
720: {
721: PSOUND_HARDWARE pHw;
722:
723:
724: pHw = &pGDI->Hw;
725:
726: if (!pGDI->ProAudioSpectrum) {
727:
728: //
729: // Only the 'pro' supports the mixer
730: //
731: if (!SBPRO(pHw)) {
732: return;
733: }
734:
735:
736: //
737: // Select voice control reg
738: //
739: OUTPORT(pHw, MIX_ADDR_PORT, (UCHAR)SYNTH_VOL_REG);
740:
741: KeStallExecutionProcessor(10);
742:
743: //
744: // Set the volume to maximum
745: //
746: OUTPORT(pHw, MIX_DATA_PORT, 0xFF);
747:
748: KeStallExecutionProcessor(10);
749: }
750: }
751:
752: BOOLEAN
753: HwSetupDMA(
754: IN PWAVE_INFO WaveInfo
755: )
756: /*++
757:
758: Routine Description :
759:
760: Start the DMA on the device according to the device parameters
761:
762: Arguments :
763:
764: WaveInfo - Wave parameters
765:
766: Return Value :
767:
768: None
769:
770: --*/
771: {
772: PSOUND_HARDWARE pHw;
773:
774: pHw = WaveInfo->HwContext;
775:
776: //
777: // Turn the speaker off for input
778: //
779:
780: if (!WaveInfo->Direction) {
781: dspSpeakerOff(pHw);
782: } else {
783: //
784: // This would not normally be necessary but when the DMA
785: // gets locked out by the SCSI horrible things happen so
786: // we turn on the speaker here. Normally the flag will
787: // stop us actually turning it on
788: //
789:
790: dspSpeakerOn(pHw);
791: }
792:
793: //
794: // Do different things depending on the type of card
795: // Sound blaster 1 cannot use auto-init DMA whereas all
796: // the others can
797: //
798:
799: if (SB1(pHw)) {
800: dspStartNonAutoDMA(pHw, WaveInfo->DoubleBuffer.BufferSize,
801: WaveInfo->Direction);
802: } else {
803: dspStartAutoDMA(pHw, WaveInfo->DoubleBuffer.BufferSize,
804: WaveInfo->Direction);
805: }
806:
807: return TRUE;
808: }
809:
810: BOOLEAN
811: HwStopDMA(
812: IN PWAVE_INFO WaveInfo
813: )
814: /*++
815:
816: Routine Description :
817:
818: Stop the DMA on the device according to the device parameters
819:
820: Arguments :
821:
822: WaveInfo - Wave parameters
823:
824: Return Value :
825:
826: None
827:
828: --*/
829: {
830: PSOUND_HARDWARE pHw;
831: BOOLEAN Rc;
832:
833: pHw = WaveInfo->HwContext;
834:
835: Rc = dspWrite(pHw, DSP_HALT_DMA);
836:
837: if (!Rc) {
838: //
839: // Resetting then setting the speaker on seems to be the only
840: // way to recover!
841: //
842:
843: dspReset(pHw);
844:
845: //
846: // The speaker is off after reset. The next time we play
847: // something we'll call dspSpeakerOn which will turn it on.
848: //
849: }
850:
851: if (!WaveInfo->Direction) {
852: dspSpeakerOn(pHw);
853: }
854:
855: return Rc;
856: }
857:
858: BOOLEAN
859: HwSetWaveFormat(
860: IN PWAVE_INFO WaveInfo
861: )
862: /*++
863:
864: Routine Description :
865:
866: Set device parameters for wave input/output
867:
868: Arguments :
869:
870: WaveInfo - Wave parameters
871:
872: Return Value :
873:
874: None
875:
876: --*/
877: {
878: PSOUND_HARDWARE pHw;
879: UCHAR Format;
880: BOOLEAN Different;
881:
882: Different = FALSE;
883:
884: pHw = WaveInfo->HwContext;
885:
886: //
887: // For the PRO select stereo if requested
888: //
889:
890: if (SBPRO(pHw)) {
891: if ((BOOLEAN)(WaveInfo->Channels > 1) != pHw->Stereo) {
892: UCHAR OutputSetting;
893:
894: Different = TRUE;
895: pHw->Stereo = (BOOLEAN)(WaveInfo->Channels > 1);
896:
897: //
898: // Set the output setting register
899: //
900:
901: OUTPORT(pHw, MIX_ADDR_PORT, OUTPUT_SETTING_REG);
902:
903: KeStallExecutionProcessor(10);
904:
905: OutputSetting = INPORT(pHw, MIX_DATA_PORT) & ~0x02;
906: if (pHw->Stereo) {
907: OutputSetting |= 0x02;
908: }
909:
910: OUTPORT(pHw, MIX_DATA_PORT, OutputSetting);
911:
912: KeStallExecutionProcessor(10);
913: }
914: } else {
915: ASSERT(WaveInfo->Channels == 1);
916: }
917:
918: //
919: // Set the actual format
920: //
921:
922: return dspSetSampleRate(pHw, WaveInfo->SamplesPerSec) || Different;
923: }
924:
925: BOOLEAN
926: HwStartMidiIn(
927: IN PMIDI_INFO MidiInfo
928: )
929: /*++
930:
931: Routine Description :
932:
933: Start midi recording
934:
935: Arguments :
936:
937: MidiInfo - Midi parameters
938:
939: Return Value :
940:
941: None
942:
943: --*/
944: {
945: PSOUND_HARDWARE pHw;
946:
947: pHw = MidiInfo->HwContext;
948:
949: //
950: // Write start midi input to device
951: //
952:
953: if (SB1(pHw)) {
954: return dspWrite(pHw, DSP_MIDI_READ);
955: } else {
956: return dspWrite(pHw, DSP_MIDI_READ_UART);
957: }
958: }
959:
960: BOOLEAN
961: HwStopMidiIn(
962: IN PMIDI_INFO MidiInfo
963: )
964: /*++
965:
966: Routine Description :
967:
968: Stop midi recording
969:
970: Arguments :
971:
972: MidiInfo - Midi parameters
973:
974: Return Value :
975:
976: None
977:
978: --*/
979: {
980: PSOUND_HARDWARE pHw;
981:
982: pHw = MidiInfo->HwContext;
983:
984: if (SB1(pHw)) {
985: //
986: // Start = stop in this case
987: //
988:
989: HwStartMidiIn(MidiInfo);
990: } else {
991: //
992: // The only way to stop is to reset the DSP
993: // Note that this is called only by the app so
994: // output cannot be going on at this time (because we
995: // have the device mutex).
996: //
997:
998: dspReset(pHw);
999: dspSpeakerOn(pHw);
1000: }
1001:
1002: return TRUE;
1003: }
1004:
1005: BOOLEAN
1006: HwMidiRead(
1007: IN PMIDI_INFO MidiInfo,
1008: OUT PUCHAR Byte
1009: )
1010: /*++
1011:
1012: Routine Description :
1013:
1014: Read a midi byte from the recording
1015:
1016: Arguments :
1017:
1018: MidiInfo - Midi parameters
1019:
1020: Return Value :
1021:
1022: None
1023:
1024: --*/
1025: {
1026: PSOUND_HARDWARE pHw;
1027:
1028: pHw = MidiInfo->HwContext;
1029:
1030: if (INPORT(pHw, DATA_AVAIL_PORT) & 0x80) {
1031: *Byte = INPORT(pHw, DATA_PORT);
1032: return TRUE;
1033: } else {
1034: return FALSE;
1035: }
1036:
1037: }
1038:
1039:
1040: VOID
1041: HwMidiOut(
1042:
1043: IN PMIDI_INFO MidiInfo,
1044: IN PUCHAR Bytes,
1045: IN int Count
1046: )
1047: /*++
1048:
1049: Routine Description :
1050:
1051: Write a midi byte to the output
1052:
1053: Arguments :
1054:
1055: MidiInfo - Midi parameters
1056:
1057: Return Value :
1058:
1059: None
1060:
1061: --*/
1062: {
1063: PSOUND_HARDWARE pHw;
1064: PGLOBAL_DEVICE_INFO pGDI;
1065: int i, j;
1066:
1067: pHw = MidiInfo->HwContext;
1068: pGDI = CONTAINING_RECORD(pHw, GLOBAL_DEVICE_INFO, Hw);
1069:
1070: //
1071: // Loop sending data to device. Synchronize with wave and midi input
1072: // using the DeviceMutex for everything except the Dpc
1073: // routine for which we use the wave output spin lock
1074: //
1075:
1076: while (Count > 0) {
1077: //
1078: // Synchronize with everything except Dpc routines
1079: // (Note we don't use this for the whole of the output
1080: // because we don't want wave output to be held off
1081: // while we output thousands of Midi bytes, but we
1082: // then need to synchronize access to the midi output
1083: // which we do with the MidiMutex
1084: //
1085:
1086: KeWaitForSingleObject(&pGDI->DeviceMutex,
1087: Executive,
1088: KernelMode,
1089: FALSE, // Not alertable
1090: NULL);
1091:
1092: for (i = 0; i < 20; i++) {
1093: //
1094: // If input is active we don't need to specify MIDI write
1095: // for version 2 or later (can't be overlapped anyway for
1096: // version 1 so the extra test is unnecessary).
1097: //
1098:
1099: if (MidiInfo->fMidiInStarted) {
1100: ASSERT(!SB1(pHw));
1101: dspWrite(pHw, Bytes[0]);
1102:
1103: //
1104: // Apparently we have to wait 400 us in this case
1105: //
1106:
1107: KeStallExecutionProcessor(400);
1108: } else {
1109: UCHAR Byte = Bytes[0]; // Don't take an exception while
1110: // we hold the spin lock!
1111:
1112: //
1113: // We don't want to hold on to the spin lock for too
1114: // long and since we can only send out 4 bytes per ms
1115: // we are rather slow. Hence wait until the device
1116: // is ready before entering the spin lock
1117: //
1118:
1119: {
1120: int j;
1121: for (j = 0; j < 250; j++) {
1122: if (INPORT(pHw, DATA_STATUS_PORT) & 0x80) {
1123: KeStallExecutionProcessor(1);
1124: } else {
1125: break;
1126: }
1127: }
1128: }
1129:
1130: //
1131: // Synch with any Dpc routines. This requires that
1132: // any write sequences done in a Dpc routine also
1133: // hold the spin lock over all the writes.
1134: //
1135:
1136: HwEnter(pHw);
1137: dspWriteNoLock(pHw, DSP_MIDI_WRITE);
1138: dspWriteNoLock(pHw, Byte);
1139: HwLeave(pHw);
1140: }
1141:
1142: //
1143: // Move on to next byte
1144: //
1145:
1146: Bytes++;
1147: if (--Count == 0) {
1148: break;
1149: }
1150: }
1151: KeReleaseMutex(&pGDI->DeviceMutex, FALSE);
1152: }
1153:
1154: }
1155:
1156:
1157: VOID
1158: HwInitialize(
1159: IN OUT PGLOBAL_DEVICE_INFO pGDI
1160: )
1161: /*++
1162:
1163: Routine Description :
1164:
1165: Write hardware routine addresses into global device data
1166:
1167: Arguments :
1168:
1169: pGDI - global data
1170:
1171: Return Value :
1172:
1173: None
1174:
1175: --*/
1176: {
1177: PWAVE_INFO WaveInfo;
1178: PMIDI_INFO MidiInfo;
1179: PSOUND_HARDWARE pHw;
1180:
1181: pHw = &pGDI->Hw;
1182: WaveInfo = &pGDI->WaveInfo;
1183: MidiInfo = &pGDI->MidiInfo;
1184:
1185: pHw->Key = HARDWARE_KEY;
1186:
1187: KeInitializeSpinLock(&pHw->HwSpinLock);
1188:
1189:
1190: //
1191: // Install Wave and Midi routine addresses
1192: //
1193:
1194: WaveInfo->HwContext = pHw;
1195: WaveInfo->HwSetupDMA = HwSetupDMA;
1196: WaveInfo->HwStopDMA = HwStopDMA;
1197: WaveInfo->HwSetWaveFormat = HwSetWaveFormat;
1198:
1199: MidiInfo->HwContext = pHw;
1200: MidiInfo->HwStartMidiIn = HwStartMidiIn;
1201: MidiInfo->HwStopMidiIn = HwStopMidiIn;
1202: MidiInfo->HwMidiRead = HwMidiRead;
1203: MidiInfo->HwMidiOut = HwMidiOut;
1204: }
1205:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.