|
|
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: * IOAudioController.cpp
26: *
27: * HISTORY
28: *
29: */
30:
31: #include <IOKit/assert.h>
32:
33: #include <IOKit/IOLib.h>
34: #include <IOKit/IOKitKeys.h>
35: #include <IOKit/IOSyncer.h>
36: #include <IOKit/IOWorkLoop.h>
37: #include <IOKit/IOCommandQueue.h>
38: #include <IOKit/IOTimerEventSource.h>
39: #include <IOKit/IOMemoryDescriptor.h>
40: #include <IOKit/audio/IOAudioController.h>
41:
42: #include <libkern/c++/OSSet.h>
43:
44: const IORegistryPlane * IOAudioController::gIOAudioPlane = NULL;
45: const OSSymbol * IOAudioController::gValSym = NULL;
46: const OSSymbol * IOAudioController::gTypeSym = NULL;
47: const OSSymbol * IOAudioController::gInputsSym = NULL;
48: const OSSymbol * IOAudioController::gControlsSym = NULL;
49: const OSSymbol * IOAudioController::gJackSym = NULL;
50: const OSSymbol * IOAudioController::gSpeakerSym = NULL;
51: const OSSymbol * IOAudioController::gHeadphonesSym = NULL;
52: const OSSymbol * IOAudioController::gLineOutSym = NULL;
53: const OSSymbol * IOAudioController::gMuteSym = NULL;
54: const OSSymbol * IOAudioController::gIdSym = NULL;
55: const OSSymbol * IOAudioController::gMasterSym = NULL;
56:
57: #define TIMER_INTS_PER_BUF 4
58: #define MAX_POLL_INTERVAL_SEC 60
59:
60: //************************************************************************
61: // Implementation of protocol clas.
62: //************************************************************************
63: OSDefineMetaClass( IOAudio, IOService )
64: OSDefineAbstractStructors( IOAudio, IOService )
65:
66: //************************************************************************
67: // Begin implementation of IOAudioController class.
68: //************************************************************************
69:
70: #undef super
71: #define super IOAudio
72:
73: OSDefineMetaClass( IOAudioController, IOAudio )
74: OSDefineAbstractStructors( IOAudioController, IOAudio )
75:
76: bool IOAudioController::init(OSDictionary *properties)
77: {
78: if (!super::init(properties)) {
79: return false;
80: }
81:
82: fMasterVolumeComponents = OSSet::withCapacity(1);
83: fNumStreamsInUse = 0;
84:
85: nanoseconds_to_absolutetime((UInt64)(MAX_POLL_INTERVAL_SEC) * (UInt64)NSEC_PER_SEC, &fMaxPollInterval);
86:
87: return true;
88: }
89:
90: bool IOAudioController::start( IOService *provider )
91: {
92: if (!super::start(provider))
93: return false;
94:
95: fDevice = provider;
96:
97: return true;
98: }
99:
100: void IOAudioController::execAndSignal(OSObject * obj, void *field0, void *field1, void *field2, void *field3)
101: {
102: IOAudioController *me = (IOAudioController *)obj;
103: IOSyncer *syncer = (IOSyncer *) field0;
104: IOAudioCmd cmd = (IOAudioCmd) (int) field1;
105:
106: me->execCommand(cmd, field2, field3);
107:
108: if(syncer)
109: syncer->signal();
110: }
111:
112: void IOAudioController::execCommand(IOAudioCmd cmd, void *field2, void *field3)
113: {
114: switch (cmd) {
115: case kConnect:
116: getMap((AudioStreamIndex)field2, (IOAudioStreamMap *)field3);
117: break;
118:
119: case kDetach:
120: releaseMap((AudioStreamIndex)field2);
121: break;
122:
123: case kSetFlow:
124: setFlow((AudioStreamIndex)field2, (bool)field3);
125: break;
126:
127: case kProbeStreams:
128: int numStreams, i;
129: numStreams = probeStreams();
130: fStreams = OSArray::withCapacity(numStreams);
131: if(fStreams) {
132: for(i=0; i<numStreams; i++) {
133: IOAudioStream *stream;
134: stream = createAudioStream(i);
135: if(stream) {
136: fStreams->setObject(i, stream);
137: stream->attach(this);
138: stream->registerService();
139: }
140: }
141: CreateAudioTopology(fQueue);
142: }
143: // Start the timer event source, if necessary (eg polling Awacs inputs)
144: AbsoluteTime pollInterval, wantTick;
145:
146: pollInterval = fMaxPollInterval;
147: calculateTickInterval(&pollInterval);
148: if(CMP_ABSOLUTETIME(&pollInterval, &fMaxPollInterval) < 0) {
149: clock_get_uptime(&wantTick);
150: ADD_ABSOLUTETIME(&wantTick, &pollInterval);
151: fNextTick = wantTick;
152: fTimer->wakeAtTime(fNextTick);
153: fTimerInUse = true;
154: fWorkLoop->addEventSource(fTimer);
155: }
156:
157: break;
158:
159: case kSetVal:
160: SetControl((UInt16)field2, (UInt16)field3);
161: break;
162:
163: case kFlush:
164: flushStream((AudioStreamIndex)field2, (IOAudioStreamPosition *)field3);
165: break;
166:
167: case kAllocMixBuffer:
168: if (*(void **)field3 == NULL) {
169: *(void **)field3 = allocateMixBuffer((AudioStreamIndex)field2);
170: }
171: break;
172:
173: default:
174: IOLog("Unexpected command %d in IOAudioController::execCommand!\n", cmd);
175:
176: }
177: }
178:
179: void IOAudioController::clockTick(OSObject * obj, IOTimerEventSource *timer)
180: {
181: ((IOAudioController *)obj)->DoClockTick(timer);
182: }
183:
184: void IOAudioController::DoClockTick(IOTimerEventSource *timer)
185: {
186: AudioStreamIndex stream;
187: AudioStreamIndex end;
188:
189: if(fStreams)
190: end = fStreams->getCount();
191: else
192: end = 0;
193:
194: for(stream = 0; stream < end; stream++) {
195: IOAudioStreamStatus *status = getSharedStatus(stream);
196:
197: if(status && status->fRunning) {
198: AbsoluteTime now;
199:
200: clock_get_uptime(&now);
201:
202: // Do buffer clearing before potentially removing the buffer!
203: if(status->fErases) {
204: UInt32 currentBlock;
205:
206: // Clear buffer behind DMA back to last erase point
207: char *buf = (char *)getSampleBuffer(stream);
208: char *mixBuf = (char *)getMixBuffer(stream);
209:
210: currentBlock = status->fCurrentBlock;
211:
212: if(currentBlock < status->fEraseHeadBlock) {
213: if (buf) {
214: bzero(buf, currentBlock * status->fBlockSize);
215: bzero(buf + (status->fEraseHeadBlock * status->fBlockSize),
216: status->fBufSize - (status->fEraseHeadBlock * status->fBlockSize));
217: }
218: if (mixBuf) {
219: bzero(mixBuf, currentBlock * status->fBlockSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE);
220: bzero(mixBuf + (status->fEraseHeadBlock * status->fBlockSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE),
221: (status->fBufSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE) - (status->fEraseHeadBlock * status->fBlockSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE));
222: }
223: }
224: else {
225: if (buf) {
226: bzero(buf + (status->fEraseHeadBlock * status->fBlockSize),
227: (currentBlock - status->fEraseHeadBlock) * status->fBlockSize);
228: }
229: if (mixBuf) {
230: bzero(mixBuf + (status->fEraseHeadBlock * status->fBlockSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE),
231: (currentBlock - status->fEraseHeadBlock) * status->fBlockSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE);
232: }
233: }
234:
235: status->fEraseHeadBlock = currentBlock;
236: }
237: if(status->fConnections == 0) {
238: UInt32 currentBlock, currentLoopCount;
239:
240: currentLoopCount = status->fCurrentLoopCount;
241: currentBlock = status->fCurrentBlock;
242:
243: // See if its time to stop (we have completed flushing output buffers)
244: if ((currentLoopCount > status->fFlushEnd.fLoopCount)
245: || ((currentLoopCount == status->fFlushEnd.fLoopCount)
246: && (currentBlock > status->fFlushEnd.fBlock))) {
247: AbsoluteTime pollInterval;
248: status->fRunning = 0;
249: stopStream(stream);
250: fNumStreamsInUse--;
251: if (fNumStreamsInUse == 0) {
252: pollInterval = fMaxPollInterval;
253: calculateTickInterval(&pollInterval);
254: if(CMP_ABSOLUTETIME(&pollInterval, &fMaxPollInterval) < 0) {
255: fWorkLoop->removeEventSource(fTimer);
256: fTimerInUse = false;
257: }
258: }
259: }
260: }
261: }
262: }
263:
264: if(fTimerInUse) {
265: fTimer->setTimeout(fTickPeriod);
266: }
267: }
268:
269: //------------------------------------------------------------------------
270: /*
271: * startWorkLoop()
272: *
273: * Drivers call this after initializing their hardware
274: * We ask the device here how many initial audio channels it has, create appropriate nubs,
275: * and then start the work loop running
276: */
277: void IOAudioController::startWorkLoop()
278: {
279: if(NULL == gIOAudioPlane) {
280: gIOAudioPlane = IORegistryEntry::makePlane( kIOAudioPlane );
281: }
282:
283: if(NULL == gValSym) {
284: gValSym = OSSymbol::withCString("Val");
285: gInputsSym = OSSymbol::withCString("Inputs");
286: gControlsSym = OSSymbol::withCString("Controls");
287: gJackSym = OSSymbol::withCString("Jack");
288: gSpeakerSym = OSSymbol::withCString("Speaker");
289: gHeadphonesSym = OSSymbol::withCString("Headphones");
290: gLineOutSym = OSSymbol::withCString("LineOut");
291: gTypeSym = OSSymbol::withCString("Type");
292: gMuteSym = OSSymbol::withCString("Mute");
293: gIdSym = OSSymbol::withCString("Id");
294: gMasterSym = OSSymbol::withCString("Master");
295: }
296:
297: fTimer = IOTimerEventSource::timerEventSource(this, &clockTick);
298: fQueue = IOCommandQueue::commandQueue(this, &execAndSignal);
299:
300: fWorkLoop = createWorkLoop();
301: fWorkLoop->addEventSource(fQueue);
302:
303: fQueue->enqueueCommand(true, 0, (void *)kProbeStreams, 0);
304:
305: registerService();
306: }
307:
308: IOWorkLoop *IOAudioController::getWorkLoop() const
309: {
310: return fWorkLoop;
311: }
312:
313: IOWorkLoop * IOAudioController::createWorkLoop()
314: {
315: IOWorkLoop *loop;
316:
317: loop = new IOWorkLoop();
318: if(loop && !loop->init()) {
319: loop->release();
320: loop = NULL;
321: }
322: return loop;
323: }
324:
325: IOAudioStream *IOAudioController::createAudioStream(AudioStreamIndex index)
326: {
327: OSDictionary *props = getStreamProperties(index);
328: IOAudioStreamImpl *stream;
329: SInt32 isOut;
330: IOReturn err;
331:
332: if(!props)
333: return NULL;
334:
335: stream = new IOAudioStreamImpl;
336: if(stream)
337: stream->initWithPropsIndexQueue(props, index, fQueue);
338:
339: props->release(); // Finished with this now.
340:
341: /*
342: * Output streams are the start of a sound chain, so put
343: * them at the root of the IOAudio plane.
344: */
345: err = stream->isOutput(&isOut);
346: if(!err && isOut)
347: stream->attachToParent(getRegistryRoot(), gIOAudioPlane);
348:
349: return stream;
350: }
351:
352: IOAudioComponentImpl *
353: IOAudioController::buildComponentAndAttach(IORegistryEntry *parent,
354: IORegistryEntry *child, const char *serialProps,
355: IOCommandQueue *queue)
356: {
357: OSDictionary *dict;
358: OSString *errorString;
359: IOAudioComponentImpl * aComp;
360: OSNumber *masterVal;
361:
362: aComp = new IOAudioComponentImpl;
363: if(!aComp)
364: return NULL;
365:
366: dict = OSDynamicCast(OSDictionary, OSUnserialize(serialProps, &errorString));
367: if (!dict && errorString) {
368: IOLog("%s\n", errorString->getCStringNoCopy());
369: errorString->release();
370: }
371: if(!aComp->initWithStuff(this, dict, queue)) {
372: aComp->release();
373: return NULL;
374: }
375:
376: if(!parent)
377: parent = getRegistryRoot();
378:
379: aComp->attachToParent(parent, gIOAudioPlane);
380:
381: if(child)
382: child->attachToParent(aComp, gIOAudioPlane);
383:
384: masterVal = (OSNumber *)dict->getObject(gMasterSym);
385: if ((masterVal != NULL) && (masterVal->unsigned32BitValue() != 0)) {
386: fMasterVolumeComponents->setObject(aComp);
387: }
388:
389: return aComp;
390: }
391:
392: void IOAudioController::AttachComponents(IORegistryEntry *parent,
393: IORegistryEntry *child)
394: {
395: child->attachToParent(parent, gIOAudioPlane);
396: }
397:
398:
399: void IOAudioController::free()
400: {
401: if (fMasterVolumeComponents)
402: fMasterVolumeComponents->release();
403: if(fWorkLoop)
404: fWorkLoop->release();
405: if(fQueue)
406: fQueue->release();
407: if(fTimer)
408: fTimer->release();
409: if(fStreams)
410: fStreams->release();
411: super::free();
412: }
413:
414: void IOAudioController::calculateTickInterval(AbsoluteTime *tickInterval)
415: {
416: AudioStreamIndex stream;
417: AudioStreamIndex end;
418:
419: if(fStreams)
420: end = fStreams->getCount();
421: else
422: end = 0;
423:
424: for(stream = 0; stream < end; stream++) {
425: IOAudioStreamStatus *status = getSharedStatus(stream);
426: if(status) {
427: AbsoluteTime pollInterval;
428:
429: nanoseconds_to_absolutetime(((UInt64)NSEC_PER_SEC * (UInt64)status->fBufSize / (UInt64)status->fDataRate / (UInt64)TIMER_INTS_PER_BUF), &pollInterval);
430:
431: if (CMP_ABSOLUTETIME(&pollInterval, tickInterval) < 0) {
432: *tickInterval = pollInterval;
433: }
434: }
435: }
436:
437: // Save the minimum period
438: fTickPeriod = *tickInterval;
439: }
440:
441: /*
442: * Map stream data for caller.
443: */
444: void IOAudioController::getMap(AudioStreamIndex index, IOAudioStreamMap *map)
445: {
446: IOAudioStreamStatus * status = getSharedStatus(index);
447:
448: if(!status) {
449: fNumStreamsInUse++;
450: status = startStream(index);
451: if(status) {
452: AbsoluteTime pollInterval, wantTick;
453:
454: //map->fMixBuffer = (void *)IOMallocAligned(round_page(status->fBufSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE), PAGE_SIZE);
455:
456: clock_get_uptime(&wantTick);
457: if(status->fErases) {
458: status->fEraseHeadBlock = 0;
459: }
460:
461: status->fFlushEnd.fBlock = 0;
462: status->fFlushEnd.fLoopCount = 0;
463: status->fMixBufferInUse = false;
464:
465: pollInterval = fMaxPollInterval;
466: calculateTickInterval(&pollInterval);
467:
468: ADD_ABSOLUTETIME(&wantTick, &pollInterval);
469:
470: if(!fTimerInUse || (CMP_ABSOLUTETIME(&wantTick, &fNextTick) < 0)) {
471: fNextTick = wantTick;
472: fTimer->wakeAtTime(fNextTick);
473: }
474: if(!fTimerInUse) {
475: fTimerInUse = true;
476: fWorkLoop->addEventSource(fTimer);
477: }
478: setFlow(index, true);
479: }
480: else {
481: map->fStatus = NULL;
482: map->fSampleBuffer = NULL;
483: //map->fMixBuffer = NULL;
484: fNumStreamsInUse--;
485: return;
486: }
487: }
488: status->fConnections = 1;
489: map->fStatus = status;
490: map->fSampleBuffer = getSampleBuffer(index);
491: }
492:
493: void IOAudioController::releaseMap(AudioStreamIndex index)
494: {
495: IOAudioStreamStatus * status = getSharedStatus(index);
496:
497: if (status) {
498: status->fConnections = 0;
499: }
500: }
501:
502: void IOAudioController::setFlow(AudioStreamIndex index, bool flowing)
503: {
504: IOAudioStreamStatus * status = getSharedStatus(index);
505: if(status) {
506: if(flowing) {
507: if(status->fRunning++ == 0) {
508: fNumStreamsInUse++;
509: resumeStream(index);
510: }
511: }
512: else {
513: if(--status->fRunning == 0) {
514: pauseStream(index);
515: fNumStreamsInUse--;
516: }
517: }
518: }
519: }
520:
521: void IOAudioController::flushStream(AudioStreamIndex index, IOAudioStreamPosition *endingPosition)
522: {
523: IOAudioStreamStatus *status = getSharedStatus(index);
524:
525: if (status) {
526: if ((endingPosition->fLoopCount > status->fFlushEnd.fLoopCount) || ((endingPosition->fLoopCount == status->fFlushEnd.fLoopCount) && (endingPosition->fBlock > status->fFlushEnd.fBlock))) {
527: status->fFlushEnd = *endingPosition;
528: }
529: }
530: }
531:
532: void *IOAudioController::allocateMixBuffer(AudioStreamIndex index)
533: {
534: IOAudioStreamStatus * status = getSharedStatus(index);
535: void *mixBuffer = NULL;
536:
537: if(status) {
538: mixBuffer = (void *)IOMallocAligned(round_page(status->fBufSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE), PAGE_SIZE);
539: bzero (mixBuffer, round_page(status->fBufSize / status->fSampleSize * MIX_BUFFER_SAMPLE_SIZE));
540: status->fMixBufferInUse = true;
541: }
542:
543: return mixBuffer;
544: }
545: void *IOAudioController::getMixBuffer(AudioStreamIndex index)
546: {
547: void *mixBuffer = NULL;
548: if (fStreams) {
549: IOAudioStreamImpl *stream = (IOAudioStreamImpl *)fStreams->getObject(index);
550: if (stream) {
551: if (stream->getMixBuffer(&mixBuffer) != kIOReturnSuccess) {
552: mixBuffer = NULL;
553: }
554: }
555: }
556:
557: return mixBuffer;
558: }
559:
560: void IOAudioController::setMasterComponentsProperties(OSDictionary *properties)
561: {
562: if (properties) {
563: OSCollectionIterator *iter;
564:
565: iter = OSCollectionIterator::withCollection(fMasterVolumeComponents);
566: if (iter) {
567: IOAudioComponent *component;
568:
569: while ((component = OSDynamicCast(IOAudioComponent, iter->getNextObject())) != NULL) {
570: component->setProperties(properties);
571: }
572: }
573: }
574: }
575: void IOAudioController::setMasterVolumeLeft(UInt16 newMasterVolumeLeft)
576: {
577: OSDictionary *controlDict;
578: OSString *errorString;
579: char controlDictString[51]; // strlen(formatString) + 5 (max chars in 16-bit int) + 1 (terminator)
580:
581: sprintf (controlDictString, "{'Controls'={'VolumeLeft'={'Val'=%d:16;};};};", newMasterVolumeLeft);
582: controlDict = OSDynamicCast(OSDictionary, OSUnserialize(controlDictString, &errorString));
583:
584: if (controlDict) {
585: setMasterComponentsProperties(controlDict);
586: controlDict->release();
587: } else if (errorString) {
588: IOLog("IOAudioController: %s\n", errorString->getCStringNoCopy());
589: errorString->release();
590: }
591: }
592:
593: void IOAudioController::setMasterVolumeRight(UInt16 newMasterVolumeRight)
594: {
595: OSDictionary *controlDict;
596: OSString *errorString;
597: char controlDictString[52]; // strlen(formatString) + 5 (max chars in 16-bit int) + 1 (terminator)
598:
599: // FIXME - We really should scale to min/max in this control...
600: sprintf (controlDictString, "{'Controls'={'VolumeRight'={'Val'=%d:16;};};};", newMasterVolumeRight);
601: controlDict = OSDynamicCast(OSDictionary, OSUnserialize(controlDictString, &errorString));
602:
603: if (controlDict) {
604: setMasterComponentsProperties(controlDict);
605: controlDict->release();
606: } else if (errorString) {
607: IOLog("IOAudioController: %s\n", errorString->getCStringNoCopy());
608: errorString->release();
609: }
610: }
611:
612: void IOAudioController::setMasterMute(bool newMasterMute)
613: {
614: OSDictionary *controlDict;
615: OSString *errorString;
616: char controlDictString[43]; // strlen(formatString) + 1 (single digit) + 1 (terminator)
617:
618: sprintf (controlDictString, "{'Controls'={'MuteAll'={'Val'=%d:8;};};};", newMasterMute ? 1 : 0);
619: controlDict = OSDynamicCast(OSDictionary, OSUnserialize(controlDictString, &errorString));
620:
621: if (controlDict) {
622: setMasterComponentsProperties(controlDict);
623: controlDict->release();
624: } else if (errorString) {
625: IOLog("IOAudioController: %s\n", errorString->getCStringNoCopy());
626: errorString->release();
627: }
628: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.