|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24: *
25: * Hardware independent (relatively) code for the AudioBus
26: *
27: * HISTORY
28: *
29: *
30: */
31:
32: #include <IOKit/audio/IOAudioBus.h>
33: #include <IOKit/IOLib.h>
34: #include <IOKit/IOWorkLoop.h>
35: #include <IOKit/IOFilterInterruptEventSource.h>
36:
37: #undef super
38: #define super IOAudioController
39:
40: //************************************************************************
41: // Implementation of protocol clas.
42: //************************************************************************
43: OSDefineMetaClass( IOAudioBus, IOAudioController )
44: OSDefineAbstractStructors( IOAudioBus, IOAudioController )
45:
46: #ifdef __ppc__
47:
48: //************************************************************************
49: // Begin implementation of IOAudioBus class.
50: //************************************************************************
51:
52: #define kNumberOfBuffers 4
53: #define kNumberOfSamples 8192
54: #define kNumberOfChannels 2 // left and right
55: #define kSampleSize 2 // 16 bit channels
56: #define kBlockSize 256
57:
58: const int IOAudioBus::kAudioDMAdeviceInt = 0;
59: const int IOAudioBus::kAudioDMAtxInt = 1;
60: const int IOAudioBus::kAudioDMArxInt = 2;
61:
62: const int IOAudioBus::kAudioDMAOutputStream = 0;
63: const int IOAudioBus::kAudioDMAInputStream = 1;
64:
65: // Constructs an empty audio bus:
66: bool
67: IOAudioBus::init(OSDictionary * properties)
68: {
69: if (!super::init(properties))
70: return false;
71:
72: ioAudioStreamsDMA = NULL;
73: numDMAStreams = NULL;
74:
75: // Initialize my ivars.
76: fBufMax = kNumberOfBuffers * kNumberOfSamples * kNumberOfChannels * kSampleSize;
77: fBlockSize = kBlockSize;
78:
79: return true;
80: }
81:
82: // This should free everything
83: void
84: IOAudioBus::free()
85: {
86: FreeStreams();
87: super::free();
88: }
89:
90: void IOAudioBus::startWorkLoop()
91: {
92: super::startWorkLoop();
93: registerInterrupts();
94: }
95:
96: void IOAudioBus::registerInterrupts()
97: {
98: fTxInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
99: IOAudioBus::AudioBusInterruptHandler,
100: IOAudioBus::AudioBusInterruptFilter,
101: fDevice,
102: kAudioDMAtxInt);
103: fWorkLoop->addEventSource(fTxInterruptSource);
104:
105: fRxInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
106: IOAudioBus::AudioBusInterruptHandler,
107: IOAudioBus::AudioBusInterruptFilter,
108: fDevice,
109: kAudioDMArxInt);
110: fWorkLoop->addEventSource(fRxInterruptSource);
111:
112: fTxInterruptSource->enable();
113: fRxInterruptSource->enable();
114: }
115:
116: bool IOAudioBus::AudioBusInterruptFilter(OSObject *owner,
117: IOFilterInterruptEventSource *source)
118: {
119: register IOAudioBus *bus = (IOAudioBus *)owner;
120: bool result = true;
121:
122: if (bus) {
123: result = bus->filterInterrupt(source->getIntIndex());
124: }
125:
126: return result;
127: }
128:
129: bool IOAudioBus::filterInterrupt(int index)
130: {
131: IOAudioStreamStatus *status = getSharedStatus(getStreamForInterrupt(index));
132:
133: if (status) {
134: clock_get_uptime(&status->fLastLoopTime);
135: ++status->fCurrentLoopCount;
136: }
137:
138: return false;
139: }
140:
141: void IOAudioBus::AudioBusInterruptHandler(OSObject *owner,
142: IOInterruptEventSource * /*source*/,
143: int /*count*/)
144: {
145: return;
146: }
147:
148: AudioStreamIndex IOAudioBus::getStreamForInterrupt(int index)
149: {
150: AudioStreamIndex result = kNoStream;
151:
152: switch (index) {
153: case kAudioDMAtxInt:
154: result = kAudioDMAOutputStream;
155: break;
156: case kAudioDMArxInt:
157: result = kAudioDMAInputStream;
158: break;
159: }
160: return result;
161: }
162:
163: // Creates n empty streams (also a method to free them)
164: bool
165: IOAudioBus::AllocateStreams(int n)
166: {
167: numDMAStreams = n;
168:
169: if (numDMAStreams > 0) {
170: // Allocates as many StreamDMAInfo as needed:
171: ioAudioStreamsDMA = (StreamDMAInfo*)IOMalloc(sizeof(StreamDMAInfo) * numDMAStreams);
172: if (ioAudioStreamsDMA == NULL) {
173: numDMAStreams = 0;
174: return false;
175: }
176: for (n =0 ; n < numDMAStreams; n++) {
177: ioAudioStreamsDMA[n].streamProperty = NULL;
178: ioAudioStreamsDMA[n].fIOBaseDMA = NULL;
179: ioAudioStreamsDMA[n].fSharedStatus = NULL;
180: }
181:
182: return (true);
183: }
184:
185: return (false);
186: }
187:
188: bool
189: IOAudioBus::FreeStreams()
190: {
191: int n;
192:
193: if (ioAudioStreamsDMA != NULL) {
194: // First stops all the streams:
195: for (n =0 ; n < numDMAStreams; n++)
196: if (ioAudioStreamsDMA[n].fIOBaseDMA != NULL) {
197: stopStream(n);
198:
199: // If we ever created a stream property fpr the stream, delete it:
200: IOFree(ioAudioStreamsDMA[n].streamProperty, 128);
201: ioAudioStreamsDMA[n].streamProperty = NULL;
202: }
203:
204: IOFree(ioAudioStreamsDMA, sizeof(StreamDMAInfo) * numDMAStreams);
205: ioAudioStreamsDMA = NULL;
206:
207: return true;
208: }
209:
210: return false;
211: }
212:
213: // For each stream defines its properties:
214: bool
215: IOAudioBus::DefineStream(AudioStreamIndex i, int direction, UInt32 rate, IODBDMAChannelRegisters *base)
216: {
217: if ((ioAudioStreamsDMA != NULL) && (i < numDMAStreams) && (base != NULL)) {
218: ioAudioStreamsDMA[i].fIOBaseDMA = base;
219:
220: // The stream direction is "hardwired" so that ecah channel
221: // can go in one direction.
222: if (direction == kInput) {
223: ioAudioStreamsDMA[i].fDmaCmd = kdbdmaInputMore;
224: ioAudioStreamsDMA[i].fNeedsErase = false;
225: ioAudioStreamsDMA[i].fIsInput = true;
226: }
227: else {
228: ioAudioStreamsDMA[i].fDmaCmd = kdbdmaOutputMore;
229: ioAudioStreamsDMA[i].fNeedsErase = true;
230: ioAudioStreamsDMA[i].fIsInput = false;
231: }
232: ioAudioStreamsDMA[i].fSampleRate = rate;
233:
234: #ifdef DEBUGMODE
235: IOLog("IOAudioBus::DefineStream(%d, %s, %ld, 0x%08lx)\n",i, (direction == kInput ? "kInput" : "kOutput"),rate, (UInt32)base);
236: #endif
237: }
238:
239: return false;
240: }
241:
242: // Returns the first stream in the given direction after the given
243: // index. (this is useful if we have to handle more than one stream
244: // for input and output). (afterIndex is inclusive)
245:
246: AudioStreamIndex
247: IOAudioBus::firstStreamAfter(int inDirection, AudioStreamIndex afterIndex)
248: {
249: if ((ioAudioStreamsDMA != NULL) && (afterIndex < numDMAStreams)) {
250: for (;afterIndex < numDMAStreams; afterIndex++) {
251: if ((inDirection == kInput) && (ioAudioStreamsDMA[afterIndex].fIsInput))
252: return (afterIndex);
253: else if ((inDirection == kOutput) && (!ioAudioStreamsDMA[afterIndex].fIsInput))
254: return (afterIndex);
255: }
256: }
257:
258: // We did not find a stream with the wanted properties
259: return (kInvalidStreamIndex);
260: }
261:
262: OSDictionary*
263: IOAudioBus::getStreamProperties(AudioStreamIndex i)
264: {
265: OSDictionary *dict = NULL;
266: OSString *errorString = NULL;
267:
268: if ((ioAudioStreamsDMA != NULL) && (i < numDMAStreams))
269: if (ioAudioStreamsDMA[i].fIOBaseDMA != NULL) {
270:
271: ioAudioStreamsDMA[i].streamProperty = (char*)IOMalloc(128);
272: if (ioAudioStreamsDMA[i].streamProperty != NULL) {
273: // Depending from the direction of the stream this builds the property
274: // string:
275: if (ioAudioStreamsDMA[i].fIsInput) {
276: sprintf(ioAudioStreamsDMA[i].streamProperty, "{'In'=%d:8;'Out'=%d:8;'Channels'=%d:8;'Rate'=%ld:32;}",
277: (UInt8)1, (UInt8)0, (UInt8)2,
278: ioAudioStreamsDMA[i].fSampleRate);
279: }
280: else{
281: sprintf(ioAudioStreamsDMA[i].streamProperty, "{'In'=%d:8;'Out'=%d:8;'Channels'=%d:8;'Rate'=%ld:32;}",
282: (UInt8)0, (UInt8)1, (UInt8)2,
283: ioAudioStreamsDMA[i].fSampleRate);
284: }
285:
286: dict = OSDynamicCast(OSDictionary, OSUnserialize(ioAudioStreamsDMA[i].streamProperty, &errorString));
287: }
288: }
289: else
290: IOLog("IOAudioBus::getStreamProperties: bad index %d\n", i);
291:
292: if (dict == NULL) {
293: if (errorString != NULL) {
294: IOLog("IOAudioBus::getStreamProperties %s (\"%s\")\n", errorString->getCStringNoCopy(), ioAudioStreamsDMA[i].streamProperty);
295: errorString->release();
296: }
297: }
298:
299: return dict;
300: }
301:
302: /*
303: * Map stream data for caller.
304: */
305:
306: IOAudioStream *
307: IOAudioBus::createAudioStream(AudioStreamIndex index)
308: {
309: assert(index < numDMAStreams);
310: IOAudioStream * stream = super::createAudioStream(index);
311: return stream;
312: }
313:
314: int IOAudioBus::probeStreams()
315: {
316: return numDMAStreams;
317: }
318:
319: IOAudioStreamStatus * IOAudioBus::startStream(AudioStreamIndex index)
320: {
321: assert(index < numDMAStreams);
322:
323: int numBlocks, bufSize, i, cmdSize;
324: u_int32_t cmdPhys, bufPhys, seqPhys, offset;
325: IOAudioStreamStatus *status;
326: char *bufs;
327: bool doInterrupt = false;
328:
329: // Calculate size and allocate dbdma command area, sample buffer and shared status.
330: numBlocks = fBufMax/fBlockSize;
331: bufSize = fBlockSize * numBlocks;
332: cmdSize = (numBlocks * 2 + 1) * sizeof(IODBDMADescriptor);
333: IODBDMADescriptor *cmds = (IODBDMADescriptor *)IOMallocAligned(cmdSize, 4);
334: bufs = (char *)IOMallocAligned(round_page(bufSize), PAGE_SIZE);
335:
336: // This makes sure we get an entire page for the status buffer
337: // to prevent the problem of other memory being allocated
338: // in the same page that we're sharing read-only with user space.
339: // Since we don't need an entire page for each status struct,
340: // we could keep track of how much of the page that we've used and
341: // assign chunks of it for each stream...
342:
343: status = (IOAudioStreamStatus *)IOMallocAligned(round_page(sizeof(IOAudioStreamStatus)), PAGE_SIZE);
344:
345: // Everything after this check should always succeed.
346: if(!cmds || !bufs || !status)
347: return NULL;
348:
349: bzero(bufs, bufSize);
350:
351: // get physical addresses of everything for the DBDMA controller.
352: seqPhys = pmap_extract(kernel_pmap, (vm_address_t) &(status->fCurrentBlock));
353: cmdPhys = pmap_extract(kernel_pmap, (vm_address_t) cmds);
354: bufPhys = pmap_extract(kernel_pmap, (vm_address_t) bufs);
355: offset = 0;
356:
357: // The address of the stop command:
358: u_int32_t cmdStopPys = pmap_extract(kernel_pmap, (vm_address_t) (&cmds[numBlocks * 2]));
359:
360: for(i=0; i<numBlocks; i++) {
361: u_int32_t cmdDest;
362:
363: if(offset >= PAGE_SIZE) {
364: bufPhys = pmap_extract(kernel_pmap, (vm_address_t) (bufs + i*fBlockSize));
365: offset = 0;
366: }
367:
368: // Need a DBDMA branch if the next command is on a different page or
369: // if we have to loop back to the first DBDMA command.
370: if(i == numBlocks-1) {
371: cmdDest = cmdPhys;
372: doInterrupt = true;
373: } else if( ((2*(i+1)*sizeof(IODBDMADescriptor)) % PAGE_SIZE) == 0)
374: cmdDest = pmap_extract(kernel_pmap, (vm_address_t) (cmds+2*(i+1)));
375: else
376: cmdDest = 0;
377:
378: IOMakeDBDMADescriptorDep( &cmds[2*i],
379: kdbdmaStoreQuad,
380: kdbdmaKeyStream0,
381: kdbdmaIntNever,
382: kdbdmaBranchNever,
383: kdbdmaWaitNever,
384: sizeof(u_int32_t),
385: seqPhys,
386: OSReadLittleInt32(&i, 0) );
387: if(cmdDest) {
388: IOMakeDBDMADescriptorDep( &cmds[2*i+1],
389: ioAudioStreamsDMA[index].fDmaCmd,
390: kdbdmaKeyStream0,
391: doInterrupt ? kdbdmaIntAlways : kdbdmaIntNever,
392: kdbdmaBranchAlways,
393: kdbdmaWaitNever,
394: fBlockSize,
395: bufPhys+offset,
396: cmdDest);
397: }
398: else {
399: IOMakeDBDMADescriptorDep( &cmds[2*i+1],
400: ioAudioStreamsDMA[index].fDmaCmd,
401: kdbdmaKeyStream0,
402: kdbdmaIntNever,
403: kdbdmaBranchIfTrue,
404: kdbdmaWaitNever,
405: fBlockSize,
406: bufPhys+offset,
407: cmdStopPys);
408:
409: }
410: offset += fBlockSize;
411: }
412:
413: // Add a STOP:
414: IOMakeDBDMADescriptor( &cmds[2*i],
415: kdbdmaStop,
416: kdbdmaKeyStream0,
417: kdbdmaIntNever,
418: kdbdmaBranchNever,
419: kdbdmaWaitNever,
420: 0,
421: NULL);
422:
423: ioAudioStreamsDMA[index].fSharedStatus = status;
424: ioAudioStreamsDMA[index].fCmds = cmds;
425: ioAudioStreamsDMA[index].fCmdSize = cmdSize;
426: ioAudioStreamsDMA[index].fSampleBuffer = (int16_t *)bufs;
427: status->fVersion = 1;
428: status->fErases = ioAudioStreamsDMA[index].fNeedsErase;
429: status->fRunning = 0;
430: status->fConnections = 0;
431:
432: status->fBufSize = bufSize;
433: status->fBlockSize = fBlockSize;
434: status->fNumBlocks = numBlocks;
435: status->fSampleSize = 2;
436: status->fChannels = 2;
437: status->fDataRate = ioAudioStreamsDMA[index].fSampleRate * status->fSampleSize * status->fChannels;
438: status->fCurrentBlock = 0;
439: status->fEraseHeadBlock = 0;
440: status->fCurrentLoopCount = 0;
441: status->fMixBufferInUse = false;
442:
443: #ifdef DEBUGMODE
444: IOLog("DMA commands at 0x%x, %d blocks, seq at 0x%x\n", cmds, numBlocks, seqVirt);
445: IOLog("Block size %d, total size %d\n", fBlockSize, bufSize);
446: #endif
447:
448: flush_dcache((vm_offset_t) cmds, cmdSize, false );
449:
450: clock_get_uptime(&status->fLastLoopTime);
451:
452: IOSetDBDMAChannelControl( ioAudioStreamsDMA[index].fIOBaseDMA, IOClearDBDMAChannelControlBits(kdbdmaS0));
453: IOSetDBDMABranchSelect( ioAudioStreamsDMA[index].fIOBaseDMA, IOSetDBDMAChannelControlBits(kdbdmaS0));
454: IODBDMAStart( ioAudioStreamsDMA[index].fIOBaseDMA, cmdPhys );
455:
456: return status;
457: }
458:
459: void IOAudioBus::stopStream(AudioStreamIndex index)
460: {
461: IOFilterInterruptEventSource *interruptEventSource;
462: UInt8 attemptsToStop = 100;
463:
464: assert(!ioAudioStreamsDMA[index].fSharedStatus->fRunning);
465:
466: if (index == kAudioDMAOutputStream) {
467: interruptEventSource = fTxInterruptSource;
468: } else { // index == kAudioDMAInputStream
469: interruptEventSource = fRxInterruptSource;
470: }
471: interruptEventSource->disable();
472:
473: IOSetDBDMAChannelControl( ioAudioStreamsDMA[index].fIOBaseDMA, IOSetDBDMAChannelControlBits(kdbdmaS0));
474: while ((IOGetDBDMAChannelStatus(ioAudioStreamsDMA[index].fIOBaseDMA) & kdbdmaActive ) && (attemptsToStop--)) {
475: eieio();
476: IOSleep(10);
477: }
478:
479: IODBDMAStop( ioAudioStreamsDMA[index].fIOBaseDMA );
480: IODBDMAReset( ioAudioStreamsDMA[index].fIOBaseDMA );
481:
482: IOFreeAligned(ioAudioStreamsDMA[index].fCmds, ioAudioStreamsDMA[index].fCmdSize);
483: IOFreeAligned(ioAudioStreamsDMA[index].fSampleBuffer, round_page(ioAudioStreamsDMA[index].fSharedStatus->fBufSize));
484: IOFreeAligned(ioAudioStreamsDMA[index].fSharedStatus, round_page(sizeof(IOAudioStreamStatus)));
485:
486: ioAudioStreamsDMA[index].fCmds = NULL;
487: ioAudioStreamsDMA[index].fSampleBuffer = NULL;
488: ioAudioStreamsDMA[index].fSharedStatus = NULL;
489:
490: interruptEventSource->enable();
491: }
492:
493: void IOAudioBus::pauseStream(AudioStreamIndex index)
494: {
495: assert(index < numDMAStreams);
496: IODBDMAPause( ioAudioStreamsDMA[index].fIOBaseDMA );
497: }
498:
499: void IOAudioBus::resumeStream(AudioStreamIndex index)
500: {
501: assert(index < numDMAStreams);
502:
503: IODBDMAContinue( ioAudioStreamsDMA[index].fIOBaseDMA );
504: }
505:
506: IOAudioStreamStatus * IOAudioBus::getSharedStatus(AudioStreamIndex index)
507: {
508: assert(index < numDMAStreams);
509: return ioAudioStreamsDMA[index].fSharedStatus;
510: }
511:
512: void * IOAudioBus::getSampleBuffer(AudioStreamIndex index)
513: {
514: assert(index < numDMAStreams);
515: return ioAudioStreamsDMA[index].fSampleBuffer;
516: }
517:
518: #endif // __ppc__
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.