Annotation of ntddk/src/mmedia/synth/driver/mididisp.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1993  Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     mididisp.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains code for the function dispatcher.
        !            12: 
        !            13: Author:
        !            14: 
        !            15:     Robin Speed (RobinSp) 30-Jan-1992
        !            16: 
        !            17: Environment:
        !            18: 
        !            19:     Kernel mode
        !            20: 
        !            21: Revision History:
        !            22: 
        !            23: 
        !            24: --*/
        !            25: 
        !            26: #include "sound.h"
        !            27: 
        !            28: BOOL SoundSynthPresent(PUCHAR base, PUCHAR inbase);
        !            29: 
        !            30: 
        !            31: #ifdef ALLOC_PRAGMA
        !            32: #pragma alloc_text(init,SoundSynthPresent)
        !            33: #pragma alloc_text(init,SoundSynthPortValid)
        !            34: #pragma alloc_text(init,SoundMidiIsOpl3)
        !            35: #endif
        !            36: 
        !            37: 
        !            38: 
        !            39: NTSTATUS
        !            40: SoundMidiData(
        !            41:     IN OUT PLOCAL_DEVICE_INFO pLDI,
        !            42:     IN     PIRP pIrp,
        !            43:     IN     PIO_STACK_LOCATION pIrpStack
        !            44: )
        !            45: /*++
        !            46: 
        !            47: Routine Description:
        !            48: 
        !            49:     The user has passed in a buffer of midi data to play
        !            50: 
        !            51:     The buffer is validated and the data passed to the device
        !            52: 
        !            53: Arguments:
        !            54: 
        !            55:     pLDI - Local wave device info
        !            56:     pIrp - The IO request packet
        !            57:     pIrpStack - The current stack location
        !            58: 
        !            59: Return Value:
        !            60: 
        !            61:     Irp status
        !            62: 
        !            63: --*/
        !            64: {
        !            65:     NTSTATUS Status;
        !            66: 
        !            67:     ULONG Length;
        !            68:     PSYNTH_DATA pData;
        !            69:     PUCHAR SynthBase;
        !            70: 
        !            71:     Length = pIrpStack->Parameters.Write.Length;
        !            72:     pData = (PSYNTH_DATA)pIrp->UserBuffer;
        !            73:     SynthBase = ((PSOUND_HARDWARE)pLDI->HwContext)->SynthBase;
        !            74: 
        !            75: 
        !            76:     if (Length % sizeof(SYNTH_DATA) != 0) {
        !            77:         return STATUS_BUFFER_TOO_SMALL;
        !            78:     }
        !            79: 
        !            80:     Status = STATUS_SUCCESS;
        !            81: 
        !            82:     try {
        !            83:         for ( ; Length != 0 ; Length -= sizeof(SYNTH_DATA), pData++) {
        !            84:             USHORT IoPort;
        !            85:             IoPort = pData->IoPort;
        !            86:             if (IoPort < SYNTH_PORT ||
        !            87:                 IoPort >= SYNTH_PORT + NUMBER_OF_SYNTH_PORTS) {
        !            88:                 Status = STATUS_INVALID_PARAMETER;
        !            89:                 break;
        !            90:             }
        !            91: 
        !            92:             WRITE_PORT_UCHAR(SynthBase + (IoPort - SYNTH_PORT),
        !            93:                              (UCHAR)pData->PortData);
        !            94: 
        !            95:             //
        !            96:             // Make sure the SYNTH can keep up
        !            97:            // newer boards need 1us  - older boards need
        !            98:            // 3.3 us after selecting the register and 23 us after
        !            99:            // writing the data - as we don't know which is which, we
        !           100:            // wait 23us after every write
        !           101:             //
        !           102:            if (pLDI->DeviceIndex == AdlibDevice) {
        !           103:                KeStallExecutionProcessor(23);
        !           104:            } else {
        !           105:                KeStallExecutionProcessor(10);
        !           106:            }
        !           107:         }
        !           108: 
        !           109:     } except (EXCEPTION_EXECUTE_HANDLER) {
        !           110:         Status = STATUS_ACCESS_VIOLATION;
        !           111:     }
        !           112: 
        !           113:     pIrp->IoStatus.Information = pIrpStack->Parameters.Write.Length - Length;
        !           114: 
        !           115:     return Status;
        !           116: }
        !           117: 
        !           118: 
        !           119: NTSTATUS
        !           120: SoundMidiReadPort(
        !           121:     IN OUT PLOCAL_DEVICE_INFO pLDI,
        !           122:     IN     PIRP pIrp,
        !           123:     IN     PIO_STACK_LOCATION pIrpStack
        !           124: )
        !           125: /*++
        !           126: 
        !           127: Routine Description:
        !           128: 
        !           129:     The user has passed in a buffer to return the status port value
        !           130: 
        !           131:     The buffer is validated and data returned if it's length 1
        !           132: 
        !           133: Arguments:
        !           134: 
        !           135:     pLDI - Local wave device info
        !           136:     pIrp - The IO request packet
        !           137:     pIrpStack - The current stack location
        !           138: 
        !           139: Return Value:
        !           140: 
        !           141:     Irp status
        !           142: 
        !           143: --*/
        !           144: {
        !           145:     NTSTATUS Status;
        !           146: 
        !           147:     ULONG Length;
        !           148:     PUCHAR SynthBase;
        !           149:     PUCHAR pData;
        !           150: 
        !           151:     Length = pIrpStack->Parameters.Read.Length;
        !           152:     pData = (PUCHAR)pIrp->UserBuffer;
        !           153:     SynthBase = ((PSOUND_HARDWARE)pLDI->HwContext)->SynthBase;
        !           154: 
        !           155: 
        !           156:     if (Length != sizeof(UCHAR)) {
        !           157:         return STATUS_INVALID_PARAMETER;
        !           158:     }
        !           159: 
        !           160:     Status = STATUS_SUCCESS;
        !           161: 
        !           162:     try {
        !           163:         *pData = READ_PORT_UCHAR(SynthBase);
        !           164:         pIrp->IoStatus.Information = sizeof(UCHAR);
        !           165:     } except (EXCEPTION_EXECUTE_HANDLER) {
        !           166:         Status = STATUS_ACCESS_VIOLATION;
        !           167:     }
        !           168: 
        !           169: 
        !           170:     return Status;
        !           171: }
        !           172: 
        !           173: 
        !           174: NTSTATUS
        !           175: SoundMidiDispatch(
        !           176:     IN OUT PLOCAL_DEVICE_INFO pLDI,
        !           177:     IN    PIRP pIrp,
        !           178:     IN    PIO_STACK_LOCATION IrpStack
        !           179: )
        !           180: /*++
        !           181: 
        !           182: Routine Description:
        !           183: 
        !           184:     Driver function dispatch routine
        !           185: 
        !           186: Arguments:
        !           187: 
        !           188:     pLDI - local device info
        !           189:     pIrp - Pointer to IO request packet
        !           190:     IrpStack - current stack location
        !           191: 
        !           192: Return Value:
        !           193: 
        !           194:     Return status from dispatched routine
        !           195: 
        !           196: --*/
        !           197: {
        !           198:     NTSTATUS Status;
        !           199: 
        !           200:     Status = STATUS_SUCCESS;
        !           201: 
        !           202:     //
        !           203:     // Initialize the irp information field.
        !           204:     //
        !           205: 
        !           206:     pIrp->IoStatus.Information = 0;
        !           207: 
        !           208:     switch (IrpStack->MajorFunction) {
        !           209:     case IRP_MJ_CREATE:
        !           210:         Status = SoundSetShareAccess(pLDI, IrpStack);
        !           211: 
        !           212:         if (IrpStack->FileObject->WriteAccess) {
        !           213:            // reset board to silence and to correct mode (opl3 or opl2)
        !           214:            SoundMidiQuiet(pLDI->DeviceIndex, pLDI->HwContext);
        !           215:        }
        !           216:         break;
        !           217: 
        !           218:     case IRP_MJ_WRITE:
        !           219:         if (IrpStack->FileObject->WriteAccess) {
        !           220:             Status = SoundMidiData(pLDI, pIrp, IrpStack);
        !           221:         } else {
        !           222:             Status = STATUS_ACCESS_DENIED;
        !           223:         }
        !           224:         break;
        !           225: 
        !           226:     case IRP_MJ_READ:
        !           227:         if (IrpStack->FileObject->WriteAccess) {
        !           228:             Status = SoundMidiReadPort(pLDI, pIrp, IrpStack);
        !           229:         } else {
        !           230:             Status = STATUS_ACCESS_DENIED;
        !           231:         }
        !           232:         break;
        !           233: 
        !           234:     case IRP_MJ_DEVICE_CONTROL:
        !           235: 
        !           236: 
        !           237:         //
        !           238:         // Check device access
        !           239:         //
        !           240:         if (!IrpStack->FileObject->WriteAccess &&
        !           241:             pLDI->PreventVolumeSetting) {
        !           242:             Status = STATUS_ACCESS_DENIED;
        !           243:         } else {
        !           244:             switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
        !           245:                 case IOCTL_MIDI_SET_VOLUME:
        !           246:                     Status = SoundIoctlSetVolume(pLDI, pIrp, IrpStack);
        !           247:                     break;
        !           248: 
        !           249:                 case IOCTL_MIDI_GET_VOLUME:
        !           250:                     Status = SoundIoctlGetVolume(pLDI, pIrp, IrpStack);
        !           251:                     break;
        !           252: 
        !           253:                 case IOCTL_SOUND_GET_CHANGED_VOLUME:
        !           254:                     Status = SoundIoctlGetChangedVolume(pLDI, pIrp, IrpStack);
        !           255:                     break;
        !           256: 
        !           257: 
        !           258:                 default:
        !           259:                     Status = STATUS_INVALID_DEVICE_REQUEST;
        !           260:                     break;
        !           261:             }
        !           262:         }
        !           263:         break;
        !           264: 
        !           265: 
        !           266:     case IRP_MJ_CLOSE:
        !           267: 
        !           268:         Status = STATUS_SUCCESS;
        !           269: 
        !           270:         break;
        !           271: 
        !           272:     case IRP_MJ_CLEANUP:
        !           273:         if (IrpStack->FileObject->WriteAccess) {
        !           274:             SoundMidiQuiet(pLDI->DeviceIndex, pLDI->HwContext);
        !           275:             (*pLDI->DeviceInit->ExclusionRoutine)(pLDI, SoundExcludeClose);
        !           276:             pLDI->PreventVolumeSetting = FALSE;
        !           277:         } else {
        !           278:             Status = STATUS_SUCCESS;
        !           279:         }
        !           280:         break;
        !           281: 
        !           282:     default:
        !           283:         dprintf1(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction));
        !           284:         Status = STATUS_INVALID_DEVICE_REQUEST;
        !           285:         break;
        !           286:     }
        !           287: 
        !           288:     //
        !           289:     // Tell the IO subsystem we're done.  If the Irp is pending we
        !           290:     // don't touch it as it could be being processed by another
        !           291:     // processor (or may even be complete already !).
        !           292:     //
        !           293: 
        !           294:     return Status;
        !           295: }
        !           296: 
        !           297: 
        !           298: 
        !           299: VOID
        !           300: SoundMidiSendFM(
        !           301:     IN    PUCHAR PortBase,
        !           302:     IN    ULONG Address,
        !           303:     IN    UCHAR Data
        !           304: )
        !           305: {
        !           306:     // these delays need to be 23us at least for old opl2 chips, even
        !           307:     // though new chips can handle 1 us delays.
        !           308: 
        !           309:     WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 0 : 2), (UCHAR)Address);
        !           310:     KeStallExecutionProcessor(23);
        !           311:     WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 1 : 3), Data);
        !           312:     KeStallExecutionProcessor(23);
        !           313: }
        !           314: 
        !           315: /*
        !           316:  * this array gives the offsets of the slots within an opl2
        !           317:  * chip. This is needed to set the attenuation for all slots to max,
        !           318:  * to ensure that the chip is silenced completely - switching off the
        !           319:  * voices alone will not do this.
        !           320:  */
        !           321: BYTE offsetSlot[] = {
        !           322:        0, 1, 2, 3, 4, 5,
        !           323:        8, 9, 10, 11, 12, 13,
        !           324:        16, 17, 18, 19, 20, 21
        !           325: };
        !           326: 
        !           327: 
        !           328: 
        !           329: VOID
        !           330: SoundMidiQuiet(
        !           331:     IN   UCHAR DeviceIndex,    
        !           332:     IN    PSOUND_HARDWARE pHw
        !           333: )
        !           334: /*++
        !           335: 
        !           336: Routine Description:
        !           337: 
        !           338:     Initialize the SYNTH hardware to silence
        !           339: 
        !           340: Arguments:
        !           341: 
        !           342:     pHw - hardware data
        !           343: 
        !           344: Return Value:
        !           345: 
        !           346:     None
        !           347: 
        !           348: --*/
        !           349: {
        !           350: 
        !           351:     ULONG   i;
        !           352: 
        !           353:     // D1 ("\nMidiQuietFM");
        !           354: 
        !           355:     /*
        !           356:      * sequence to initialise and silence the device
        !           357:      * depends on whether it is an Opl3 device or not
        !           358:      */
        !           359:     if (DeviceIndex == Opl3Device) {
        !           360: 
        !           361:        /* tell the FM chip to use 4-operator mode, and
        !           362:                fill in any other random variables */
        !           363:        SoundMidiSendFM (pHw->SynthBase, AD_NEW, 0x01);
        !           364:        SoundMidiSendFM (pHw->SynthBase, AD_MASK, 0x60);
        !           365:        SoundMidiSendFM (pHw->SynthBase, AD_CONNECTION, 0x3f);
        !           366:        SoundMidiSendFM (pHw->SynthBase, AD_NTS, 0x00);
        !           367: 
        !           368: 
        !           369:        /* turn off the drums, and use high vibrato/modulation */
        !           370:        SoundMidiSendFM (pHw->SynthBase, AD_DRUM, 0xc0);
        !           371: 
        !           372:        /* turn off all the oscillators */
        !           373:        for (i = 0; i < 0x15; i++) {
        !           374:                SoundMidiSendFM (pHw->SynthBase, AD_LEVEL + i, 0x3f);
        !           375:                SoundMidiSendFM (pHw->SynthBase, AD_LEVEL2 + i, 0x3f);
        !           376:                };
        !           377: 
        !           378:        /* turn off all the voices */
        !           379:        for (i = 0; i < 0x08; i++) {
        !           380:                SoundMidiSendFM (pHw->SynthBase, AD_BLOCK + i, 0x00);
        !           381:                SoundMidiSendFM (pHw->SynthBase, AD_BLOCK2 + i, 0x00);
        !           382:                };
        !           383:     } else {
        !           384:        /* base adlib hardware initialisation */
        !           385: 
        !           386:        // ensure that if we have a opl3 chip, we are in base mode
        !           387:        SoundMidiSendFM (pHw->SynthBase, AD_NEW, 0x00);
        !           388: 
        !           389:        // turn off all the slot oscillators
        !           390:        for (i = 0; i < 18; i++) {
        !           391:                SoundMidiSendFM(pHw->SynthBase, offsetSlot[i]+AD_LEVEL, 0x3f);
        !           392:        }
        !           393: 
        !           394:        /* silence all voices */
        !           395:        for (i = 0; i <= 8; i++) {
        !           396:            SoundMidiSendFM(pHw->SynthBase, (AD_FNUMBER | i), 0);
        !           397:            SoundMidiSendFM(pHw->SynthBase, (AD_BLOCK | i), 0);
        !           398:        }
        !           399: 
        !           400:        /* switch to percussive mode and silence percussion instruments */
        !           401:        SoundMidiSendFM(pHw->SynthBase, AD_DRUM, (BYTE)0x20);
        !           402:     }
        !           403: }
        !           404: 
        !           405: 
        !           406: BOOL
        !           407: SoundSynthPresent(PUCHAR base, PUCHAR inbase)
        !           408: /*++
        !           409: 
        !           410: Routine Description:
        !           411: 
        !           412:     Detect the presence or absence of a 3812 (adlib-compatible) synthesizer
        !           413:     at the given i/o address by starting the timer and looking for an
        !           414:     overflow. Can be used to detect left and right synthesizers separately.
        !           415: 
        !           416: Arguments:
        !           417: 
        !           418:     base - base output address
        !           419:     inbase - base input address
        !           420: 
        !           421: Return Value:
        !           422: 
        !           423:     TRUE if a synthesizer is present at that address
        !           424: 
        !           425: --*/
        !           426: {
        !           427: #define inport(port)   READ_PORT_UCHAR((PUCHAR)(port))
        !           428: 
        !           429:        UCHAR t1, t2;
        !           430: 
        !           431: 
        !           432:        // check if the chip is present
        !           433:        SoundMidiSendFM(base, 4, 0x60);             // mask T1 & T2
        !           434:        SoundMidiSendFM(base, 4, 0x80);             // reset IRQ
        !           435:        t1 = inport(inbase);                                // read status register
        !           436:        SoundMidiSendFM(base, 2, 0xff);             // set timer - 1 latch
        !           437:        SoundMidiSendFM(base, 4, 0x21);             // unmask & start T1
        !           438:                                                                                                
        !           439:        // this timer should go off in 80 us. It sometimes
        !           440:        // takes more than 100us, but will always have expired within
        !           441:        // 200 us if it is ever going to.
        !           442:        KeStallExecutionProcessor(200);
        !           443:                                                                                                        
        !           444:        t2 = inport(inbase);                        // read status register
        !           445: 
        !           446:        
        !           447:        SoundMidiSendFM(base, 4, 0x60);
        !           448:        SoundMidiSendFM(base, 4, 0x80);
        !           449: 
        !           450:                                                                                                                
        !           451:        if (!((t1 & 0xE0) == 0) || !((t2 & 0xE0) == 0xC0)) {
        !           452:            return(FALSE);
        !           453:        }
        !           454:        
        !           455:        return TRUE;
        !           456: 
        !           457: #undef inport
        !           458: 
        !           459: }
        !           460: 
        !           461: 
        !           462: 
        !           463: NTSTATUS
        !           464: SoundSynthPortValid(
        !           465:     IN OUT PGLOBAL_DEVICE_INFO pGDI
        !           466: )
        !           467: {
        !           468:     NTSTATUS Status;
        !           469:     ULONG Port;
        !           470: 
        !           471:     Port = SYNTH_PORT;
        !           472: 
        !           473:     //
        !           474:     // Check we're going to be allowed to use this port or whether
        !           475:     // some other device thinks it owns this hardware
        !           476:     //
        !           477: 
        !           478:     Status = SoundReportResourceUsage(
        !           479:                 (PDEVICE_OBJECT)pGDI->DriverObject,
        !           480:                  pGDI->BusType,
        !           481:                  pGDI->BusNumber,
        !           482:                  NULL,
        !           483:                  0,
        !           484:                  FALSE,
        !           485:                  NULL,
        !           486:                  &Port,
        !           487:                  NUMBER_OF_SYNTH_PORTS);
        !           488: 
        !           489:     if (!NT_SUCCESS(Status)) {
        !           490:         return Status;
        !           491:     }
        !           492: 
        !           493:     //
        !           494:     // Find where our device is mapped
        !           495:     //
        !           496: 
        !           497:     pGDI->Hw.SynthBase = SoundMapPortAddress(
        !           498:                                pGDI->BusType,
        !           499:                                pGDI->BusNumber,
        !           500:                                Port,
        !           501:                                NUMBER_OF_SYNTH_PORTS,
        !           502:                                &pGDI->MemType);
        !           503:     {
        !           504:        PUCHAR base;
        !           505: 
        !           506:        base = pGDI->Hw.SynthBase;
        !           507: 
        !           508:        if (!SoundSynthPresent(base, base)) {
        !           509: 
        !           510:            dprintf1(("No synthesizer present"));
        !           511:            return STATUS_DEVICE_CONFIGURATION_ERROR;
        !           512:        }
        !           513:     }
        !           514: 
        !           515:     return STATUS_SUCCESS;
        !           516: }
        !           517: 
        !           518: 
        !           519: 
        !           520: BOOL
        !           521: SoundMidiIsOpl3(
        !           522:     IN    PSOUND_HARDWARE pHw
        !           523: )
        !           524: /*++
        !           525: 
        !           526: Routine Description:
        !           527: 
        !           528:     Check if the midi synthesizer is Opl3 compatible or just adlib-compatible.
        !           529: 
        !           530: Arguments:
        !           531: 
        !           532:     pHw - hardware data
        !           533: 
        !           534: Return Value:
        !           535: 
        !           536:     TRUE if OPL3-compatible chip. FALSE otherwise.
        !           537: 
        !           538: --*/
        !           539: {
        !           540:     BOOL bReturn = FALSE;
        !           541: 
        !           542:     PUCHAR Port = pHw->SynthBase;
        !           543: 
        !           544:     /*
        !           545:      * theory: an opl3-compatible synthesizer chip looks
        !           546:      * exactly like two separate 3812 synthesizers (for left and right
        !           547:      * channels) until switched into opl3 mode. Then, the timer-control
        !           548:      * register for the right half is replaced by a channel connection register
        !           549:      * (among other changes).
        !           550:      *
        !           551:      * We can detect 3812 synthesizers by starting a timer and looking for
        !           552:      * timer overflow. So if we find 3812s at both left and right addresses,
        !           553:      * we then switch to opl3 mode and look again for the right-half. If we
        !           554:      * still find it, then the switch failed and we have an old synthesizer
        !           555:      * if the right half disappeared, we have a new opl3 synthesizer.
        !           556:      *
        !           557:      * NB we use either monaural base-level synthesis, or stereo opl3
        !           558:      * synthesis. If we discover two 3812s (as on early SB Pro and
        !           559:      * PAS), we ignore one of them.
        !           560:      */
        !           561: 
        !           562:     /*
        !           563:      * nice theory - but wrong. The timer on the right half of the
        !           564:      * opl3 chip reports its status in the left-half status register.
        !           565:      * There is no right-half status register on the opl3 chip.
        !           566:      */
        !           567: 
        !           568: 
        !           569:     /* ensure base mode */
        !           570:     SoundMidiSendFM (Port, AD_NEW, 0x00);
        !           571:     KeStallExecutionProcessor(20);
        !           572: 
        !           573:     /* look for right half of chip */
        !           574:     if (SoundSynthPresent(Port + 2, Port)) {
        !           575:        /* yes - is this two separate chips or a new opl3 chip ? */
        !           576: 
        !           577:        /* switch to opl3 mode */
        !           578:        SoundMidiSendFM (Port, AD_NEW, 0x01);
        !           579:        KeStallExecutionProcessor(20);
        !           580: 
        !           581: 
        !           582:        if (!SoundSynthPresent(Port + 2, Port)) {
        !           583: 
        !           584:            /* right-half disappeared - so opl3 */
        !           585:            bReturn = TRUE;
        !           586:        }
        !           587:     }
        !           588: 
        !           589:     /* reset to 3812 mode */
        !           590:     SoundMidiSendFM (Port, AD_NEW, 0x00);
        !           591:     KeStallExecutionProcessor(20);
        !           592: 
        !           593: 
        !           594:     return(bReturn);
        !           595: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.