|
|
1.1 root 1: /*
2: * Copyright (c) 1994 NeXT Computer, Inc. All rights reserved.
3: *
4: * HISTORY
5: * 4-Mar-94 Rakesh Dubey at NeXT
6: * Created.
7: */
8:
9: #import "SoundBlaster8.h"
10: #import "SoundBlaster8Registers.h"
11:
12: #import <driverkit/generalFuncs.h>
13:
14: static const char codecDeviceName[] = "SoundBlaster8";
15: static const char codecDeviceKind[] = "Audio";
16:
17: static sbCardParameters_t sbCardType; // hardware type
18: static BOOL lowSpeedDMA; // different programming
19:
20: /*
21: * Include inline functions.
22: */
23: #import "SoundBlaster8Inline.h"
24:
25: @implementation SoundBlaster8
26:
27: /*
28: * Probe and initialize new instance
29: */
30: + (BOOL) probe:deviceDescription
31: {
32: SoundBlaster8 *dev;
33: IORange *portRangeList;
34: int numPortRanges;
35: unsigned int baseAddress;
36:
37: #ifdef DEBUG
38: int i;
39: #endif DEBUG
40:
41: dev = [self alloc];
42: if (dev == nil)
43: return NO;
44:
45: portRangeList = [deviceDescription portRangeList];
46: numPortRanges = [deviceDescription numPortRanges];
47:
48: if (numPortRanges < 1)
49: return NO;
50:
51: #ifdef DEBUG
52: for (i=0; i < numPortRanges; i++) {
53: IOLog("SoundBlaster8: port %x %d\n",
54: portRangeList[i].start, portRangeList[i].size);
55: }
56: #endif DEBUG
57:
58: baseAddress = portRangeList[0].start;
59: #ifdef DEBUG
60: IOLog("SoundBlaster8: Base address = 0x%x.\n", baseAddress);
61: #endif DEBUG
62:
63:
64: /*
65: * Check base address to verify if this is a legal address.
66: */
67:
68: if ((baseAddress == SB_BASE_ADDRESS_1) ||
69: (baseAddress == SB_BASE_ADDRESS_2) ||
70: (baseAddress == SB_BASE_ADDRESS_3) ||
71: (baseAddress == SB_BASE_ADDRESS_4) ||
72: (baseAddress == SB_BASE_ADDRESS_5) ||
73: (baseAddress == SB_BASE_ADDRESS_6)) {
74: sbBaseRegisterAddress = baseAddress;
75: } else {
76: IOLog("SoundBlaster8: Invalid port address 0x%0x.\n", baseAddress);
77: [dev free];
78: return NO;
79: }
80:
81: /*
82: * Now assign all SB DSP and Mixer registers their addresses.
83: */
84: assignDSPRegAddresses();
85: assignMixerRegAddresses();
86:
87: return [dev initFromDeviceDescription:deviceDescription] != nil;
88: }
89:
90:
91: - (BOOL)reset
92: {
93: unsigned int channel = [[self deviceDescription] channel];
94: unsigned int interrupt = [[self deviceDescription] interrupt];
95:
96: IOReturn ioReturn;
97:
98: [self setName:codecDeviceName];
99: [self setDeviceKind:codecDeviceKind];
100:
101: /*
102: * Are user selections valid?
103: */
104: if (checkSelectedDMAAndIRQ(channel, interrupt) == NO) {
105: return NO;
106: }
107:
108: /*
109: * Now that all hardware parameters have been assigned and/or verified
110: * initialize the hardware.
111: */
112: [self initializeHardware];
113:
114: /*
115: * This driver is only for 8-bit Sound Blaster cards. If this is not one
116: * of these systems we quit since the test is fully reliable.
117: */
118:
119: switch (sbCardType.version) {
120: case SB_CLASSIC:
121: sbCardType.name = "Classic";
122: break;
123: case SB_20:
124: sbCardType.name = "2.0";
125: break;
126: case SB_PRO:
127: sbCardType.name = "Pro";
128: break;
129: case SB_16:
130: sbCardType.name = "Pro";
131: sbCardType.version = SB_PRO; /* SB16 will emulate it */
132: break;
133: default: {
134: IOLog("SoundBlaster8: Hardware not detected at port 0x%0x.\n",
135: sbBaseRegisterAddress);
136: return NO;
137: }
138: }
139:
140: IOLog("SoundBlaster8: Sound Blaster %s (ver %d.%d) at port 0x%0x.\n",
141: sbCardType.name,
142: sbCardType.majorVersion, sbCardType.minorVersion,
143: sbBaseRegisterAddress);
144:
145: /*
146: * Initialize DMA controller.
147: */
148:
149: [self disableChannel: 0];
150:
151: /*
152: * This call is only applicable in EISA systems. All dma channels
153: * that are available to this driver in ISA machines are 8-bit. So we do
154: * this setup only for EISA machines.
155: */
156: if ([self isEISAPresent]) {
157: ioReturn = [self setDMATransferWidth:IO_8Bit forChannel:0];
158: if (ioReturn != IO_R_SUCCESS) {
159: IOLog("SoundBlaster8: could not set transfer width to 8 bits, error %d.\n", ioReturn);
160: return NO;
161: }
162: }
163:
164: ioReturn = [self setTransferMode: IO_Single forChannel: 0];
165: if (ioReturn != IO_R_SUCCESS) {
166: IOLog("%s: dma transfer mode error %d\n", [self name], ioReturn);
167: return NO;
168: }
169:
170: /*
171: * We will program the DMA controller in auto-init mode but the card is
172: * in single cycle mode. So at every interrupt we only need to reprogram
173: * the card.
174: */
175: ioReturn = [self setAutoinitialize: YES forChannel: 0];
176: if (ioReturn != IO_R_SUCCESS) {
177: IOLog("%s: dma auto initialize error %d", [self name], ioReturn);
178: return NO;
179: }
180:
181: return YES;
182: }
183:
184:
185: - (void) initializeHardware
186: {
187: resetHardware();
188: }
189:
190: /*
191: * Converts gain (0 - 32768) into hardware supported gain (0 - 7). If the
192: * input source is line (not supported now), simply double the gain.
193: */
194:
195: - (void)updateInputGainLeft
196: {
197: unsigned int gain = [self inputGainLeft];
198: unsigned int left = 0;
199:
200: if (gain)
201: left = ((gain * MAX_INPUT_GAIN_MICROPHONE)/32768);
202: else
203: left = gain; // minimum input gain = 0
204:
205: setInputGain(LEFT_CHANNEL, left);
206: #ifdef DEBUG
207: IOLog("%s: updateInputGainLeft %d based on gain %d\n", [self name],left, gain);
208: #endif DEBUG
209: }
210:
211: /*
212: * Converts gain (0 - 32768) into hardware supported gain (0 - 7)
213: */
214:
215: - (void)updateInputGainRight
216: {
217: unsigned int gain = [self inputGainRight];
218: unsigned int right = 0;
219:
220: if (gain)
221: right = ((gain * MAX_INPUT_GAIN_MICROPHONE)/32768);
222: else
223: right = gain; // minimum input gain = 0
224:
225: setInputGain(RIGHT_CHANNEL, right);
226: #ifdef DEBUG
227: IOLog("%s: updateInputGainRight %d based on gain %d\n", [self name], right, gain);
228: #endif DEBUG
229: }
230:
231: - (void)updateOutputMute
232: {
233: enableAudioOutput(! [self isOutputMuted]);
234: }
235:
236: /*
237: * (0) - (-84) needs to be converted to hardware supported (0) - (15)
238: */
239: - (void) updateOutputAttenuationLeft
240: {
241: unsigned int attenuation = [self outputAttenuationLeft] + 84;
242: unsigned int left = 0;
243:
244: left = ((attenuation * MAX_MASTER_OUTPUT_VOLUME)/84);
245:
246: setOutputAttenuation(LEFT_CHANNEL, left);
247:
248: #ifdef DEBUG
249: IOLog("%s: converted la: %d into %d\n", [self name], attenuation, left);
250: #endif DEBUG
251: }
252:
253: /*
254: * (0) - (-84) needs to be converted to hardware supported (0) - (15)
255: */
256: - (void) updateOutputAttenuationRight
257: {
258: unsigned int attenuation = [self outputAttenuationRight] + 84;
259: unsigned int right = 0;
260:
261: right = ((attenuation * MAX_MASTER_OUTPUT_VOLUME)/84);
262:
263: setOutputAttenuation(RIGHT_CHANNEL, right);
264:
265: #ifdef DEBUG
266: IOLog("SoundBlaster8: converted ra: %d into %d\n", attenuation, right);
267: #endif DEBUG
268: }
269:
270: /*
271: * Program DSP.
272: */
273: - (void)updateSampleRate
274: {
275: unsigned int rate;
276: unsigned int mode;
277:
278: rate = [self sampleRate];
279: mode = ([self channelCount] == 2) ? DSP_STEREO_MODE : DSP_MONO_MODE;
280:
281: /*
282: * Programming sequence depends upon whether we are doing a low speed or
283: * high speed transfer. Rather messy, see SB SDK page 12-5.
284: */
285: if (sbCardType.version == SB_CLASSIC) {
286: lowSpeedDMA = YES;
287: } else if (sbCardType.version == SB_20) {
288: if (currentDMADirection == DMA_DIRECTION_IN)
289: lowSpeedDMA = (rate < SB_20_LOW_SPEED_RECORD) ? YES : NO;
290: else
291: lowSpeedDMA = (rate < SB_20_LOW_SPEED_PLAYBACK) ? YES : NO;
292: } else if (sbCardType.version == SB_PRO) {
293: if (mode == DSP_STEREO_MODE)
294: rate *= 2;
295: lowSpeedDMA = (rate < SB_PRO_LOW_SPEED) ? YES : NO;
296: }
297:
298: setCodecDataMode(mode, currentDMADirection);
299: setCodecSamplingRate(rate);
300: }
301:
302:
303: /*
304: * Sets the DMA Counter Load register which decides when the next interrupt
305: * will arrive.
306: */
307: - (void) setBufferCount:(int)count
308: {
309: setSampleBufferCounter(count);
310: }
311:
312:
313: - (IOReturn) enableAllInterrupts
314: {
315: enableCodecInterrupts();
316: return [super enableAllInterrupts];
317: }
318:
319: - (void) disableAllInterrupts
320: {
321: disableCodecInterrupts();
322: [super disableAllInterrupts];
323: }
324:
325: /*
326: * Return NO if the hardware does not support this particular playback/record
327: * request. The parameter scheme in soundkit does not fit the anarchy
328: * of PC world very well.
329: */
330: - (BOOL)isValidRequest: (BOOL)isRead
331: {
332: unsigned int rate;
333: unsigned int mode;
334: unsigned int encoding;
335:
336: rate = [self sampleRate];
337: encoding = [self dataEncoding];
338: mode = ([self channelCount] == 2) ? DSP_STEREO_MODE : DSP_MONO_MODE;
339:
340: #ifdef DEBUG
341: IOLog("SoundBlaster8: rate: %d ", rate);
342:
343: if (mode == DSP_MONO_MODE)
344: IOLog("dataMode: mono ");
345: else if (mode == DSP_STEREO_MODE)
346: IOLog("dataMode: stereo ");
347: else
348: IOLog("dataMode: unknown ");
349:
350: if (encoding == NX_SoundStreamDataEncoding_Linear16)
351: IOLog("dataEncoding: linear 16\n");
352: else if (encoding == NX_SoundStreamDataEncoding_Linear8)
353: IOLog("dataEncoding: linear 8\n");
354: else if (encoding == NX_SoundStreamDataEncoding_Mulaw8)
355: IOLog("dataEncoding: mulaw 8\n");
356: else if (encoding == NX_SoundStreamDataEncoding_Alaw8)
357: IOLog("dataEncoding: Alaw 8\n");
358: else
359: IOLog("dataEncoding: unknown\n");
360: #endif DEBUG
361:
362: if (sbCardType.version == SB_PRO) {
363: if ((mode == DSP_STEREO_MODE) &&
364: (rate > SB_PRO_LOW_SPEED))
365: return NO;
366: }
367:
368: if (sbCardType.version == SB_20) {
369: if (isRead && rate > SB_20_LOW_SPEED_RECORD)
370: return NO;
371: }
372:
373: if (sbCardType.version == SB_CLASSIC) {
374: if (isRead && rate > SB_CLASSIC_MAX_SPEED_RECORD)
375: return NO;
376: if (!isRead && rate > SB_CLASSIC_MAX_SPEED_PLAYBACK)
377: return NO;
378: }
379:
380: return YES;
381: }
382:
383:
384: - (BOOL) startDMAForChannel: (unsigned int) localChannel
385: read: (BOOL) isRead
386: buffer: (IOEISADMABuffer) buffer
387: bufferSizeForInterrupts: (unsigned int) bufferSize
388: {
389: IOReturn ioReturn;
390:
391: #ifdef DEBUG
392: IOLog("SoundBlaster8: startDMAForChannel\n");
393: #endif DEBUG
394:
395: isValidRequest = [self isValidRequest:isRead];
396:
397: interruptTimedOut = NO;
398:
399: if (isValidRequest == NO) {
400: IOLog("%s: unsupported %s mode.\n", [self name],
401: isRead ? "recording" : "playback");
402:
403: if (isRead)
404: return YES;
405: else
406: return NO;
407: }
408:
409: if (isRead)
410: currentDMADirection = DMA_DIRECTION_IN;
411: else
412: currentDMADirection = DMA_DIRECTION_OUT;
413:
414: /*
415: * Output must be off while recording.
416: */
417: if (![self isOutputMuted])
418: enableAudioOutput(isRead ? NO : YES);
419:
420: [self updateSampleRate];
421:
422: dmaDescriptorSize = bufferSize; // used by interrupt handler
423:
424: #ifdef DEBUG
425: if (lowSpeedDMA)
426: IOLog("SoundBlaster8: starting low speed DMA ");
427: else
428: IOLog("SoundBlaster8: starting high speed DMA ");
429:
430: if (isRead)
431: IOLog("input.\n");
432: else
433: IOLog("output.\n");
434: #endif DEBUG
435:
436: ioReturn = [self startDMAForBuffer: buffer channel: localChannel];
437:
438: if (ioReturn != IO_R_SUCCESS) {
439: IOLog("%s: could not start DMA channel error %d\n",
440: [self name], ioReturn);
441: return NO;
442: }
443:
444: ioReturn = [self enableChannel: localChannel];
445:
446: if (ioReturn != IO_R_SUCCESS) {
447: IOLog("%s: could not enable DMA channel error %d\n",
448: [self name], ioReturn);
449: return NO;
450: }
451:
452: (void) [self enableAllInterrupts];
453:
454: /*
455: * The order is important here. See SB SDK page 12-8 and 12-13.
456: */
457: if (lowSpeedDMA) {
458: if (isRead) {
459: startDMA(DMA_DIRECTION_IN);
460: } else {
461: startDMA(DMA_DIRECTION_OUT);
462: }
463: [self setBufferCount: dmaDescriptorSize];
464: } else {
465: [self setBufferCount: dmaDescriptorSize];
466: if (isRead) {
467: startDMA(DMA_DIRECTION_IN);
468: } else {
469: startDMA(DMA_DIRECTION_OUT);
470: }
471: }
472:
473: return YES;
474: }
475:
476: - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
477: {
478: #ifdef DEBUG
479: IOLog("SoundBlaster8: stopDMAForChannel\n");
480: #endif DEBUG
481:
482: /*
483: * DMA request was denied bacause of lack of hardware support.
484: */
485: if (isValidRequest == NO)
486: return;
487:
488: if (isRead) {
489: stopDMAInput();
490: } else {
491: stopDMAOutput();
492: }
493:
494: (void)[self disableAllInterrupts];
495:
496: /*
497: * Disable channel only after disabling capture and playback.
498: */
499: [self disableChannel: localChannel];
500:
501: if (isRead == NO)
502: enableAudioOutput(NO);
503:
504: /*
505: * Reset DSP to stop high speed DMA transfer. This is necessary since the
506: * current "DMA block" might be continuing in case the transfer was
507: * interrupted.
508: */
509: if (lowSpeedDMA == NO) {
510: resetDSPQuick();
511: }
512: }
513:
514: static void clearInterrupts(void)
515: {
516: /*
517: * Acknowledge and clear the interrupt.
518: */
519:
520: inb(sbDataAvailableStatusReg);
521: }
522:
523: - (IOAudioInterruptClearFunc) interruptClearFunc
524: {
525: return clearInterrupts;
526: }
527:
528: - (void) interruptOccurredForInput: (BOOL *) serviceInput
529: forOutput: (BOOL *) serviceOutput
530: {
531: #ifdef DEBUG
532: IOLog("SoundBlaster8: handleHardwareInterrupt\n");
533: #endif DEBUG
534:
535: /*
536: * Acknowledge and clear the interrupt.
537: */
538:
539: inb(sbDataAvailableStatusReg);
540:
541: /*
542: * We do not have simultaneous playback and record in SB.
543: */
544: if (currentDMADirection == DMA_DIRECTION_OUT)
545: *serviceOutput = YES;
546: else
547: *serviceInput = YES;
548:
549: if (lowSpeedDMA) {
550: if (currentDMADirection == DMA_DIRECTION_IN) {
551: startDMA(DMA_DIRECTION_IN);
552: } else {
553: startDMA(DMA_DIRECTION_OUT);
554: }
555: [self setBufferCount: dmaDescriptorSize]; /* needed here */
556: } else {
557: //[self setBufferCount: dmaDescriptorSize]; /* but not here */
558: if (currentDMADirection == DMA_DIRECTION_IN) {
559: startDMA(DMA_DIRECTION_IN);
560: } else {
561: startDMA(DMA_DIRECTION_OUT);
562: }
563: }
564: }
565:
566: /*
567: * This routine will be called if interrupts are not being received. Some
568: * cards seem to lock up once in a while.
569: */
570: - (void) timeoutOccurred
571: {
572: #ifdef DEBUG
573: IOLog("%s: timeout occurred.\n", [self name]);
574: #endif DEBUG
575:
576: if (interruptTimedOut == NO) {
577: resetDSPQuick();
578: interruptTimedOut = YES; // reset only once
579: }
580: }
581:
582: /*
583: * Choose between different input sources.
584: */
585:
586: - (void)setAnalogInputSource:(NXSoundParameterTag) val
587: {
588: if (val == NX_SoundDeviceAnalogInputSource_Microphone) {
589: setInputLevel(MICROPHONE_LEVEL_INPUT);
590: } else if (val == NX_SoundDeviceAnalogInputSource_LineIn) {
591: setInputLevel(LINE_LEVEL_INPUT);
592: } else {
593: setInputLevel(MICROPHONE_LEVEL_INPUT); // default
594: }
595: }
596:
597: /*
598: * Parameter access.
599: */
600:
601: - (BOOL)acceptsContinuousSamplingRates
602: {
603: return YES;
604: }
605:
606: - (void)getSamplingRatesLow:(int *)lowRate
607: high:(int *)highRate
608: {
609: *lowRate = 4000;
610: *highRate = 44100;
611: }
612:
613: - (void)getSamplingRates:(int *)rates
614: count:(unsigned int *)numRates
615: {
616: /* Return some supported rates */
617: rates[0] = 4000;
618: rates[1] = 8000;
619: rates[2] = 11025;
620: rates[3] = 22050;
621: rates[4] = 44100;
622: *numRates = 5;
623: }
624:
625: - (void)getDataEncodings: (NXSoundParameterTag *)encodings
626: count:(unsigned int *)numEncodings
627: {
628: encodings[0] = NX_SoundStreamDataEncoding_Linear8;
629: *numEncodings = 1;
630: }
631:
632: - (unsigned int)channelCountLimit
633: {
634: return (sbCardType.version == SB_PRO) ? 2 : 1; /* stereo and mono */
635: }
636:
637: @end
638:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.