|
|
1.1 root 1: /*
2: * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
3: */
4:
5: #import "ProAudioSpectrum16Registers.h"
6: #import <driverkit/i386/ioPorts.h>
7: #import <driverkit/generalFuncs.h>
8:
9: static inline
10: void
11: setBaseAddress(unsigned int baseAddress)
12: {
13: /*
14: * To relocate the I/O addresses, two 8-bit values are written to the
15: * Master Address Pointer (0x9a01):
16: * (1) board ID value (valid settings are 0xbc-0xbf)
17: * (2) base address shifted right by two positions
18: */
19: outb(MASTER_ADDRESS_POINTER, FIRST_BOARD_ID);
20: outb(MASTER_ADDRESS_POINTER, (baseAddress) >> 2);
21: }
22:
23: static inline
24: filterControl_t
25: getFilterControl()
26: {
27: union {
28: filterControl_t reg;
29: unsigned char data;
30: } filterControl;
31:
32: filterControl.data = inb(FILTER_CONTROL);
33:
34: return (filterControl.reg);
35: }
36:
37: static inline
38: void
39: setFilterControl(filterControl_t reg)
40: {
41: union {
42: filterControl_t reg;
43: unsigned char data;
44: } filterControl;
45:
46: filterControl.reg = reg;
47:
48: outb(FILTER_CONTROL, filterControl.data);
49: }
50:
51: static inline
52: void
53: enableAudioOutput(boolean_t enable)
54: {
55: filterControl_t filterControl = {0};
56:
57: filterControl = getFilterControl();
58: filterControl.enableAudioOutput = enable;
59: setFilterControl(filterControl);
60: }
61:
62: static inline
63: interruptControl_t
64: getInterruptControl()
65: {
66: union {
67: interruptControl_t reg;
68: unsigned char data;
69: } interruptControl;
70:
71: interruptControl.data = inb(INTERRUPT_CONTROL);
72:
73: return (interruptControl.reg);
74: }
75:
76: static inline
77: void
78: setInterruptControl(interruptControl_t reg)
79: {
80: union {
81: interruptControl_t reg;
82: unsigned char data;
83: } interruptControl;
84:
85: interruptControl.reg = reg;
86:
87: outb(INTERRUPT_CONTROL, interruptControl.data);
88: }
89:
90: static inline
91: interruptStatus_t
92: getInterruptStatus()
93: {
94: union {
95: interruptStatus_t reg;
96: unsigned char data;
97: } interruptStatus;
98:
99: interruptStatus.data = inb(INTERRUPT_STATUS);
100:
101: return (interruptStatus.reg);
102: }
103:
104: static inline
105: void
106: setInterruptStatus(interruptStatus_t reg)
107: {
108: union {
109: interruptStatus_t reg;
110: unsigned char data;
111: } interruptStatus;
112:
113: interruptStatus.reg = reg;
114:
115: outb(INTERRUPT_STATUS, interruptStatus.data);
116: }
117:
118: static inline
119: crossChannelControl_t
120: getCrossChannelControl()
121: {
122: union {
123: crossChannelControl_t reg;
124: unsigned char data;
125: } crossChannelControl;
126:
127: crossChannelControl.data = inb(CROSS_CHANNEL_CONTROL);
128:
129: return (crossChannelControl.reg);
130: }
131:
132: static inline
133: void
134: setCrossChannelControl(crossChannelControl_t reg)
135: {
136: union {
137: crossChannelControl_t reg;
138: unsigned char data;
139: } crossChannelControl;
140:
141: crossChannelControl.reg = reg;
142:
143: outb(CROSS_CHANNEL_CONTROL, crossChannelControl.data);
144: }
145:
146: static inline
147: sampleCounterControl_t
148: getSampleCounterControl()
149: {
150: union {
151: sampleCounterControl_t reg;
152: unsigned char data;
153: } sampleCounterControl;
154:
155: sampleCounterControl.data = inb(SAMPLE_COUNTER_CONTROL);
156:
157: return (sampleCounterControl.reg);
158: }
159:
160: static inline
161: void
162: setSampleCounterControl(sampleCounterControl_t reg)
163: {
164: union {
165: sampleCounterControl_t reg;
166: unsigned char data;
167: } sampleCounterControl;
168:
169: sampleCounterControl.reg = reg;
170:
171: outb(SAMPLE_COUNTER_CONTROL, sampleCounterControl.data);
172: }
173:
174: static inline
175: systemConfiguration1_t
176: getSystemConfiguration1()
177: {
178: union {
179: systemConfiguration1_t reg;
180: unsigned char data;
181: } systemConfiguration1;
182:
183: systemConfiguration1.data = inb(SYSTEM_CONFIGURATION_1);
184:
185: return (systemConfiguration1.reg);
186: }
187:
188: static inline
189: void
190: setSystemConfiguration1(systemConfiguration1_t reg)
191: {
192: union {
193: systemConfiguration1_t reg;
194: unsigned char data;
195: } systemConfiguration1;
196:
197: systemConfiguration1.reg = reg;
198:
199: outb(SYSTEM_CONFIGURATION_1, systemConfiguration1.data);
200: }
201:
202: static inline
203: systemConfiguration2_t
204: getSystemConfiguration2()
205: {
206: union {
207: systemConfiguration2_t reg;
208: unsigned char data;
209: } systemConfiguration2;
210:
211: systemConfiguration2.data = inb(SYSTEM_CONFIGURATION_2);
212:
213: return (systemConfiguration2.reg);
214: }
215:
216: static inline
217: void
218: setSystemConfiguration2(systemConfiguration2_t reg)
219: {
220: union {
221: systemConfiguration2_t reg;
222: unsigned char data;
223: } systemConfiguration2;
224:
225: systemConfiguration2.reg = reg;
226:
227: outb(SYSTEM_CONFIGURATION_2, systemConfiguration2.data);
228: }
229:
230: static inline
231: DMAChannelConfiguration_t
232: getDMAChannelConfiguration()
233: {
234: union {
235: DMAChannelConfiguration_t reg;
236: unsigned char data;
237: } DMAChannelConfiguration;
238:
239: DMAChannelConfiguration.data = inb(DMA_CHANNEL_CONFIGURATION);
240:
241: return (DMAChannelConfiguration.reg);
242: }
243:
244: static inline
245: void
246: setDMAChannelConfiguration(DMAChannelConfiguration_t reg)
247: {
248: union {
249: DMAChannelConfiguration_t reg;
250: unsigned char data;
251: } DMAChannelConfiguration;
252:
253: DMAChannelConfiguration.reg = reg;
254:
255: outb(DMA_CHANNEL_CONFIGURATION, DMAChannelConfiguration.data);
256: }
257:
258: static inline
259: boolean_t
260: setDMAChannel(int channel)
261: {
262: static DMAChannelConfiguration_t DMAChannelConfiguration = {0};
263: static const unsigned char DMAMap[] = {
264: DMA_CHANNEL_0,
265: DMA_CHANNEL_1,
266: DMA_CHANNEL_2,
267: DMA_CHANNEL_3,
268: DMA_CHANNEL_NONE,
269: DMA_CHANNEL_5,
270: DMA_CHANNEL_6,
271: DMA_CHANNEL_7,
272: };
273:
274: if (DMAMap[channel] == DMA_CHANNEL_NONE)
275: return FALSE;
276:
277: DMAChannelConfiguration.channel = DMAMap[channel];
278: setDMAChannelConfiguration(DMAChannelConfiguration);
279: return TRUE;
280:
281: }
282:
283: static inline
284: IRQConfiguration_t
285: getIRQConfiguration()
286: {
287: union {
288: IRQConfiguration_t reg;
289: unsigned char data;
290: } IRQConfiguration;
291:
292: IRQConfiguration.data = inb(IRQ_CONFIGURATION);
293:
294: return (IRQConfiguration.reg);
295: }
296:
297: static inline
298: void
299: setIRQConfiguration(IRQConfiguration_t reg)
300: {
301: union {
302: IRQConfiguration_t reg;
303: unsigned char data;
304: } IRQConfiguration;
305:
306: IRQConfiguration.reg = reg;
307:
308: outb(IRQ_CONFIGURATION, IRQConfiguration.data);
309: }
310:
311: static inline
312: boolean_t
313: setInterrupt(int interrupt)
314: {
315:
316: static IRQConfiguration_t IRQConfiguration = {0};
317: static const unsigned char IRQMap[] = {
318: INTERRUPT_NONE,
319: INTERRUPT_NONE,
320: INTERRUPT_2,
321: INTERRUPT_3,
322: INTERRUPT_4,
323: INTERRUPT_5,
324: INTERRUPT_6,
325: INTERRUPT_7,
326: INTERRUPT_NONE,
327: INTERRUPT_NONE,
328: INTERRUPT_10,
329: INTERRUPT_11,
330: INTERRUPT_12,
331: INTERRUPT_NONE,
332: INTERRUPT_14,
333: INTERRUPT_15
334: };
335:
336: if (IRQMap[interrupt] == INTERRUPT_NONE)
337: return FALSE;
338:
339: IRQConfiguration.interrupt = IRQMap[interrupt];
340: setIRQConfiguration(IRQConfiguration);
341: return TRUE;
342: }
343:
344:
345: static inline
346: void
347: setMasterOutputAttenuation(u_int channel, masterAttenuation_t attenuation)
348: {
349: union {
350: channelSelection_t reg;
351: unsigned char data;
352: } channelSelection;
353:
354: // avoid a warning
355: channelSelection.data = 0;
356:
357: // select the master A mixer
358: channelSelection.reg.selectAddress = MIXER_A_MASTER;
359: channelSelection.reg.selectChannel = channel;
360: channelSelection.reg.isTransfer = TRUE;
361:
362: outb(MIXER_CONTROL, channelSelection.data);
363:
364: // set the attenuation
365: outb(MIXER_CONTROL, (char)attenuation);
366: }
367:
368: static inline
369: void
370: setOutputAttenuation(u_int address, u_int channel, u_int attenuation)
371: {
372:
373: union {
374: channelSelection_t reg;
375: unsigned char data;
376: } channelSelection;
377:
378: union {
379: channelAttenuation_t reg;
380: unsigned char data;
381: } channelAttenuation;
382:
383: // avoid a warning
384: channelSelection.data = 0;
385: channelAttenuation.data = 0;
386:
387: channelSelection.reg.selectAddress = address;
388: channelSelection.reg.selectChannel = channel;
389: channelSelection.reg.isTransfer = TRUE;
390: outb(MIXER_CONTROL, channelSelection.data);
391:
392: channelAttenuation.reg.attenuation = attenuation;
393: channelAttenuation.reg.routeChannel = MIXER_A_ROUTE;
394: channelAttenuation.reg.swapChannels = NORMAL_STEREO;
395: outb(MIXER_CONTROL, channelAttenuation.data);
396: }
397:
398: static inline
399: void
400: setMasterInputAttenuation(u_int channel, masterAttenuation_t attenuation)
401: {
402: union {
403: channelSelection_t reg;
404: unsigned char data;
405: } channelSelection;
406:
407: // avoid a warning
408: channelSelection.data = 0;
409:
410: // select the master B mixer
411: channelSelection.reg.selectAddress = MIXER_B_MASTER;
412: channelSelection.reg.selectChannel = channel;
413: channelSelection.reg.isTransfer = TRUE;
414: outb(MIXER_CONTROL, channelSelection.data);
415:
416: // set the attenuation
417: outb(MIXER_CONTROL, (char)attenuation);
418: }
419:
420: static inline
421: void
422: setInputAttenuation(u_int address, u_int channel, u_int attenuation)
423: {
424: union {
425: channelSelection_t reg;
426: unsigned char data;
427: } channelSelection;
428:
429: union {
430: channelAttenuation_t reg;
431: unsigned char data;
432: } channelAttenuation;
433:
434: // avoid a warning
435: channelSelection.data = 0;
436: channelAttenuation.data = 0;
437:
438: channelSelection.reg.selectAddress = address;
439: channelSelection.reg.selectChannel = channel;
440: channelSelection.reg.isTransfer = TRUE;
441: outb(MIXER_CONTROL, channelSelection.data);
442:
443: channelAttenuation.reg.attenuation = attenuation;
444: channelAttenuation.reg.routeChannel = MIXER_B_ROUTE;
445: channelAttenuation.reg.swapChannels = NORMAL_STEREO;
446: outb(MIXER_CONTROL, channelAttenuation.data);
447:
448: }
449:
450: /*
451: * In the 3.1 release, the driver set the sample rate using the technique
452: * described in the Developer Reference. Unfortunately, this was imprecise
453: * due to rounding errors. The values were calculated as follows:
454: *
455: * 1193180 / (sample rate * channel count)
456: * 1193180 / (44100 * 1) = 27 // 44.1 kHz mono
457: * 1193180 / (44100 * 2) = 13 // 44.1 kHz stereo
458: *
459: * MediaVision has provided us with the calculateRate function which calculates
460: * the sample rate with more precision. This technique (which also sets the
461: * prescale register) is undocumented in their reference manual.
462: *
463: */
464: static inline
465: void
466: calculateRate(u_int sampleRate, u_int *timer, u_int *prescale)
467: {
468: long targetRatio;
469: long bestRatio;
470: long testRatio;
471: long bestDifference;
472: long lastDifference;
473: long testDifference;
474: long p;
475: long t;
476:
477: targetRatio = (441000L << 10) / sampleRate;
478: bestRatio = 300L << 10;
479: bestDifference = 7000L << 10;
480: *prescale = 0;
481: *timer = 0;
482:
483: for (p = 2; p < 256; p++) {
484: lastDifference = 300L << 10;
485:
486: for (t = p+1; t < 256; t++) {
487: testRatio = (t << 10) / p;
488:
489: if (testRatio == targetRatio) {
490: bestRatio = testRatio;
491: *prescale = p;
492: *timer = t;
493: return;
494: }
495:
496: testDifference = testRatio - targetRatio;
497:
498: if (testDifference < 0)
499: testDifference = -testDifference;
500:
501: if (testDifference > lastDifference)
502: break;
503:
504: if (testDifference < bestDifference) {
505: bestRatio = testRatio;
506: bestDifference = testDifference;
507: *prescale = p;
508: *timer = t;
509: }
510:
511: lastDifference = testDifference;
512: }
513: }
514: }
515:
516: static inline
517: void
518: setSampleRateTimer(u_int rate)
519: {
520:
521: u_int prescale;
522: u_int timer;
523:
524: union {
525: sampleRateTimer_t rate;
526: unsigned char data[2];
527: } sampleRateTimer;
528:
529:
530: filterControl_t filterControl = {0};
531: sampleCounterControl_t sampleCounterControl = {0};
532:
533: /*
534: * Before setting the sample rate interval, be sure to select the
535: * Sample Rate Timer using Local Timer Control Register (0x138b). Also
536: * remember to set the Sample Rate Timer Gate of the Audio Filter Control
537: * Register (0xb8a) to 0 before programming the timer.
538: */
539: filterControl = getFilterControl();
540: filterControl.enableSampleRateTimer = FALSE;
541: setFilterControl(filterControl);
542:
543: sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
544: sampleCounterControl.selectMode = SAMPLE_RATE_MODE;
545: sampleCounterControl.latchCounter = 3;
546: sampleCounterControl.selectCounter = SAMPLE_RATE_COUNT;
547: setSampleCounterControl(sampleCounterControl);
548:
549: switch (rate) {
550:
551: case 44100:
552: timer = 20;
553: prescale = 2;
554: break;
555:
556: case 22050:
557: timer = 40;
558: prescale = 2;
559: break;
560:
561: case 8012:
562: timer = 110;
563: prescale = 2;
564: break;
565:
566: default:
567: calculateRate(rate, &timer, &prescale);
568: break;
569: }
570:
571: sampleRateTimer.rate = timer;
572:
573: outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[0]);
574: outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[1]);
575:
576: outb(PRESCALE_DIVIDER, prescale & 0x0F);
577:
578: }
579:
580: static inline
581: void
582: setSampleBufferCounter(sampleBufferCounter_t count)
583: {
584: union {
585: sampleBufferCounter_t count;
586: unsigned char data[2];
587: } sampleBufferCounter;
588:
589: filterControl_t filterControl = {0};
590: sampleCounterControl_t sampleCounterControl = {0};
591:
592: filterControl = getFilterControl();
593: filterControl.enableSampleBufferCounter = FALSE;
594: setFilterControl(filterControl);
595:
596: sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
597: sampleCounterControl.latchCounter = 3;
598: sampleCounterControl.selectMode = SAMPLE_BUFFER_MODE;
599: sampleCounterControl.selectCounter = SAMPLE_BUFFER_COUNT;
600: setSampleCounterControl(sampleCounterControl);
601:
602: sampleBufferCounter.count = count;
603: outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[0]);
604: outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[1]);
605: }
606:
607: static inline
608: void
609: setMasterModeControl(masterModeControl_t mode)
610: {
611: union {
612: masterModeControl_t reg;
613: unsigned char data;
614: } masterModeControl;
615:
616: union {
617: channelSelection_t reg;
618: unsigned char data;
619: } channelSelection;
620:
621:
622: // avoid a warning
623: channelSelection.data = 0;
624:
625: channelSelection.reg.selectAddress = MASTER_MODE_CONTROL;
626: channelSelection.reg.selectChannel = BOTH_CHANNELS;
627: channelSelection.reg.isTransfer = TRUE;
628: outb(MIXER_CONTROL, channelSelection.data);
629:
630: masterModeControl.reg = mode;
631: outb(MIXER_CONTROL, masterModeControl.data);
632: }
633:
634: static inline
635: void
636: setLoudnessFilter(boolean_t flag)
637: {
638: masterModeControl_t masterModeControl = {0};
639:
640: masterModeControl.loudnessFilter = flag;
641: setMasterModeControl(masterModeControl);
642: }
643:
644:
645: static inline
646: void
647: setBassControl(unsigned char boost)
648: {
649: union {
650: channelSelection_t reg;
651: unsigned char data;
652: } channelSelection;
653:
654: // avoid a warning
655: channelSelection.data = 0;
656:
657: channelSelection.reg.selectAddress = BASS_CONTROL;
658: channelSelection.reg.selectChannel = BOTH_CHANNELS;
659: channelSelection.reg.isTransfer = TRUE;
660: outb(MIXER_CONTROL, channelSelection.data);
661:
662: outb(MIXER_CONTROL, boost);
663: }
664:
665: static inline
666: void
667: setTrebleControl(unsigned char boost)
668: {
669: union {
670: channelSelection_t reg;
671: unsigned char data;
672: } channelSelection;
673:
674: // avoid a warning
675: channelSelection.data = 0;
676:
677: channelSelection.reg.selectAddress = TREBLE_CONTROL;
678: channelSelection.reg.selectChannel = BOTH_CHANNELS;
679: channelSelection.reg.isTransfer = TRUE;
680: outb(MIXER_CONTROL, channelSelection.data);
681:
682: outb(MIXER_CONTROL, boost);
683: }
684:
685: static inline
686: void
687: resetMixer()
688: {
689: setMasterOutputAttenuation(BOTH_CHANNELS,
690: DEFAULT_MASTER_OUTPUT_ATTENUATION);
691:
692: setOutputAttenuation(PCM,
693: BOTH_CHANNELS,
694: DEFAULT_OUTPUT_ATTENUATION);
695:
696: /*
697: * mute all other output channels
698: */
699: setOutputAttenuation(INPUT_MIXER_LOOPBACK,
700: BOTH_CHANNELS,
701: MUTE);
702:
703: setMasterInputAttenuation(BOTH_CHANNELS,
704: DEFAULT_MASTER_INPUT_ATTENUATION);
705:
706: setInputAttenuation(MICROPHONE,
707: BOTH_CHANNELS,
708: DEFAULT_MICROPHONE_ATTENUATION);
709:
710: setInputAttenuation(EXTERNAL_LINE_IN,
711: BOTH_CHANNELS,
712: DEFAULT_INPUT_ATTENUATION);
713:
714: /*
715: * mute all other input channels
716: */
717: setInputAttenuation(FM_SYNTHESIS,
718: BOTH_CHANNELS,
719: MUTE);
720:
721: setInputAttenuation(INTERNAL_LINE_IN,
722: BOTH_CHANNELS,
723: MUTE);
724:
725: setInputAttenuation(SPEAKER,
726: BOTH_CHANNELS,
727: MUTE);
728:
729: setInputAttenuation(SOUNDBLASTER,
730: BOTH_CHANNELS,
731: MUTE);
732:
733: /*
734: * set treble and bass boost to 0db
735: */
736: setBassControl(DEFAULT_BASS_BOOST);
737: setTrebleControl(DEFAULT_TREBLE_BOOST);
738: }
739:
740:
741:
742: /*
743: * resetHardware uses "magic" values recommended by MediaVision. These
744: * settings are not always documented in the reference guide. In addition,
745: * some of the values are specific to a particular version of the hardware.
746: */
747: static inline
748: boolean_t
749: resetHardware()
750: {
751: systemConfiguration1_t systemConfiguration1;
752:
753: union {
754: interruptControl_t reg;
755: unsigned char data;
756: } interruptControl;
757:
758: unsigned char version;
759:
760: /*
761: * The presence of the hardware is verified. The version bits in the
762: * interrupt control register are read only.
763: */
764: interruptControl.data = inb(INTERRUPT_CONTROL);
765:
766: if (interruptControl.data == 0xff)
767: return FALSE;
768:
769: version = interruptControl.reg.version;
770: interruptControl.reg.version = 0;
771:
772: outb(INTERRUPT_CONTROL, interruptControl.data);
773: interruptControl.data = inb(INTERRUPT_CONTROL);
774:
775: if (interruptControl.reg.version != version)
776: return FALSE;
777:
778: /*
779: * Turn off MPU and SoundBlaster emulation
780: *
781: outb(COMPATIBILITY_ENABLE, 0);
782:
783: /*
784: * Turn off MPU and SoundBlaster interrupts
785: */
786: outb(EMULATION_CONFIGURATION, 0);
787:
788: /*
789: * Sets wait state to 140ns period
790: */
791: outb(WAIT_STATE, WAIT_STATE_RESET);
792:
793: /*
794: * D0 - resets FM
795: * D1 - resets Codec
796: * D2 - resets SoundBlaster
797: * D4 - resets MVA508 Mixer
798: */
799: outb(AUDIO_MIXER, 0);
800: outb(AUDIO_MIXER, AUDIO_MIXER_RESET);
801:
802: /*
803: * This is required when using the prescale register for more precise
804: * sample rate timing.
805: */
806: systemConfiguration1 = getSystemConfiguration1();
807: systemConfiguration1.selectCompatibleClock = TRUE;
808: setSystemConfiguration1(systemConfiguration1);
809:
810: outb(SYSTEM_CONFIGURATION_2, SYSTEM_CONFIGURATION_2_RESET);
811: /*
812: * D3 (invert bclk output)
813: * D4 (use codec sync output)
814: */
815: outb(SYSTEM_CONFIGURATION_3, SYSTEM_CONFIGURATION_3_RESET);
816:
817: outb(SYSTEM_CONFIGURATION_4, SYSTEM_CONFIGURATION_4_RESET);
818:
819: /*
820: * When a 16 bit Codec is attached, the Prescale counter is used to
821: * set the ratio between the incoming Codec bit clock and the outgoing
822: * master clock.
823: */
824: outb(PRESCALE_DIVIDER, PRESCALE_DIVIDER_RESET);
825:
826: resetMixer();
827: return TRUE;
828: }
829:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.