|
|
1.1 root 1: /* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
2: *
3: */
4: #import "ProAudioSpectrum16.h"
5: #import "ProAudioSpectrum16Registers.h"
6: #import "ProAudioSpectrum16Inline.h"
7:
8: #import <driverkit/generalFuncs.h>
9:
10: static char pasDeviceName[] = "ProAudioSpectrum16";
11: static char pasDeviceKind[] = "Audio";
12:
13: @implementation ProAudioSpectrum16
14:
15: /*
16: * Probe and initialize new instance
17: */
18: + (BOOL) probe:description
19: {
20: ProAudioSpectrum16 *dev;
21:
22: dev = [self alloc];
23: if (dev == nil)
24: return NO;
25:
26: /*
27: * Sets the base IO address (needs to be performed before any other
28: * hardware access)
29: */
30: setBaseAddress(DEFAULT_BASE_ADDRESS);
31:
32: return [dev initFromDeviceDescription:description] != nil;
33: }
34:
35: - (BOOL) reset
36: {
37: IOReturn ioReturn;
38: unsigned int dmaChannel = [[self deviceDescription] channel];
39: unsigned int interrupt = [[self deviceDescription] interrupt];
40: IOEISADMATransferWidth transferWidth = IO_16BitByteCount;
41:
42: [self setName: pasDeviceName];
43: [self setDeviceKind: pasDeviceKind];
44:
45: if (! (resetHardware())) {
46: IOLog("%s: hardware failed verification\n", [self name]);
47: return NO;
48: }
49:
50: /*
51: * The irq and dma channel are software selectable on the
52: * ProAudioSpectrum16.
53: */
54: if (! (setDMAChannel(dmaChannel))) {
55: IOLog("%s: %d is an invalid dma setting\n",
56: [self name], dmaChannel);
57: return NO;
58: }
59:
60: if (! (setInterrupt(interrupt))) {
61: IOLog("%s: %d is an invalid irq setting\n",
62: [self name], interrupt);
63: return NO;
64: }
65:
66: /*
67: * The DMA controller is initialized.
68: */
69: [self disableChannel: 0];
70:
71: /*
72: * On both ISA and EISA machines, the ProAudioSpectrum16 hardware
73: * requires that DMA channels 0-4 are set to an 8-bit transfer width.
74: */
75: if ([self isEISAPresent]) {
76: if (dmaChannel < 5)
77: transferWidth = IO_8Bit;
78:
79: ioReturn = [self setDMATransferWidth: transferWidth forChannel: 0];
80: if (ioReturn != IO_R_SUCCESS) {
81: IOLog("%s: dma transfer width error %d\n", [self name], ioReturn);
82: return NO;
83: }
84: }
85:
86: ioReturn = [self setTransferMode: IO_Single forChannel: 0];
87:
88: if (ioReturn != IO_R_SUCCESS) {
89: IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
90: return NO;
91: }
92:
93: ioReturn = [self setAutoinitialize: YES forChannel: 0];
94: if (ioReturn != IO_R_SUCCESS) {
95: IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
96: return NO;
97: }
98:
99: return YES;
100: }
101:
102: /*
103: * converts gain (0 - 32768) into attenuation (0 - 31)
104: */
105:
106: - (void) updateInputGainLeft
107: {
108: unsigned int gain = [self inputGainLeft] / 1057;
109:
110: setInputAttenuation(MICROPHONE, LEFT_CHANNEL, (unsigned char) gain);
111: setInputAttenuation(EXTERNAL_LINE_IN, LEFT_CHANNEL, (unsigned char) gain);
112: }
113:
114: - (void)updateInputGainRight
115: {
116: unsigned int gain = [self inputGainRight] / 1057;
117:
118: setInputAttenuation(MICROPHONE, RIGHT_CHANNEL, (unsigned char) gain);
119: setInputAttenuation(EXTERNAL_LINE_IN, RIGHT_CHANNEL, (unsigned char) gain);
120: }
121:
122: - (void)updateOutputMute
123: {
124: enableAudioOutput(! [self isOutputMuted]);
125: }
126:
127: - (void)updateLoudnessEnhanced
128: {
129: setLoudnessFilter([self isLoudnessEnhanced]);
130: }
131:
132: /*
133: * (0) - (-84) needs to be converted to (0) - (31)
134: */
135: - (void) updateOutputAttenuationLeft
136: {
137: unsigned int attenuation = [self outputAttenuationLeft] + 84;
138: attenuation = ((attenuation * 10)/27);
139:
140: setOutputAttenuation(PCM, LEFT_CHANNEL, (unsigned char) attenuation);
141: }
142:
143: /*
144: * (0) - (-84) needs to be converted to (0) - (32)
145: */
146: - (void) updateOutputAttenuationRight
147: {
148: unsigned int attenuation = [self outputAttenuationRight] + 84;
149: attenuation = ((attenuation * 10)/27);
150:
151: setOutputAttenuation(PCM, RIGHT_CHANNEL, (unsigned char) attenuation);
152: }
153:
154: - (IOReturn) enableAllInterrupts
155: {
156: interruptStatus_t interruptStatus = {0};
157: interruptControl_t interruptControl = {0};
158:
159: /*
160: * clear all interrupts
161: */
162: setInterruptStatus(interruptStatus);
163:
164: interruptControl.enableSampleBufferInterrupt = YES;
165: setInterruptControl(interruptControl);
166:
167: return [super enableAllInterrupts];
168: }
169:
170: - (void) disableAllInterrupts
171: {
172: interruptControl_t interruptControl = {0};
173:
174: setInterruptControl(interruptControl);
175:
176: [super disableAllInterrupts];
177: }
178:
179:
180: - (BOOL) startDMAForChannel: (unsigned int) localChannel
181: read: (BOOL) isRead
182: buffer: (IOEISADMABuffer) buffer
183: bufferSizeForInterrupts: (unsigned int) bufferSize
184: {
185:
186: IOReturn ioReturn;
187: unsigned int rate = [self sampleRate];
188:
189: IOEISADMATransferWidth transferWidth;
190:
191: filterControl_t filterControl = {0};
192: crossChannelControl_t crossChannelControl = {0};
193: systemConfiguration2_t systemConfiguration2 = {0};
194:
195:
196: /*
197: * Before enabling the DMA channel, "secure" the channel via the DRQ
198: * bit in the Cross Channel register (0xf8a). This causes the
199: * ProAudioSpectrum16 to drive the DMA channel from a floating state to
200: * a known good state. If you enable the DMA channel with an unsecured
201: * DRQ line, the DMA will perform a rapid-fire data tranfer due to the
202: * floating DRQ line.
203: */
204: crossChannelControl = getCrossChannelControl();
205: crossChannelControl.enableDMA = YES;
206: setCrossChannelControl(crossChannelControl);
207:
208: ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
209:
210: if (ioReturn != IO_R_SUCCESS) {
211: IOLog("%s: could not start DMA channel error %d\n",
212: [self name], ioReturn);
213: return NO;
214: }
215:
216: ioReturn = [self enableChannel: localChannel];
217:
218: if (ioReturn != IO_R_SUCCESS) {
219: IOLog("%s: could not enable DMA channel error %d\n",
220: [self name], ioReturn);
221: return NO;
222: }
223:
224: (void) [self enableAllInterrupts];
225:
226: setSampleRateTimer(rate);
227:
228: /*
229: * Use the Sample Buffer Count register to set the number of bytes in the
230: * DMA buffer division. This register holds a 16-bit value. When using a
231: * 16-bit DMA channel, the Sample Buffer Count must be divided by two.
232: */
233: (void) [self getDMATransferWidth: &transferWidth forChannel: localChannel];
234: if (transferWidth == IO_16BitByteCount ||
235: transferWidth == IO_16BitWordCount)
236: setSampleBufferCounter(bufferSize / 2);
237: else
238: setSampleBufferCounter(bufferSize);
239:
240:
241: if ([self dataEncoding] == NX_SoundStreamDataEncoding_Linear16)
242: systemConfiguration2.dataEncoding = LINEAR_16;
243: else
244: systemConfiguration2.dataEncoding = LINEAR_8;
245:
246: setSystemConfiguration2(systemConfiguration2);
247:
248: crossChannelControl.rightToRight = YES;
249: crossChannelControl.leftToLeft = YES;
250:
251: crossChannelControl.direction = !isRead;
252:
253: /*
254: * The mixer has feedback problems. MediaVision advised us to mute
255: * the PCM output channel when recording.
256: */
257: if (isRead)
258: setOutputAttenuation(PCM, BOTH_CHANNELS, 0);
259:
260: if ([self channelCount] == 1)
261: crossChannelControl.isMono = YES;
262: else
263: crossChannelControl.isMono = NO;
264:
265: setCrossChannelControl(crossChannelControl);
266: crossChannelControl.enablePCM = YES;
267: crossChannelControl.enableDMA = YES;
268: setCrossChannelControl(crossChannelControl);
269:
270: filterControl = getFilterControl();
271: filterControl.enableSampleRateTimer = YES;
272: filterControl.enableSampleBufferCounter = YES;
273: setFilterControl(filterControl);
274:
275: return YES;
276: }
277:
278: - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
279: {
280: filterControl_t filterControl = {0};
281: crossChannelControl_t crossChannelControl = {0};
282:
283: [self disableChannel: localChannel];
284:
285: filterControl = getFilterControl();
286: filterControl.enableSampleRateTimer = NO;
287: filterControl.enableSampleBufferCounter = NO;
288: setFilterControl(filterControl);
289:
290: (void)[self disableAllInterrupts];
291:
292: crossChannelControl = getCrossChannelControl();
293: crossChannelControl.enablePCM = NO;
294: setCrossChannelControl(crossChannelControl);
295: crossChannelControl.enableDMA = NO;
296: setCrossChannelControl(crossChannelControl);
297:
298: /*
299: * Due to mixer feedback problems, the PCM channels are muted during
300: * recording. Their current values are restored here.
301: */
302: if (isRead) {
303: [self updateOutputAttenuationLeft];
304: [self updateOutputAttenuationRight];
305: }
306: }
307:
308: static void clearInterrupts(void)
309: {
310: interruptStatus_t interruptStatus = {0};
311:
312: /*
313: * clear the hardware interrupt register
314: */
315: interruptStatus = getInterruptStatus();
316: if (! interruptStatus.sampleBufferInterruptPending)
317: return;
318:
319: /*
320: * The chip specification states that a write to this register
321: * will clear the clip status and sample interrupts.
322: */
323: interruptStatus.sampleBufferInterruptPending = NO;
324: setInterruptStatus(interruptStatus);
325: }
326:
327: - (IOAudioInterruptClearFunc) interruptClearFunc
328: {
329: return clearInterrupts;
330: }
331:
332: - (void) interruptOccurredForInput: (BOOL*)serviceInput
333: forOutput:(BOOL*)serviceOutput
334: {
335: interruptStatus_t interruptStatus = {0};
336:
337: /*
338: * clear the hardware interrupt register
339: */
340: interruptStatus = getInterruptStatus();
341: if (! interruptStatus.sampleBufferInterruptPending) {
342: IOLog("ProAudioSpectrum16: spurious dma interrupt\n");
343: return;
344: }
345:
346: /*
347: * The chip specification states that a write to this register
348: * will clear the clip status and sample interrupts.
349: */
350: interruptStatus.sampleBufferInterruptPending = NO;
351: setInterruptStatus(interruptStatus);
352:
353: if ([self isInputActive])
354: *serviceInput = YES;
355: else
356: *serviceOutput = YES;
357: }
358:
359: - (void) timeoutOccurred
360: {
361: crossChannelControl_t crossChannelControl = {0};
362:
363: crossChannelControl = getCrossChannelControl();
364: crossChannelControl.enablePCM = NO;
365: setCrossChannelControl(crossChannelControl);
366: crossChannelControl.enablePCM = YES;
367: setCrossChannelControl(crossChannelControl);
368: }
369:
370: /*
371: * Parameter access.
372: */
373:
374: - (BOOL)acceptsContinuousSamplingRates
375: {
376: return YES;
377: }
378:
379: - (void)getSamplingRatesLow: (int *)lowRate
380: high: (int *)highRate
381: {
382: *lowRate = 2000;
383: *highRate = 44100;
384: }
385:
386: - (void)getSamplingRates: (int *)rates
387: count: (unsigned int *)numRates
388: {
389: /* Return a few common rates */
390: rates[0] = 2000;
391: rates[1] = 8000;
392: rates[2] = 11025;
393: rates[3] = 16000;
394: rates[4] = 22050;
395: rates[5] = 32000;
396: rates[6] = 44100;
397: *numRates = 7;
398: }
399:
400: - (void)getDataEncodings: (NXSoundParameterTag *)encodings
401: count: (unsigned int *)numEncodings
402: {
403: IOEISADMATransferWidth transferWidth;
404:
405: encodings[0] = NX_SoundStreamDataEncoding_Linear8;
406: encodings[1] = NX_SoundStreamDataEncoding_Linear16;
407: *numEncodings = 2;
408:
409: /*
410: * For EISA machines, the driver is unable to handle 16-bit linear data
411: * when the DMA transfer width is 8 bits.
412: */
413: if ([self isEISAPresent]) {
414: (void)[self getDMATransferWidth: &transferWidth forChannel: 0];
415: if (transferWidth == IO_8Bit) {
416: encodings[1] = 0;
417: *numEncodings = 1;
418: }
419: }
420: }
421:
422: - (unsigned int) channelCountLimit
423: {
424: return 2; /* stereo and mono */
425: }
426:
427: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.