source: cmedia/trunk/Drv16/ioctl.cpp@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 34.2 KB
Line 
1/* $Id: ioctl.cpp,v 1.7 2001/04/30 21:07:57 sandervl Exp $ */
2
3/* SCCSID = %W% %E% */
4/****************************************************************************
5 * *
6 * Copyright (c) IBM Corporation 1994 - 1997. *
7 * *
8 * The following IBM OS/2 source code is provided to you solely for the *
9 * the purpose of assisting you in your development of OS/2 device drivers. *
10 * You may use this code in accordance with the IBM License Agreement *
11 * provided in the IBM Device Driver Source Kit for OS/2. *
12 * *
13 ****************************************************************************/
14/**@internal %W%
15 * @notes
16 * the functions that implement all the IOCTLs (command 10x) received by
17 * the device driver via the strategy entry.
18 * @version %I%
19 * @context Unless otherwise noted, all interfaces are Ring-0, 16-bit,
20 * <stack context>.
21 * @history
22 *
23 */
24#define INCL_NOPMAPI
25#define INCL_DOSINFOSEG
26#define INCL_DOSERRORS
27#include <os2.h>
28#include <os2me.h>
29#include <audio.h>
30
31#include "strategy.h"
32#include "audiohw.hpp"
33#include "mpu401.hpp"
34#include "waudio.hpp"
35#include "dwavestrm.hpp"
36#include "midistrm.hpp"
37
38#include <include.h>
39#include <sbvsd.h>
40#include <dbgos2.h>
41#include <devhelp.h>
42#include <ossidc.h>
43#include <ioctl90.h>
44#include <parse.h>
45#include "ioctl.h"
46
47#include <daudio.h>
48
49#include "trace.h"
50
51
52#define VSD_ID 0
53
54
55//Map of possible 256 supported ioctls (IOCTl 90 mixer api)
56static UCHAR MixerApiMap[256];
57static MIXSTRUCT MixerSettings[16];
58
59//override flags for rec src & gain mixer commands
60BOOL fRecSrcIOCTL90 = FALSE;
61BOOL fRecGainIOCTL90 = FALSE;
62BOOL fStreamVolIOCTL90 = FALSE;
63struct _CALLBACKREC *pCallbackList = NULL;
64
65
66//******************************************************************************
67//******************************************************************************
68
69typedef struct _CALLBACKREC
70{
71 struct _CALLBACKREC *pNext;
72 USHORT usOwnerID;
73 ULONG hevNotify;
74} CALLBACKREC;
75
76CALLBACKREC *FindCallback(USHORT usSearchID)
77{
78 CALLBACKREC *p = pCallbackList;
79 while( p && p->usOwnerID != usSearchID ) p = p->pNext;
80 return p;
81}
82
83BOOL AddCallback(USHORT usOwnerID, ULONG ulEvent)
84{
85 CALLBACKREC *p;
86
87 if( DevHelp_OpenEventSem(ulEvent) == 0 )
88 {
89 DevHelp_CloseEventSem(ulEvent);
90
91 if( (p = new CALLBACKREC) != NULL )
92 {
93 p->usOwnerID = usOwnerID;
94 p->hevNotify = ulEvent;
95 p->pNext = pCallbackList;
96 pCallbackList = p;
97 return TRUE;
98 }
99 }
100
101 return FALSE;
102}
103
104BOOL RemoveCallback(CALLBACKREC *pCallback)
105{
106 CALLBACKREC *p = pCallbackList;
107
108 if( p == pCallback ) {
109 pCallbackList = pCallback->pNext; delete pCallback; return TRUE;
110 }
111
112 while( p ) {
113 if( p->pNext == pCallback ) {
114 p->pNext = pCallback->pNext; delete pCallback; return TRUE;
115 }
116 p = p->pNext;
117 }
118
119 return FALSE;
120}
121
122void MixerChangeCleanup(USHORT usCallerID)
123{
124 CALLBACKREC *p = FindCallback(usCallerID);
125 if( p ) RemoveCallback(p);
126}
127
128void MixerChangeNotify(USHORT usCallerID)
129{
130 CALLBACKREC *p;
131 ULONG ulNumPosts, linNumPostsPtr;
132
133 if( DevHelp_VirtToLin(_SS(), (USHORT)&ulNumPosts, &linNumPostsPtr) == 0 )
134 {
135 p = pCallbackList;
136 while( p )
137 {
138 if( p->usOwnerID != usCallerID &&
139 DevHelp_OpenEventSem(p->hevNotify) == 0 )
140 {
141 DevHelp_PostEventSem(p->hevNotify);
142 DevHelp_ResetEventSem(p->hevNotify, linNumPostsPtr);
143 DevHelp_CloseEventSem(p->hevNotify);
144 }
145
146 p = p->pNext;
147 }
148 }
149}
150
151
152
153//******************************************************************************
154// Rudi: Helper to verify data/param packet
155//******************************************************************************
156
157USHORT QueryPercentage(ULONG ulCurrVal, USHORT usMaxVal)
158{
159 USHORT usPercent = (USHORT)((ulCurrVal * 100) / usMaxVal);
160 return ( usPercent > 100 ) ? 100 : usPercent;
161}
162
163
164//******************************************************************************
165// Rudi: Helper to verify data/param packet
166//******************************************************************************
167
168BOOL VerifyAccess(VOID FAR *pData,
169 USHORT usCurrLen, USHORT usMinLen, UCHAR uchAccess)
170{
171 return usCurrLen >= usMinLen &&
172 OFFSETOF(pData) <= (USHORT)~usCurrLen &&
173 DevHelp_VerifyAccess(SELECTOROF(pData), usCurrLen,
174 OFFSETOF(pData), uchAccess) == 0;
175}
176
177
178
179//******************************************************************************
180//******************************************************************************
181
182/**@internal
183 * @param PREQPACKET pointer to the strategy request packet
184 * @return None But the Status in the request packet is updated on error
185 * @notes
186 * The Audio Init Ioctl only 2 things happen in here :
187 * 1. We call CheckForStream to make sure there is not already a stream
188 * registered with the same sysfilenumber. If we get a good rc from that
189 * 2: we look at sMode in the MCI_AUDIO_INIT to determine the type of stream
190 * to init and call the approprate stream constructor.
191 *
192 */
193void IoctlAudioInit(PREQPACKET prp, USHORT LDev)
194{
195 PAUDIOHW pHWobj;
196 PSTREAM pstream;
197 USHORT HardwareType;
198 LPMCI_AUDIO_INIT p = (LPMCI_AUDIO_INIT)prp->s.ioctl.pvData;
199
200 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
201 sizeof(MCI_AUDIO_INIT), VERIFY_READWRITE) )
202 {
203 dprintf(("Invalid MCI_AUDIO_INIT pointer %lx!!", (ULONG)p));
204 prp->usStatus |= RPERR | RPBADPARAM;
205 return;
206 }
207
208 pstream = FindStream_fromFile(prp->s.ioctl.usSysFileNum);
209
210#ifndef NOTRACE
211 struct { ULONG streamid; ULONG mode; } TraceData;
212 TraceData.streamid = (ULONG)pstream;
213 TraceData.mode = p->sMode;
214 SYSTRACE(241, 20, TraceData);
215#endif
216
217 // if this is an IDLE or De-Init request
218 // fetch the stream object based on the sysfilenum and turn on the
219 // stream idle bit in the stream state then write the sysfilenum
220 // into the request packet, set rc = 0 and return
221 if (p->sMode == IDLE) {
222 if (pstream)
223 pstream->usStreamState |= STREAM_IDLE;
224 p->pvReserved = (VOID FAR *) (ULONG)prp->s.ioctl.usSysFileNum;
225 p->sReturnCode = 0;
226 return;
227 }
228 // call FindStream_fromFile to see if there is already a stream
229 // for this sysfilenum. if there is then see if the idle bit is on,
230 // if the idle bit is on, reset it, then write the sysfilenum
231 // into the request packet, set rc = 0 and return
232 // MMPM sends idle down to a stream that is "losing" the hardware but
233 // should not go away. It usually is associated with an app losing
234 // focus. If the idle bit is not the stream is either not registered or
235 // is being "re-initted" in another mode or with different file
236 // attributes. "Re-initting" a stream is a total hack on the part
237 // of MMPM they should de-register the stream and then init a new
238 // stream but they don't . If anyone ever writes a VSD that behaves
239 // "correctly" then this code can be deleted.
240 // Either way delete the stream and build a new one with
241 // this request packet.
242
243 if (pstream) {
244 if (pstream->usStreamState & STREAM_IDLE) {
245 pstream->usStreamState &= STREAM_NOT_IDLE;
246 p->pvReserved = (VOID FAR *) (ULONG)prp->s.ioctl.usSysFileNum;
247 p->sReturnCode = 0;
248 return;
249 }
250 else {
251#if 1
252 // Rudi: Workaround for MMPM device sharing bug
253 if (pstream->usStreamState & STREAM_STREAMING) {
254 CONTROL_PARM dummy;
255 pstream->PauseStream(&dummy);
256 pstream->ResumeStream();
257 p->pvReserved = (VOID FAR *) (ULONG)prp->s.ioctl.usSysFileNum;
258 p->sReturnCode = 0;
259 return;
260 }
261#endif
262 delete pstream;
263 }
264 }
265
266//Rudi: !! Workaround for WARP3 problem (sMode not set correctly) !!
267 if( p->sMode == 0 ) p->sMode = ( p->lSRate == 0 ) ? MIDI : PCM;
268
269 // get the hardware type
270 // return with bad status if the harware type is invalid/unsupported
271 HardwareType = GetHardwareType(p->sMode, (USHORT)p->ulOperation, LDev);
272 if (HardwareType == AUDIOHW_INVALID_DEVICE) {
273 p->sReturnCode = INVALID_REQUEST;
274 prp->usStatus |= RPERR;
275 return;
276 }
277 // make sure we have a Hardware object that can handle this
278 // data type and operation..
279 pHWobj = GetHardwareDevice(HardwareType);
280 if (pHWobj == NULL) {
281 p->sReturnCode = INVALID_REQUEST;
282 prp->usStatus |= RPERR;
283 return;
284 }
285
286 // Initialize flags, additional bits will be set by WAVESTREAM ctor
287 p->ulFlags = VOLUME | /* Volume control is supported */
288 INPUT | /* Input select is supported */
289 OUTPUT | /* Output select is supported */
290 MONITOR; /* Record Monitor is supported */
291
292 switch (HardwareType) {
293 case AUDIOHW_WAVE_PLAY:
294 case AUDIOHW_WAVE_CAPTURE:
295 pstream = new WAVESTREAM(HardwareType,p,prp->s.ioctl.usSysFileNum);
296 if (pstream && !((PWAVESTREAM)pstream)->IsEverythingOk() ) {
297 delete pstream; pstream = NULL;
298 }
299 break;
300
301 case AUDIOHW_MPU401_PLAY:
302 case AUDIOHW_FMSYNTH_PLAY:
303 pstream = new MIDISTREAM(HardwareType, prp->s.ioctl.usSysFileNum);
304 break;
305
306 default:
307 pstream = NULL;
308 } /* endswitch */
309
310
311 if (!pstream) {
312 p->sReturnCode = INVALID_REQUEST;
313 prp->usStatus |= RPERR;
314 return;
315 }
316
317 p->sDeviceID = VSD_ID; /* Reported in VSD dll */
318 p->pvReserved = (VOID FAR *) (ULONG) prp->s.ioctl.usSysFileNum;
319 p->sReturnCode = 0;
320 dprintf(("IoctlAudioInit: file nr: %x", pstream->usSysFileNum));
321}
322
323
324/**@internal
325 * @param PREQPACKET pointer to the strategy request packet
326 * @return None But the Status in the request packet is updated on error
327 * @notes
328 */
329void IoctlAudioCapability(PREQPACKET prp, USHORT LDev)
330{
331 PAUDIO_CAPS p = (PAUDIO_CAPS)prp->s.ioctl.pvData;
332 PWAVESTREAM pStream;
333 USHORT usDevicetype;
334 PAUDIOHW pHWobj;
335
336 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
337 sizeof(MCI_AUDIO_CAPS), VERIFY_READWRITE) )
338 {
339 dprintf(("Invalid MCI_AUDIO_CAPS pointer %lx!!", (ULONG)p));
340 prp->usStatus |= RPERR | RPBADPARAM;
341 return;
342 }
343
344 // get the hardware device type based on the datatype and operation
345 usDevicetype = GetHardwareType((USHORT)p->ulDataType,(USHORT)p->ulOperation,LDev);
346
347 // Tell the caller we support this IOCTL
348 p->ulCapability = SUPPORT_CAP;
349
350 // get the pointer to the hardware object
351 // call DevCaps
352 // bailout if no hardware object is returned..
353 pHWobj = GetHardwareDevice(usDevicetype);
354 if (pHWobj) {
355 pHWobj->DevCaps(p);
356 if (p->ulSupport != SUPPORT_SUCCESS) {
357 prp->usStatus |= RPERR;
358 }
359
360// Rudi: raise cost of a wave record stream, if a 4 channel (playback) stream
361// is present. Also avoid another playback stream, if DAUDIO is active.
362 pStream = (PWAVESTREAM)EnumStreams(NULL, STREAM_WAVE_PLAY);
363 while( pStream ) {
364 if( (usDevicetype == AUDIOHW_WAVE_CAPTURE && pStream->GetNumChannels() > 2) ||
365 (usDevicetype == AUDIOHW_WAVE_PLAY && pStream->GetProperty(PROPERTY_LOOPING) != -1) ) {
366 p->ulResourceUnits = 255; break;
367 }
368
369 pStream = (PWAVESTREAM)EnumStreams(pStream, STREAM_WAVE_PLAY);
370 }
371
372
373// Rudi: raise the cost of the second MIDI stream
374 if( usDevicetype == AUDIOHW_FMSYNTH_PLAY &&
375 EnumStreams(NULL, STREAM_FMSYNTH_PLAY) ) p->ulResourceUnits = 255;
376
377 }
378 else {
379 p->ulSupport = UNSUPPORTED_DATATYPE;
380 prp->usStatus |= RPERR;
381 }
382
383 SYSTRACE(241, 21, *p);
384}
385
386/**@internal IoctlAudioControl
387 * @param PREQPACKET pointer to the strategy request packet
388 * @return None But the Status in the request packet is updated on error
389 * @notes
390 * if it's AUDIO_CHANGE, just report success, otherwise report failure
391 * this is because we don't support volume, balance, multiple in/out devices,
392 * etc. Also, START, STOP, RESUME, and PAUSE are redundant, so we don't
393 * support those either.
394 */
395void IoctlAudioControl(PREQPACKET prp)
396{
397 LPMCI_AUDIO_CHANGE pAudChange;
398 LPMCI_TRACK_INFO pMasterVol;
399 PSTREAM pStream;
400 USHORT left, right;
401 ULONG volume, balance;
402 LPMCI_AUDIO_CONTROL p = (LPMCI_AUDIO_CONTROL) prp->s.ioctl.pvData;
403
404 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
405 sizeof(MCI_AUDIO_CONTROL), VERIFY_READWRITE) )
406 {
407 dprintf(("Invalid MCI_AUDIO_CAPS pointer %lx!!", (ULONG)p));
408 prp->usStatus |= RPERR | RPBADPARAM;
409 return;
410 }
411
412 p->sReturnCode = INVALID_REQUEST;
413
414 if( p->usIOCtlRequest != AUDIO_CHANGE ) {
415 prp->usStatus |= RPERR | RPBADCMD;
416 return;
417 }
418
419 pAudChange = (LPMCI_AUDIO_CHANGE)p->pbRequestInfo;
420 if( pAudChange && !VerifyAccess(pAudChange, sizeof(MCI_AUDIO_CHANGE),
421 sizeof(MCI_AUDIO_CHANGE), VERIFY_READONLY) )
422 {
423 dprintf(("Invalid MCI_AUDIO_CHANGE pointer %lx!!", (ULONG)pAudChange));
424 prp->usStatus |= RPERR | RPBADPARAM;
425 return;
426 }
427
428 pMasterVol = ( pAudChange ) ?
429 (LPMCI_TRACK_INFO)pAudChange->pvDevInfo : (LPMCI_TRACK_INFO)NULL;
430
431 if( pMasterVol && !VerifyAccess(pMasterVol, sizeof(MCI_TRACK_INFO),
432 sizeof(MCI_TRACK_INFO), VERIFY_READONLY) )
433 {
434 dprintf(("Invalid MCI_TRACK_INFO pointer %lx!!", (ULONG)pMasterVol));
435 prp->usStatus |= RPERR | RPBADPARAM;
436 return;
437 }
438
439
440 p->sReturnCode = 0;
441
442 if( pMasterVol ) {
443 volume = balance = (ULONG)-1;
444
445 if( pMasterVol->usMasterVolume != AUDIO_IGNORE ) {
446 // master volume ranges from 0 to 0x7FFF (linear)
447 volume = QueryPercentage(pMasterVol->usMasterVolume, 0x7fff);
448 dprintf(("Set master volume to %d", volume));
449 volume = MAKE_VOLUME_LR(volume, volume);
450 }
451
452 if( pMasterVol->usMasterBalance < 0x8000 ) {
453 // master balance ranges from 0 (left) to 0x7FFF (right)
454 // Rudi: 0xFFE8 when mono
455 left = right = 0x3fff;
456 if( pMasterVol->usMasterBalance < 0x4000 )
457 left = pMasterVol->usMasterBalance;
458 else
459 right = 0x7fff - pMasterVol->usMasterBalance;
460
461 balance = MAKE_VOLUME_LR(QueryPercentage(left, 0x3fff),
462 QueryPercentage(right, 0x3fff));
463 dprintf(("Set master balance to %d, %d",
464 GET_VOLUME_L(balance), GET_VOLUME_R(balance)));
465 }
466
467 if( (volume & balance) != (ULONG)-1 )
468 STREAM::SetMasterControl(volume, balance);
469 }
470
471
472 if( (pStream = FindStream_fromFile(prp->s.ioctl.usSysFileNum)) != NULL) {
473
474 if(!fStreamVolIOCTL90 && pAudChange->lVolume != AUDIO_IGNORE) {
475 // stream volume ranges from 0 to 0x7FFFFFFF (linear)
476 volume = QueryPercentage(pAudChange->lVolume >> 16, 0x7fff);
477 dprintf(("Set stream volume of %x to %d", prp->s.ioctl.usSysFileNum, volume));
478 pStream->SetProperty(PROPERTY_VOLUME, MAKE_VOLUME_LR(volume, volume));
479 }
480/*
481 if(!fStreamVolIOCTL90 && pAudChange->lBalance != AUDIO_IGNORE) {
482 // stream balance ranges from 0 (left) to 0x7FFFFFFF (right)
483 // Rudi: 0x3FFFFFE8 when mono, very strange !
484 balance = QueryPercentage(pAudChange->lBalance >> 16, 0x7fff);
485 pStream->SetProperty(PROPERTY_BALANCE, MAKE_VOLUME_LR((balance, balance));
486 }
487
488 if(pAudChange->lMonitor != AUDIO_IGNORE) {
489 // from AUDIO.H
490 #define MONITOR_OFF 0
491 #define MONITOR_UNCOMPRESSED 1
492 #define MONITOR_COMPRESSED 2
493 }
494*/
495 if(!fRecSrcIOCTL90) {
496 for(int i=0;i<8;i++)
497 {
498 switch(pAudChange->rInputList[0].ulDevType) {
499// case NULL_INPUT:
500// break;
501
502 case STEREO_LINE_INPUT:
503 case LEFT_LINE_INPUT:
504 case RIGHT_LINE_INPUT:
505 pStream->SetProperty(PROPERTY_INPUTSRC, MIX_RECSRC_LINE);
506 break;
507
508 case MIC_INPUT:
509 case BOOSTED_MIC_INPUT:
510 pStream->SetProperty(PROPERTY_INPUTSRC, MIX_RECSRC_MIC);
511 break;
512
513 case PHONE_LINE_INPUT:
514 case HANDSET_INPUT:
515 case SYNTH_INPUT:
516 case DIGITAL_PHONE_LINE_INPUT:
517 case DIGITAL_HANDSET_INPUT:
518 case MIDI_IN_PORT:
519// case LOOPBACK:
520 pStream->SetProperty(PROPERTY_INPUTSRC, MIX_RECSRC_MIXER);
521 break;
522 }
523 }
524 }
525
526 if(!fRecGainIOCTL90 && pAudChange->lGain != AUDIO_IGNORE) {
527 // input ranges from 0 to 0x7FFFFFFF (linear)
528 volume = QueryPercentage(pAudChange->lGain >> 16, 0x7fff);
529 dprintf(("Set input gain of %x to %d", prp->s.ioctl.usSysFileNum, volume));
530 pStream->SetProperty(PROPERTY_INPUTGAIN, MAKE_VOLUME_LR(volume, volume));
531 }
532
533 } else {
534 dprintf(("IoctlAudioControl stream %lx not found!",
535 (ULONG) prp->s.ioctl.usSysFileNum));
536 }
537
538
539 if( STREAM::QueryMixerChange() )
540 MixerChangeNotify(prp->s.ioctl.usSysFileNum);
541}
542
543//******************************************************************************
544//******************************************************************************
545void IoctlDirectAudio(PREQPACKET prp)
546{
547 if(prp->s.ioctl.bCode == DAUDIO_OPEN)
548 {
549 LPMCI_AUDIO_INIT pInit = (LPMCI_AUDIO_INIT) prp->s.ioctl.pvData;
550 PAUDIOHW pHWobj;
551 MCI_AUDIO_CAPS audioCaps;
552 PDWAVESTREAM pStream;
553
554 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
555 sizeof(MCI_AUDIO_INIT), VERIFY_READWRITE) )
556 {
557 dprintf(("Invalid MCI_AUDIO_INIT pointer %lx!!", (ULONG)pInit));
558 prp->usStatus |= RPERR | RPBADPARAM;
559 return;
560 }
561
562 audioCaps.ulLength = sizeof(MCI_AUDIO_CAPS);
563 audioCaps.ulSamplingRate = pInit->lSRate;
564 audioCaps.ulChannels = pInit->sChannels;
565 audioCaps.ulBitsPerSample = pInit->lBitsPerSRate;
566 audioCaps.ulDataType = pInit->sMode;
567 audioCaps.ulOperation = OPERATION_PLAY;
568
569 // get the pointer to the hardware object
570 // call DevCaps
571 // bailout if no hardware object is returned
572
573 // Rudi: also return, if hardware busy
574 pHWobj = GetHardwareDevice(AUDIOHW_WAVE_PLAY);
575 if (pHWobj || EnumStreams(NULL, STREAM_WAVE_PLAY) )
576 {
577 pHWobj->DevCaps(&audioCaps);
578 if (audioCaps.ulSupport != SUPPORT_SUCCESS) {
579 dprintf(("IoctlDirectAudio: DevCaps failed"));
580 pInit->sReturnCode = INVALID_REQUEST;
581 prp->usStatus |= RPERR;
582 return;
583 }
584 }
585 else {
586 pInit->sReturnCode = INVALID_REQUEST;
587 prp->usStatus |= RPERR;
588 return;
589 }
590
591 pStream = new DWAVESTREAM(AUDIOHW_WAVE_PLAY, pInit, prp->s.ioctl.usSysFileNum);
592 if(pStream == NULL) {
593 DebugInt3();
594 pInit->sReturnCode = INVALID_REQUEST;
595 prp->usStatus |= RPERR;
596 return;
597 }
598
599 if(!pStream->IsEverythingOk()) {
600 delete pStream;
601 DebugInt3();
602 pInit->sReturnCode = INVALID_REQUEST;
603 prp->usStatus |= RPERR;
604 return;
605 }
606 pInit->ulFlags |= VOLUME; /* volume control is supported */
607 pInit->ulFlags |= INPUT; /* Input select is supported */
608 pInit->ulFlags |= OUTPUT; /* Output select is supported */
609 pInit->ulFlags |= MONITOR; /* Record Monitor is supported */
610 pInit->sDeviceID = VSD_ID; /* Reported in VSD dll */
611 pStream->usSysFileNum = prp->s.ioctl.usSysFileNum;
612 pInit->pvReserved = (VOID FAR *) (ULONG) prp->s.ioctl.usSysFileNum;
613 pInit->sReturnCode = 0;
614
615 return;
616 }
617 else
618 if(prp->s.ioctl.bCode == DAUDIO_QUERYFORMAT)
619 {
620 LPMCI_AUDIO_INIT pInit = (LPMCI_AUDIO_INIT) prp->s.ioctl.pvData;
621 PAUDIOHW pHWobj;
622 MCI_AUDIO_CAPS audioCaps;
623
624 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
625 sizeof(MCI_AUDIO_INIT), VERIFY_READWRITE) )
626 {
627 dprintf(("Invalid MCI_AUDIO_INIT pointer %lx!!", (ULONG)pInit));
628 prp->usStatus |= RPERR | RPBADPARAM;
629 return;
630 }
631
632 audioCaps.ulLength = sizeof(MCI_AUDIO_CAPS);
633 audioCaps.ulSamplingRate = pInit->lSRate;
634 audioCaps.ulChannels = pInit->sChannels;
635 audioCaps.ulBitsPerSample = pInit->lBitsPerSRate;
636 audioCaps.ulDataType = pInit->sMode;
637 audioCaps.ulOperation = OPERATION_PLAY;
638
639 // get the pointer to the hardware object
640 // call DevCaps
641 // bailout if no hardware object is returned..
642 pHWobj = GetHardwareDevice(AUDIOHW_WAVE_PLAY);
643 if (pHWobj)
644 {
645 pHWobj->DevCaps(&audioCaps);
646 if (audioCaps.ulSupport != SUPPORT_SUCCESS) {
647 dprintf(("IoctlDirectAudio: DevCaps failed"));
648 prp->usStatus |= RPERR;
649 pInit->sReturnCode = INVALID_REQUEST;
650 return;
651 }
652 pInit->sReturnCode = 0;
653 return;
654 }
655 else {
656 pInit->sReturnCode = INVALID_REQUEST;
657 prp->usStatus |= RPERR;
658 return;
659 }
660 }
661 else
662 if(prp->s.ioctl.bCode == DAUDIO_QUERYCAPS)
663 {
664 LPDAUDIO_CAPS lpCaps = (LPDAUDIO_CAPS) prp->s.ioctl.pvData;
665 PWAVEAUDIO pHWobj;
666
667 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
668 sizeof(DAUDIO_CAPS), VERIFY_READWRITE) ||
669 lpCaps->dwSize != sizeof(DAUDIO_CAPS) )
670 {
671 dprintf(("Invalid DAUDIO_CAPS pointer %lx!!", (ULONG)lpCaps));
672 prp->usStatus |= RPERR | RPBADPARAM;
673 return;
674 }
675
676 // get the pointer to the hardware object
677 // call DevCaps
678 // bailout if no hardware object is returned..
679 pHWobj = (PWAVEAUDIO)GetHardwareDevice(AUDIOHW_WAVE_PLAY);
680 if (pHWobj)
681 {
682 pHWobj->DevCaps(lpCaps);
683 lpCaps->dwFreeHwMixingAllBuffers =
684 lpCaps->dwFreeHwMixingStaticBuffers =
685 lpCaps->dwFreeHwMixingStreamingBuffers = DWAVESTREAM::GetFreeStreams();
686 return;
687 }
688 else {
689 prp->usStatus |= RPERR;
690 return;
691 }
692 }
693 PSTREAM pStream;
694
695 pStream = FindStream_fromFile(prp->s.ioctl.usSysFileNum);
696 if(pStream == NULL) {
697 dprintf(("IoctlDirectAudio stream %x not found!", prp->s.ioctl.usSysFileNum));
698 DebugInt3();
699 prp->usStatus |= RPERR | RPBADCMD;
700 return;
701 }
702
703 LPDAUDIO_CMD pDAudioCmd = (LPDAUDIO_CMD) prp->s.ioctl.pvData;
704 ULONG rc = 0;
705
706
707 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
708 sizeof(DAUDIO_CMD), VERIFY_READWRITE) )
709 {
710 dprintf(("Invalid DAUDIO_CMD pointer %lx!!", (ULONG)pDAudioCmd));
711 prp->usStatus |= RPERR | RPBADPARAM;
712 return;
713 }
714
715 switch(prp->s.ioctl.bCode)
716 {
717 case DAUDIO_CLOSE:
718 delete pStream;
719 break;
720
721 case DAUDIO_SETVOLUME:
722 {
723 pStream->SetProperty(PROPERTY_VOLUME,
724 MAKE_VOLUME_LR(pDAudioCmd->Vol.VolumeL, pDAudioCmd->Vol.VolumeR));
725
726 if( STREAM::QueryMixerChange() ) MixerChangeNotify(prp->s.ioctl.usSysFileNum);
727 break;
728 }
729
730 case DAUDIO_GETVOLUME:
731 {
732 ULONG ulTemp = pStream->GetProperty(PROPERTY_VOLUME);
733 pDAudioCmd->Vol.VolumeL = GET_VOLUME_L(ulTemp);
734 pDAudioCmd->Vol.VolumeR = GET_VOLUME_R(ulTemp);
735 break;
736 }
737
738 case DAUDIO_START:
739 rc = pStream->StartStream();
740 break;
741
742 case DAUDIO_STOP:
743 {
744 CONTROL_PARM cParm;
745 rc = pStream->StopStream(&cParm);
746 break;
747 }
748
749 case DAUDIO_PAUSE:
750 {
751 CONTROL_PARM cParm;
752 rc = pStream->PauseStream(&cParm);
753 break;
754 }
755
756 case DAUDIO_RESUME:
757 rc = pStream->ResumeStream();
758 break;
759
760 case DAUDIO_GETPOS:
761 pDAudioCmd->Pos.ulCurrentPos = pStream->GetCurrentPos();
762 pDAudioCmd->Pos.ulWritePos = pStream->GetCurrentWritePos();
763 break;
764
765 case DAUDIO_ADDBUFFER:
766 {
767 rc = pStream->Write((PSTREAMBUF)pDAudioCmd->Buffer.lpBuffer,
768 pDAudioCmd->Buffer.ulBufferLength);
769 break;
770 }
771
772 case DAUDIO_SETPROPERTY:
773 {
774 rc = pStream->SetProperty((int)pDAudioCmd->SetProperty.type,
775 pDAudioCmd->SetProperty.value);
776 break;
777 }
778
779 case DAUDIO_REGISTER_THREAD:
780 {
781 DDCMDREGISTER reg;
782
783 reg.ulFunction = DDCMD_REG_STREAM;
784 reg.hStream = pDAudioCmd->Thread.hSemaphore;
785 reg.ulSysFileNum = prp->s.ioctl.usSysFileNum;
786 reg.pSHDEntryPoint = NULL;
787 rc = pStream->Register(&reg);
788 break;
789 }
790
791 case DAUDIO_DEREGISTER_THREAD:
792 {
793 pStream->DeRegister();
794 break;
795 }
796
797 case DAUDIO_QUERYVERSION:
798 pDAudioCmd->Version.ulVersion = DAUDIO_VERSION;
799 break;
800 }
801
802 if(rc) {
803 prp->usStatus |= RPERR | RPBADCMD;
804 return;
805 }
806 return;
807}
808
809//******************************************************************************
810//******************************************************************************
811void IoctlMixer(PREQPACKET prp)
812{
813 MIXSTRUCT FAR *pMixStruct = (MIXSTRUCT FAR *)prp->s.ioctl.pvData;
814 ULONG FAR *pIoctlData = (ULONG FAR *)prp->s.ioctl.pvData;
815 USHORT VolumeL, VolumeR, usCallerID, usIdx;
816 BOOL fResult, fMixerChanged = FALSE;
817 CALLBACKREC *pCallbackRec;
818 ULONG ulEvent;
819
820 if((prp->s.ioctl.bCode & 0xF0) == 0x40)
821 {
822 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
823 sizeof(MIXSTRUCT), VERIFY_READONLY) )
824 {
825 dprintf(("Invalid IOCTL90 pointer %lx!!", (ULONG)pMixStruct));
826 prp->usStatus |= RPERR | RPBADPARAM;
827 return;
828 }
829
830 usIdx = prp->s.ioctl.bCode & 0xF;
831
832 if( MixerSettings[usIdx].VolumeL != pMixStruct->VolumeL ) {
833 MixerSettings[usIdx].VolumeL = pMixStruct->VolumeL; fMixerChanged = TRUE;
834 }
835
836 if( MixerSettings[usIdx].VolumeR != pMixStruct->VolumeR ) {
837 MixerSettings[usIdx].VolumeR = pMixStruct->VolumeR; fMixerChanged = TRUE;
838 }
839
840 if( MixerSettings[usIdx].Mute != pMixStruct->Mute ) {
841 MixerSettings[usIdx].Mute = pMixStruct->Mute; fMixerChanged = TRUE;
842 }
843
844 VolumeL = (USHORT)pMixStruct->VolumeL;
845 VolumeR = (USHORT)pMixStruct->VolumeR;
846 if( pMixStruct->Mute == 1 &&
847 prp->s.ioctl.bCode != BASSTREBLESET ) VolumeL = VolumeR = 0;
848 }
849 else if((prp->s.ioctl.bCode & 0xF0) == 0x60)
850 {
851 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
852 sizeof(MIXSTRUCT), VERIFY_READWRITE) )
853 {
854 dprintf(("Invalid IOCTL90 pointer %lx!!", (ULONG)pMixStruct));
855 prp->usStatus |= RPERR | RPBADPARAM;
856 return;
857 }
858 }
859
860
861 switch(prp->s.ioctl.bCode) {
862 case MICSET:
863 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETMICVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
864 break;
865 case LINESET:
866 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETLINEINVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
867 break;
868 case CDSET:
869 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETCDVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
870 break;
871 case VIDEOSET:
872 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETVIDEOVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
873 break;
874 case AUXSET:
875 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETAUXVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
876 break;
877 case MONOINSET:
878 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETSPKVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
879 break;
880
881 case BASSTREBLESET:
882 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETBASS, MAKE_VOLUME_LR(VolumeL, VolumeL));
883 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETTREBLE, MAKE_VOLUME_LR(VolumeR, VolumeR));
884 break;
885
886 case STREAMVOLSET:
887 //release stream volume override?
888 if(pMixStruct->Mute == 2) {
889 fStreamVolIOCTL90 = FALSE;
890 break;
891 }
892 fStreamVolIOCTL90 = TRUE;
893 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETWAVEVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
894 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETMIDIVOL, MAKE_VOLUME_LR(VolumeL, VolumeR));
895 break;
896
897 case RECORDSRCSET:
898 {
899 int recsrc = MIX_RECSRC_LINE;
900
901 //release recording source override?
902 if(pMixStruct->Mute == 2) {
903 fRecSrcIOCTL90 = FALSE;
904 break;
905 }
906 fRecSrcIOCTL90 = TRUE;
907
908 switch(pMixStruct->VolumeL) {
909 case I90SRC_MIC:
910 recsrc = MIX_RECSRC_MIC;
911 break;
912 case I90SRC_CD:
913 recsrc = MIX_RECSRC_CD;
914 break;
915 case I90SRC_VIDEO:
916 recsrc = MIX_RECSRC_VIDEO;
917 break;
918// case I90SRC_LINE:
919// recsrc = MIX_RECSRC_LINE;
920// break;
921 case I90SRC_AUX:
922 recsrc = MIX_RECSRC_AUX;
923 break;
924 case I90SRC_SPDIF:
925 recsrc = MIX_RECSRC_SPDIF1;
926 break;
927
928// case I90SRC_LOOPBACK:
929// case I90SRC_PHONE:
930// default:
931// break;
932 }
933 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETINPUTSRC, recsrc);
934 break;
935 }
936 case RECORDGAINSET:
937 //release recording gain override?
938 if(pMixStruct->Mute == 2) {
939 fRecGainIOCTL90 = FALSE;
940 break;
941 }
942 fRecGainIOCTL90 = TRUE;
943 OSS16_SetGlobalVol(prp->s.ioctl.usSysFileNum, MIX_SETINPUTGAIN, MAKE_VOLUME_LR(VolumeL, VolumeL));
944 break;
945
946 case BASSTREBLEQUERY:
947 MixerSettings[BASSTREBLEQUERY & 0xF].Mute = 0; // no bass or treble
948 case MICQUERY:
949 case LINEQUERY:
950 case VIDEOQUERY:
951 case AUXQUERY:
952 case CDQUERY:
953 case MONOINQUERY:
954 case STREAMVOLQUERY:
955 case RECORDSRCQUERY:
956 case RECORDGAINQUERY:
957 _fmemcpy(pMixStruct,
958 &MixerSettings[prp->s.ioctl.bCode & 0xF], sizeof(MIXSTRUCT));
959 break;
960
961 case APILEVELQUERY:
962 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
963 sizeof(ULONG), VERIFY_READWRITE) )
964 {
965 dprintf(("Invalid IOCTL90 pointer %lx!!", (ULONG)pIoctlData));
966 prp->usStatus |= RPERR | RPBADPARAM;
967 return;
968 }
969
970 *pIoctlData = 2;
971 break;
972
973 case GETAPIMAP:
974 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
975 sizeof(MixerApiMap), VERIFY_READWRITE) )
976 {
977 dprintf(("Invalid IOCTL90 pointer %lx!!", (ULONG)pIoctlData));
978 prp->usStatus |= RPERR | RPBADPARAM;
979 return;
980 }
981
982 _fmemcpy(pIoctlData, MixerApiMap, sizeof(MixerApiMap));
983 break;
984
985 case CALLBACKREG:
986 if( !VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
987 sizeof(ULONG), VERIFY_READONLY) )
988 {
989 dprintf(("Invalid IOCTL90 pointer %lx!!", (ULONG)pIoctlData));
990 prp->usStatus |= RPERR | RPBADPARAM;
991 return;
992 }
993
994 fResult = FALSE;
995 ulEvent = *pIoctlData;
996 usCallerID = prp->s.ioctl.usSysFileNum;
997 pCallbackRec = FindCallback(usCallerID);
998
999 if( ulEvent && !pCallbackRec ) {
1000 fResult = AddCallback(usCallerID, ulEvent);
1001 } else if( !ulEvent && pCallbackRec ) {
1002 fResult = RemoveCallback(pCallbackRec);
1003 }
1004
1005 if( !fResult ) {
1006 prp->usStatus |= RPERR | RPBADCMD;
1007 return;
1008 }
1009 break;
1010
1011// case PHONESET:
1012// case THREEDSET:
1013// case PHONEQUERY:
1014// case THREEDQUERY:
1015// case MSGBUF:
1016 default:
1017 prp->usStatus |= RPERR | RPBADCMD;
1018 return;
1019 }
1020
1021 if( fMixerChanged ) MixerChangeNotify(prp->s.ioctl.usSysFileNum);
1022}
1023
1024//******************************************************************************
1025//******************************************************************************
1026void MixerInit(void)
1027{
1028 REQPACKET rp;
1029 MIXSTRUCT mixinfo;
1030
1031 static struct {
1032 UCHAR uchCode;
1033 UCHAR uchMute;
1034 USHORT usValue;
1035 } arInitVals[] = {
1036 { MICSET, 0, 40 }, // mic
1037 { LINESET, 0, 80 }, // line
1038 { CDSET, 0, 80 }, // cd
1039 { AUXSET, 0, 80 }, // aux
1040 { MONOINSET, 1, 0 }, // pcspeaker
1041 { STREAMVOLSET, 0, 80 }, // stream volume
1042 { STREAMVOLSET, 2, 80 }, // stream volume release
1043// { BASSTREBLESET, 3, 50 }, // bass / treble
1044 { RECORDSRCSET, 0, I90SRC_LINE }, // record source
1045 { RECORDSRCSET, 2, I90SRC_LINE }, // record source release
1046// { RECORDGAINSET, 0, 75 }, // record gain
1047// { RECORDGAINSET, 2, 75 }, // record gain release
1048 { SPDIFSET, 0, 0 },
1049 { 0, 0, 0 }
1050 };
1051
1052 arInitVals[0].uchMute = (UCHAR)fMicMute;
1053 arInitVals[1].uchMute = (UCHAR)fLineMute;
1054 arInitVals[2].uchMute = (UCHAR)fCDMute;
1055 arInitVals[3].uchMute = (UCHAR)fAuxMute;
1056
1057 MixerApiMap[APILEVELQUERY] =
1058 MixerApiMap[GETAPIMAP] =
1059 MixerApiMap[CALLBACKREG] = 1;
1060
1061 _fmemset(&rp, 0, sizeof(rp));
1062 rp.s.ioctl.pvData = &mixinfo;
1063 rp.s.ioctl.usDLength = sizeof(mixinfo);
1064
1065 for( int i = 0; arInitVals[i].uchCode; i++ )
1066 {
1067 MixerApiMap[arInitVals[i].uchCode] = // SET supported
1068 MixerApiMap[arInitVals[i].uchCode ^ 0x20] = 1; // QUERY supported
1069
1070 rp.s.ioctl.bCode = arInitVals[i].uchCode;
1071 mixinfo.Mute = arInitVals[i].uchMute;
1072 mixinfo.VolumeR = mixinfo.VolumeL = arInitVals[i].usValue;
1073 IoctlMixer(&rp);
1074 }
1075}
1076
1077//******************************************************************************
1078//******************************************************************************
1079void IoctlDevEscape(PREQPACKET prp)
1080{
1081 USHORT i;
1082 #define MAX_INFO 5
1083 ULONG FAR *pIoctlParm, FAR *pIoctlData = (ULONG FAR *)prp->s.ioctl.pvData;
1084
1085 switch( prp->s.ioctl.bCode )
1086 {
1087 case 0x80 :
1088 if( VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
1089 MAX_INFO * sizeof(ULONG), VERIFY_READWRITE) )
1090 {
1091 for( i = 0; i < MAX_INFO; i++ ) pIoctlData[i] = OSS16_DevEscape(0, i, 0, 0);
1092 }
1093 else
1094 {
1095 prp->usStatus |= RPERR | RPBADPARAM;
1096 }
1097 return;
1098
1099 case 0x81 :
1100 if( VerifyAccess(prp->s.ioctl.pvParm, prp->s.ioctl.usPLength,
1101 2 * sizeof(ULONG), VERIFY_READONLY) &&
1102 VerifyAccess(prp->s.ioctl.pvData, prp->s.ioctl.usDLength,
1103 1 * sizeof(ULONG), VERIFY_READWRITE) )
1104 {
1105 pIoctlParm = (ULONG FAR *)prp->s.ioctl.pvParm;
1106 *pIoctlData = OSS16_DevEscape(0, 255, pIoctlParm[0], pIoctlParm[1]);
1107 }
1108 else
1109 {
1110 prp->usStatus |= RPERR | RPBADPARAM;
1111 }
1112 return;
1113 }
1114
1115 prp->usStatus |= RPERR | RPBADCMD;
1116}
1117
1118
1119//******************************************************************************
1120//******************************************************************************
1121/**@internal
1122 * @param PREQPACKET pointer to the strategy request packet
1123 * @return None But the Status in the request packet is updated on error
1124 * @notes
1125 * StrategyIoctl is called from the strategy entry point to process IOCTL
1126 * requests. only catagory 80x requests will be processed.
1127 */
1128/* void StrategyIoctl(PREQPACKET prp, USHORT LDev)
1129*
1130*
1131*
1132*/
1133void StrategyIoctl(PREQPACKET prp, USHORT LDev)
1134{
1135 USHORT usTemp = prp->s.ioctl.bCategory << 8;
1136
1137 if( usTemp == (AUDIO_IOCTL_CAT << 8) ) usTemp |= prp->s.ioctl.bCode;
1138
1139 switch( usTemp )
1140 {
1141 case MAKEUSHORT(AUDIO_INIT, AUDIO_IOCTL_CAT) :
1142 IoctlAudioInit(prp, LDev);
1143 return;
1144
1145 case MAKEUSHORT(AUDIO_CONTROL, AUDIO_IOCTL_CAT) :
1146 IoctlAudioControl(prp);
1147 return;
1148
1149 case MAKEUSHORT(AUDIO_CAPABILITY, AUDIO_IOCTL_CAT) :
1150 IoctlAudioCapability(prp, LDev);
1151 return;
1152
1153 // chip revision details and custom commands
1154 case MAKEUSHORT(0, 0x81) :
1155 IoctlDevEscape(prp);
1156 return;
1157
1158 // IOCTL90 mixer API
1159 case MAKEUSHORT(0, 0x90) :
1160 IoctlMixer(prp);
1161 return;
1162
1163 // IOCTL91 direct audio API
1164 case MAKEUSHORT(0, DAUDIO_IOCTL_CAT) :
1165 IoctlDirectAudio(prp);
1166 return;
1167 }
1168
1169 prp->usStatus |= RPERR | RPBADCMD;
1170}
1171
1172
Note: See TracBrowser for help on using the repository browser.