Annotation of ntddk/src/mmedia/synth/driver/mididisp.c, revision 1.1.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.