|
|
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: * IOAudioDevice.cpp
26: *
27: * HISTORY
28: *
29: */
30:
31: #include <IOKit/assert.h>
32:
33: #include <IOKit/IOLib.h>
34: #include <IOKit/IOSyncer.h>
35: #include <IOKit/IOWorkLoop.h>
36: #include <IOKit/IOCommandQueue.h>
37: #include <IOKit/IOMemoryDescriptor.h>
38: #include <IOKit/audio/IOAudioController.h>
39:
40: //************************************************************************
41: // Implementation of protocol classes.
42: //************************************************************************
43: OSDefineMetaClass( IOAudioStream, IOUserClient )
44: OSDefineAbstractStructors( IOAudioStream, IOUserClient )
45:
46: OSDefineMetaClass( IOAudioComponent, IOUserClient )
47: OSDefineAbstractStructors( IOAudioComponent, IOUserClient )
48:
49: //************************************************************************
50: // Begin implementation of IOAudioStreamImpl class.
51: //************************************************************************
52:
53: #undef super
54: #define super IOAudioStream
55: OSDefineMetaClassAndStructors( IOAudioStreamImpl, IOAudioStream )
56:
57: bool
58: IOAudioStreamImpl::initWithPropsIndexQueue(OSDictionary *props,
59: AudioStreamIndex index, IOCommandQueue *queue)
60: {
61: if(!super::init(props))
62: return false;
63:
64: if(!queue)
65: return false;
66:
67: fIndex = index;
68: fCmdQueue = queue;
69:
70: fMappedMem.fMixBuffer = NULL;
71:
72: // make sure essential stuff is there
73: assert(OSDynamicCast(OSNumber, getProperty("In")) != NULL);
74: assert(OSDynamicCast(OSNumber, getProperty("Out")) != NULL);
75:
76: fMethods[kCallSetFlow].object = this;
77: fMethods[kCallSetFlow].func = (IOMethod) &IOAudioStream::setFlow;
78: fMethods[kCallSetFlow].count0 = 1;
79: fMethods[kCallSetFlow].count1 = 0;
80: fMethods[kCallSetFlow].flags = kIOUCScalarIScalarO;
81:
82: fMethods[kCallFlush].object = this;
83: fMethods[kCallFlush].func = (IOMethod) &IOAudioStream::Flush;
84: fMethods[kCallFlush].count0 = sizeof(IOAudioStreamPosition);
85: fMethods[kCallFlush].count1 = 0;
86: fMethods[kCallFlush].flags = kIOUCStructIStructO;
87:
88: fMethods[kCallSetErase].object = this;
89: fMethods[kCallSetErase].func = (IOMethod) &IOAudioStream::setErase;
90: fMethods[kCallSetErase].count0 = 1;
91: fMethods[kCallSetErase].count1 = 1;
92: fMethods[kCallSetErase].flags = kIOUCScalarIScalarO;
93:
94: return true;
95: }
96:
97: void IOAudioStreamImpl::free()
98: {
99: if (fMappedMem.fMixBuffer) {
100: // Need to free mix buffer here - it will leak now
101: }
102:
103: super::free();
104: }
105:
106: /*
107: * Connect a client, possibly starting DMA for the stream if it's
108: * the first client.
109: */
110: IOReturn
111: IOAudioStreamImpl::newUserClient( task_t owningTask, void * security_id,
112: UInt32 type, IOUserClient ** handler )
113: {
114: IOSyncer *syncWakeup;
115:
116: *handler = this;
117: (*handler)->retain();
118:
119: syncWakeup = IOSyncer::create();
120:
121: fCmdQueue->enqueueCommand(true, syncWakeup, (void *)kConnect,
122: (void *)fIndex, &fMappedMem);
123:
124: syncWakeup->wait();
125:
126: return kIOReturnSuccess;
127: }
128:
129: IOReturn IOAudioStreamImpl::clientDied()
130: {
131: /*
132: * Decrememt connection count, possibly freeing DMA buffers
133: */
134: fCmdQueue->enqueueCommand(true, 0, (void *)kDetach, (void *)fIndex);
135:
136: return kIOReturnSuccess;
137: }
138:
139: IOReturn IOAudioStreamImpl::clientClose()
140: {
141: /*
142: * Decrememt connection count, possibly freeing DMA buffers
143: */
144: //fCmdQueue->enqueueCommand(true, 0, (void *)kDetach, (void *)fIndex);
145:
146: return kIOReturnSuccess;
147: }
148:
149: IOReturn IOAudioStreamImpl::Flush(IOAudioStreamPosition *end)
150: {
151: // Tell device when it'll be safe to stop the stream
152: fCmdQueue->enqueueCommand(true, 0, (void *)kFlush, (void *)fIndex, (void *)end);
153: return kIOReturnSuccess;
154: }
155:
156: IOReturn IOAudioStreamImpl::setFlow(bool flowing)
157: {
158: fCmdQueue->enqueueCommand(true, 0, (void *)kSetFlow, (void *)fIndex,
159: (void *)flowing);
160: return kIOReturnSuccess;
161: }
162:
163: IOReturn IOAudioStreamImpl::isOutput(SInt32 *res) const
164: {
165: const OSNumber *obj;
166: obj = getOutputDescriptor();
167: if(obj)
168: *res = obj->unsigned8BitValue();
169: else
170: *res = 0;
171:
172: return kIOReturnSuccess;
173: }
174:
175: IOReturn IOAudioStreamImpl::getMixBuffer(void **mixBuffer)
176: {
177: *mixBuffer = fMappedMem.fMixBuffer;
178:
179: return kIOReturnSuccess;
180: }
181:
182: IOReturn IOAudioStreamImpl::setErase(bool erase, SInt32 *oldErase)
183: {
184: assert(fMappedMem.fStatus != NULL); // Must be a user attached.
185: *oldErase = fMappedMem.fStatus->fErases;
186: fMappedMem.fStatus->fErases = erase;
187: return kIOReturnSuccess;
188: }
189:
190: IOReturn
191: IOAudioStreamImpl::setProperties( OSObject * properties )
192: {
193: return kIOReturnNotPrivileged;
194: }
195:
196:
197: IOReturn IOAudioStreamImpl::clientMemoryForType( UInt32 type,
198: UInt32 * flags, IOMemoryDescriptor ** memory )
199: {
200: // kprintf("IOAudioStream::clientMemoryForType(%d, %d, %d, %d)\n",
201: // type, flags, address, size);
202:
203: switch(type) {
204: case kSampleBuffer:
205: *memory = IOMemoryDescriptor::withAddress(
206: (void *)fMappedMem.fSampleBuffer,
207: fMappedMem.fStatus->fBufSize,
208: kIODirectionNone);
209: *flags = 0;
210: break;
211: case kStatus:
212: *memory = IOMemoryDescriptor::withAddress(
213: (void *)fMappedMem.fStatus,
214: sizeof(IOAudioStreamStatus),
215: kIODirectionNone);
216: *flags = kIOMapReadOnly;
217: break;
218: case kMixBuffer:
219: if (fMappedMem.fMixBuffer == NULL) {
220: IOSyncer *syncWakeup;
221:
222: syncWakeup = IOSyncer::create();
223:
224: fCmdQueue->enqueueCommand(true, syncWakeup, (void *)kAllocMixBuffer,
225: (void *)fIndex, (void *)&fMappedMem.fMixBuffer);
226: syncWakeup->wait();
227: }
228: fMappedMem.fStatus->fMixBufferInUse = true;
229: *memory = IOMemoryDescriptor::withAddress(
230: (void *)fMappedMem.fMixBuffer,
231: (fMappedMem.fStatus->fBufSize / fMappedMem.fStatus->fSampleSize * sizeof(float)),
232: kIODirectionNone);
233: *flags = 0;
234: break;
235: default:
236: return kIOReturnUnsupported;
237: break;
238: }
239: return kIOReturnSuccess;
240: }
241:
242: IOExternalMethod *
243: IOAudioStreamImpl::getExternalMethodForIndex( UInt32 index )
244: {
245: IOExternalMethod *method = NULL;
246:
247: if(index < kNumCalls)
248: method = &fMethods[index];
249: return method;
250: }
251:
252:
253: //************************************************************************
254: // Begin implementation of IOAudioComponentImpl class.
255: //************************************************************************
256:
257: #undef super
258: #define super IOAudioComponent
259: OSDefineMetaClassAndStructors( IOAudioComponentImpl, IOAudioComponent )
260:
261:
262: bool
263: IOAudioComponentImpl::initWithStuff(IOAudioController *owner, OSDictionary *props,
264: IOCommandQueue *queue)
265: {
266: if(!super::init(props))
267: return false;
268:
269: if(!queue || !owner)
270: return false;
271:
272: fCmdQueue = queue;
273: fOwner = owner;
274: return true;
275: }
276:
277: void
278: IOAudioComponentImpl::free()
279: {
280: if(fNotifyMsg)
281: IOFree(fNotifyMsg, sizeof (struct _notifyMsg));
282:
283: super::free();
284: }
285:
286: IOReturn
287: IOAudioComponentImpl::updateVal(UInt32 val, OSDictionary *control, bool direct)
288: {
289: IOReturn ret = kIOReturnSuccess;
290: OSNumber * oldVal;
291:
292: oldVal = (OSNumber *)control->getObject(IOAudioController::gValSym);
293: if(val != oldVal->unsigned32BitValue()) {
294: OSNumber * id;
295: OSNumber * newVal;
296: newVal = OSNumber::withNumber(val, oldVal->numberOfBits());
297: control->setObject(IOAudioController::gValSym, newVal);
298: id = (OSNumber *)control->getObject(IOAudioController::gIdSym);
299: if(id) {
300: if(direct)
301: fOwner->SetControl(id->unsigned16BitValue(), val);
302: else
303: fCmdQueue->enqueueCommand(true, 0, (void *)kSetVal,
304: (void *)id->unsigned16BitValue(), (void *)val);
305:
306: }
307: }
308: return ret;
309: }
310:
311: void
312: IOAudioComponentImpl::Set(const OSSymbol *type, const OSSymbol *name, int val)
313: {
314: OSDictionary *controls;
315:
316: controls = OSDynamicCast(OSDictionary, getProperty(type));
317:
318: if(controls) {
319: OSDictionary *valDict;
320: OSNumber * old;
321: OSNumber * newObj;
322: valDict = OSDynamicCast(OSDictionary,
323: controls->getObject(name));
324: if(valDict) {
325: old = OSDynamicCast(OSNumber, valDict->getObject(IOAudioController::gValSym));
326: if(old) {
327: newObj = OSNumber::withNumber(val, old->numberOfBits());
328: valDict->setObject(IOAudioController::gValSym, newObj);
329: newObj->release(); // XXX -- svail: added.
330: /* FIXME: Don't block */
331: if(fNotifyMsg)
332: mach_msg_send_from_kernel((mach_msg_header_t *)fNotifyMsg,
333: fNotifyMsg->h.msgh_size);
334: else if(type == IOAudioController::gInputsSym &&
335: name == IOAudioController::gJackSym &&
336: ( GetType() == IOAudioController::gHeadphonesSym ||
337: GetType() == IOAudioController::gLineOutSym)) {
338: /*
339: * This is a headphone or line out jack, mute/unmute any speakers
340: * with the same IOAudio parent
341: */
342: OSIterator * parents =
343: getParentIterator(IOAudioController::gIOAudioPlane);
344: IORegistryEntry *parent;
345: while((parent = OSDynamicCast(IORegistryEntry, parents->getNextObject()))) {
346: OSIterator * siblings =
347: parent->getChildIterator(IOAudioController::gIOAudioPlane);
348: IOAudioComponentImpl *sibling;
349: while((sibling = OSDynamicCast(IOAudioComponentImpl, siblings->getNextObject()))) {
350: if(sibling->GetType() == IOAudioController::gSpeakerSym) {
351: // Set all controls of type Mute to the new value
352: OSDictionary *spkrCtls =
353: OSDynamicCast(OSDictionary, sibling->getProperty(IOAudioController::gControlsSym));
354: OSCollectionIterator *iter = OSCollectionIterator::withCollection(spkrCtls);
355: OSSymbol *iterKey;
356: while((iterKey = OSDynamicCast(OSSymbol, iter->getNextObject()))){
357: OSObject *spkrCtlObj = spkrCtls->getObject(iterKey);
358: if(GetType(spkrCtlObj) == IOAudioController::gMuteSym) {
359: // Safe to just cast because GetType checks object type.
360: // Update hardware directly
361: updateVal(val, (OSDictionary *)spkrCtlObj, true);
362: }
363: }
364: }
365: }
366: }
367: }
368: }
369: }
370: }
371: }
372:
373: IOReturn IOAudioComponentImpl::clientClose( void )
374: {
375: return kIOReturnSuccess;
376: }
377:
378: IOReturn IOAudioComponentImpl::clientDied( void )
379: {
380: return kIOReturnSuccess;
381: }
382: /*
383: * Return a subclass of IOUserClient for User<->kernel comminication
384: * Since IOAudioStream is such a suclass, we can return the object
385: * itself (remembering to increment its retain count!).
386: */
387: IOReturn IOAudioComponentImpl::newUserClient( task_t owningTask,
388: void * security_id, UInt32 type, IOUserClient ** handler )
389: {
390: //kprintf("task:%d, sec_id:0x%x, type:%d\n", owningTask, security_id, type);
391: *handler = this;
392: (*handler)->retain();
393:
394: return kIOReturnSuccess;
395: }
396:
397:
398: IOReturn
399: IOAudioComponentImpl::setProperties( OSObject * properties )
400: {
401: OSDictionary *myControls;
402: OSDictionary *newControls;
403: OSDictionary *newDict;
404: OSCollectionIterator *iter;
405: OSObject *iterKey;
406: IOReturn ret = kIOReturnSuccess;
407:
408: newDict = OSDynamicCast(OSDictionary, properties);
409: if(!newDict)
410: return kIOReturnBadArgument;
411:
412: myControls = OSDynamicCast(OSDictionary, getProperty(IOAudioController::gControlsSym));
413: newControls = OSDynamicCast(OSDictionary, newDict->getObject(IOAudioController::gControlsSym));
414: if(!newControls)
415: return kIOReturnBadArgument;
416:
417: /*
418: * Look through the Controls dictionary, for each one that has a new Val
419: * make a kSetVal command, updating the hardware.
420: */
421: iter = OSCollectionIterator::withCollection(newControls);
422: while((iterKey = iter->getNextObject())) {
423: OSSymbol *key = OSDynamicCast(OSSymbol, iterKey);
424: OSDictionary *newCtrl;
425: OSNumber* newVal;
426: if(!key) {
427: ret = kIOReturnBadArgument;
428: break;
429: }
430: OSDictionary *myCtrl;
431: myCtrl = (OSDictionary *)myControls->getObject(key);
432: if(!myCtrl) {
433: ret = kIOReturnBadArgument;
434: break;
435: }
436: newCtrl = OSDynamicCast(OSDictionary, newControls->getObject(key));
437: if(!newCtrl) {
438: ret = kIOReturnBadArgument;
439: break;
440: }
441: newVal = OSDynamicCast(OSNumber, newCtrl->getObject(IOAudioController::gValSym));
442: if(!newVal) {
443: ret = kIOReturnBadArgument;
444: break;
445: }
446: // Update hardware via command queue
447: ret = updateVal(newVal->unsigned16BitValue(), myCtrl, false);
448: if(kIOReturnSuccess != ret)
449: break;
450: }
451:
452: return ret;
453: }
454:
455: IOReturn
456: IOAudioComponentImpl::registerNotificationPort(
457: mach_port_t port, UInt32 type, UInt32 refCon)
458: {
459: static IOAudioNotifyMsg notify_msg = {{
460: // mach_msg_bits_t msgh_bits;
461: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
462: // mach_msg_size_t msgh_size;
463: sizeof (IOAudioNotifyMsg),
464: // mach_port_t msgh_remote_port;
465: MACH_PORT_NULL,
466: // mach_port_t msgh_local_port;
467: MACH_PORT_NULL,
468: // mach_msg_size_t msgh_reserved;
469: 0,
470: // mach_msg_id_t msgh_id;
471: type },
472: // UInt32 refCon
473: refCon
474: };
475:
476: if( type != kIOAudioInputNotification)
477: return( kIOReturnUnsupported);
478: if ( fNotifyMsg == NULL )
479: fNotifyMsg = (struct _notifyMsg *)
480: IOMalloc( sizeof (IOAudioNotifyMsg) );
481: // Initialize the events available message.
482: *fNotifyMsg = notify_msg;
483:
484: fNotifyMsg->h.msgh_remote_port = port;
485:
486: return kIOReturnSuccess;
487: }
488:
489: const OSSymbol *
490: IOAudioComponentImpl::GetType() const
491: {
492: const OSString *type;
493: type = OSDynamicCast(OSString, getProperty(IOAudioController::gTypeSym));
494:
495: return OSSymbol::withString(type);
496: }
497:
498: const OSSymbol *
499: IOAudioComponentImpl::GetType(const OSObject *obj) const
500: {
501: const OSString *type;
502: const OSDictionary *dict;
503: dict = OSDynamicCast(OSDictionary, obj);
504: if(NULL == dict)
505: return NULL;
506: type = OSDynamicCast(OSString, dict->getObject(IOAudioController::gTypeSym));
507:
508: return OSSymbol::withString(type);
509: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.