Annotation of ntddk/src/mmedia/mmdrv/drvutil.c, revision 1.1.1.1

1.1       root        1: /****************************************************************************
                      2:  *
                      3:  *   drvutil.c
                      4:  *
                      5:  *   Multimedia kernel driver support component (mmdrv)
                      6:  *
                      7:  *   Copyright (c) Microsoft Corporation 1992. All rights reserved.
                      8:  *
                      9:  *   Support functions common to multiple multi-media drivers :
                     10:  *
                     11:  *   -- Open a device
                     12:  *   -- Translate a kernel IO return code to a multi-media return code
                     13:  *   -- Count the number of devices of a given type
                     14:  *   -- Set and Get data synchronously to a kernel device
                     15:  *
                     16:  *   History
                     17:  *      01-Feb-1992 - Robin Speed (RobinSp) wrote it
                     18:  *      04-Feb-1992 - Reviewed by SteveDav
                     19:  *
                     20:  ***************************************************************************/
                     21: 
                     22: #include "mmdrv.h"
                     23: #include <ntddwave.h>
                     24: #include <ntddmidi.h>
                     25: #include <ntddaux.h>
                     26: 
                     27: /****************************************************************************
                     28:  * @doc INTERNAL
                     29:  *
                     30:  * @api MMRESULT | sndOpenDev | Open the kernel driver device corresponding
                     31:  *       to a logical wave device id
                     32:  *
                     33:  * @parm UINT | DeviceType | The type of device
                     34:  *
                     35:  * @parm DWORD | dwId | The device id
                     36:  *
                     37:  * @parm PHANDLE | phDev | Where to return the kernel device handle
                     38:  *
                     39:  * @parm ACCESS_MASK | Access | The desired access
                     40:  *
                     41:  * @comm For our sound devices the only relevant access are read and
                     42:  *    read/write.  Device should ALWAYS allow opens for read unless some
                     43:  *    resource or access-rights restriction occurs.
                     44:  ***************************************************************************/
                     45: MMRESULT sndOpenDev(UINT DeviceType, DWORD dwId,
                     46:                     PHANDLE phDev, DWORD Access)
                     47: {
                     48:     WCHAR cDev[SOUND_MAX_DEVICE_NAME];
                     49: 
                     50:     WinAssert(DeviceType == WaveOutDevice ||
                     51:               DeviceType == WaveInDevice  ||
                     52:               DeviceType == MidiOutDevice ||
                     53:               DeviceType == MidiInDevice  ||
                     54:               DeviceType == AuxDevice);
                     55: 
                     56:     //
                     57:     // Check it's not out of range
                     58:     //
                     59: 
                     60:     if (dwId > SOUND_MAX_DEVICES) {
                     61:         return MMSYSERR_BADDEVICEID;
                     62:     }
                     63:     //
                     64:     // Create the device name and open it - remove '\Device'
                     65:     //
                     66: 
                     67:     wsprintf(cDev, L"\\\\.%ls%d",
                     68:              (DeviceType == WaveOutDevice ? DD_WAVE_OUT_DEVICE_NAME_U :
                     69:               DeviceType == WaveInDevice  ? DD_WAVE_IN_DEVICE_NAME_U  :
                     70:               DeviceType == MidiOutDevice ? DD_MIDI_OUT_DEVICE_NAME_U :
                     71:               DeviceType == MidiInDevice  ? DD_MIDI_IN_DEVICE_NAME_U  :
                     72:                                             DD_AUX_DEVICE_NAME_U) +
                     73:               strlen("\\Device"),
                     74:              dwId);
                     75: 
                     76:     *phDev = INVALID_HANDLE_VALUE;
                     77: 
                     78:     *phDev = CreateFile(cDev,
                     79:                         Access,
                     80:                         FILE_SHARE_WRITE,
                     81:                         NULL,
                     82:                         OPEN_EXISTING,
                     83:                         Access != GENERIC_READ ? FILE_FLAG_OVERLAPPED : 0,
                     84:                         NULL);
                     85: 
                     86:     //
                     87:     // Check up on the driver for refusing to open
                     88:     // multiply for read
                     89:     //
                     90: 
                     91:     WinAssert(!(GetLastError() == ERROR_ACCESS_DENIED &&
                     92:                 Access == GENERIC_READ));
                     93: 
                     94:     //
                     95:     // Return status to caller
                     96:     //
                     97: 
                     98:     return *phDev != INVALID_HANDLE_VALUE ? MMSYSERR_NOERROR : sndTranslateStatus();
                     99: }
                    100: 
                    101: /****************************************************************************
                    102:  * @doc INTERNAL
                    103:  *
                    104:  * @api void | sndTranslateStatus | This function translates an NT status
                    105:  *     code into a multi-media error code as far as possible.
                    106:  *
                    107:  * @parm NTSTATUS | Status | The NT base operating system return status.
                    108:  *
                    109:  *
                    110:  * @rdesc The multi-media error code.
                    111:  ***************************************************************************/
                    112: DWORD sndTranslateStatus(void)
                    113: {
                    114: #if DBG
                    115:     UINT n;
                    116:     switch (n=GetLastError()) {
                    117: #else
                    118:     switch (GetLastError()) {
                    119: #endif
                    120:     case NO_ERROR:
                    121:     case ERROR_IO_PENDING:
                    122:         return MMSYSERR_NOERROR;
                    123: 
                    124:     case ERROR_BUSY:
                    125:         return MMSYSERR_ALLOCATED;
                    126: 
                    127:     case ERROR_NOT_SUPPORTED:
                    128:     case ERROR_INVALID_FUNCTION:
                    129:         return MMSYSERR_NOTSUPPORTED;
                    130: 
                    131:     case ERROR_NOT_ENOUGH_MEMORY:
                    132:         return MMSYSERR_NOMEM;
                    133: 
                    134:     case ERROR_ACCESS_DENIED:
                    135:         return MMSYSERR_BADDEVICEID;
                    136: 
                    137:     case ERROR_INSUFFICIENT_BUFFER:
                    138:         return MMSYSERR_INVALPARAM;
                    139: 
                    140:     default:
                    141:         dprintf2(("sndTranslateStatus:  LastError = %d", n));
                    142:         return MMSYSERR_ERROR;
                    143:     }
                    144: }
                    145: 
                    146: /****************************************************************************
                    147:  * @doc INTERNAL
                    148:  *
                    149:  * @api DWORD | sndGetNumDevs | This function returns the number of (kernel)
                    150:  *
                    151:  * @parm UINT | DeviceType | The Device type
                    152:  *
                    153:  * @rdesc The number of devices.
                    154:  ***************************************************************************/
                    155: 
                    156: DWORD sndGetNumDevs(UINT DeviceType)
                    157: {
                    158:     //
                    159:     // Look for devices until we don't find one
                    160:     //
                    161:     int i;
                    162:     HANDLE h;
                    163: 
                    164:     for (i=0;
                    165:          sndOpenDev(DeviceType, i, &h, GENERIC_READ) == MMSYSERR_NOERROR;
                    166:          i++) {
                    167: 
                    168:         //
                    169:         // BUGBUG try something to make sure !
                    170:         //
                    171: 
                    172:         CloseHandle(h);
                    173:     }
                    174:     //
                    175:     // We incremented i each time we found a good device
                    176:     //
                    177: 
                    178:     return i;
                    179: }
                    180: 
                    181: /****************************************************************************
                    182:  * @doc INTERNAL
                    183:  *
                    184:  * @api DWORD | sndSetData | This function sets the volume given a device id
                    185:  *                           and could be used for other soft value setting
                    186:  *                           when only read access is required to the device
                    187:  *
                    188:  * @parm UINT | DeviceType | The Device type
                    189:  *
                    190:  * @parm UINT | DeviceId | The device id
                    191:  *
                    192:  * @parm UINT | Length | Length of data to set
                    193:  *
                    194:  * @parm PBYTE | Data | Data to set
                    195:  *
                    196:  * @parm ULONG | Ioctl | The Ioctl to use
                    197:  *
                    198:  * @rdesc MM... return code.
                    199:  ***************************************************************************/
                    200: 
                    201:  MMRESULT sndSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
                    202:                      ULONG Ioctl)
                    203:  {
                    204: 
                    205:     HANDLE hDev;
                    206:     MMRESULT mRet;
                    207:     DWORD BytesReturned;
                    208: 
                    209:     //
                    210:     // Open the wave output device
                    211:     //
                    212: 
                    213:     mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ);
                    214:     if (mRet != MMSYSERR_NOERROR) {
                    215:          return mRet;
                    216:     }
                    217: 
                    218:     //
                    219:     // Set our data.
                    220:     //
                    221:     // Setting the overlapped parameter (last) to null means we
                    222:     // wait until the operation completes.
                    223:     //
                    224: 
                    225:     mRet = DeviceIoControl(hDev, Ioctl, Data, Length, NULL, 0,
                    226:                            &BytesReturned, NULL) ?
                    227:            MMSYSERR_NOERROR : sndTranslateStatus();
                    228: 
                    229: 
                    230:     //
                    231:     // Close our file and return
                    232:     //
                    233: 
                    234:     CloseHandle(hDev);
                    235: 
                    236:     return mRet;
                    237:  }
                    238: 
                    239: /****************************************************************************
                    240:  * @doc INTERNAL
                    241:  *
                    242:  * @api DWORD | sndGetData | This function gets data from a given device
                    243:  *                           specified by device id when read-only access is
                    244:  *                           sufficient
                    245:  *
                    246:  * @parm UINT | DeviceType | The Device type
                    247:  *
                    248:  * @parm UINT | DeviceId | The device id
                    249:  *
                    250:  * @parm UINT | Length | Length of data to set
                    251:  *
                    252:  * @parm PBYTE | Data | Data to set
                    253:  *
                    254:  * @parm ULONG | Ioctl | The Ioctl to use
                    255:  *
                    256:  * @rdesc MM... return code.
                    257:  ***************************************************************************/
                    258: 
                    259:  MMRESULT sndGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
                    260:                      ULONG Ioctl)
                    261:  {
                    262: 
                    263:     HANDLE hDev;
                    264:     MMRESULT mRet;
                    265:     DWORD BytesReturned;
                    266: 
                    267:     //
                    268:     // Open the wave output device
                    269:     //
                    270: 
                    271:     mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ);
                    272:     if (mRet != MMSYSERR_NOERROR) {
                    273:          return mRet;
                    274:     }
                    275: 
                    276:     //
                    277:     // Set our data.
                    278:     //
                    279:     // Setting the overlapped parameter (last) to null means we
                    280:     // wait until the operation completes.
                    281:     //
                    282: 
                    283:     mRet = DeviceIoControl(hDev, Ioctl, NULL, 0, (LPVOID)Data, Length,
                    284:                            &BytesReturned, NULL) ?
                    285:            MMSYSERR_NOERROR : sndTranslateStatus();
                    286: 
                    287: 
                    288:     //
                    289:     // Close our file and return
                    290:     //
                    291: 
                    292:     CloseHandle(hDev);
                    293: 
                    294:     return mRet;
                    295:  }
                    296: 
                    297: 
                    298: /****************************************************************************
                    299:  * @doc INTERNAL
                    300:  *
                    301:  * @api MMRESULT | sndGetHandleData | Get data from a device using its handle
                    302:  *
                    303:  * @parm PWAVEALLOC | pClient | Client handle.
                    304:  *
                    305:  * @parm DWORD | dwSize | Size of the data
                    306:  *
                    307:  * @parm PVOID | pData | Where to put the data.
                    308:  *
                    309:  * @parm ULONG | Function | The Ioctl to use
                    310:  *
                    311:  * @rdesc MMSYS... return value.
                    312:  ***************************************************************************/
                    313: 
                    314: MMRESULT sndGetHandleData(HANDLE     hDev,
                    315:                           DWORD      dwSize,
                    316:                           PVOID      pData,
                    317:                           ULONG      Ioctl,
                    318:                           HANDLE     hEvent)
                    319: {
                    320:     OVERLAPPED Overlap;
                    321:     DWORD BytesReturned;
                    322: 
                    323:     WinAssert(hDev != NULL);
                    324: 
                    325:     memset(&Overlap, 0, sizeof(Overlap));
                    326: 
                    327:     Overlap.hEvent = hEvent;
                    328: 
                    329:     //
                    330:     // Issue the IO control.  We must wait with our own event because
                    331:     // setting the overlapped object to null will complete if other
                    332:     // IOs complete.
                    333:     //
                    334: 
                    335:     if (!DeviceIoControl(hDev,
                    336:                          Ioctl,
                    337:                          NULL,
                    338:                          0,
                    339:                          pData,
                    340:                          dwSize,
                    341:                          &BytesReturned,
                    342:                          &Overlap)) {
                    343:          DWORD cbTransfer;
                    344: 
                    345:          //
                    346:          // Wait for completion if necessary
                    347:          //
                    348: 
                    349:          if (GetLastError() == ERROR_IO_PENDING) {
                    350:              if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer,
                    351:                                       TRUE)) {
                    352:                   return sndTranslateStatus();
                    353:              }
                    354:          } else {
                    355:              return sndTranslateStatus();
                    356:          }
                    357:     }
                    358: 
                    359:     //
                    360:     // We'd better peek aleratbly to flush out any IO
                    361:     // completions so that things like RESET only
                    362:     // return when all buffers have been completed
                    363:     //
                    364:     // This relies on the fact that SleepEx will return
                    365:     // WAIT_IO_COMPLETION in preference to OK
                    366:     //
                    367: 
                    368:     while (SetEvent(hEvent) &&
                    369:            WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_IO_COMPLETION) {}
                    370: 
                    371: 
                    372:     return MMSYSERR_NOERROR;
                    373: }
                    374: 
                    375: /****************************************************************************
                    376:  * @doc INTERNAL
                    377:  *
                    378:  * @api MMRESULT | sndSetHandleData | Pass data to a device using its handle
                    379:  *
                    380:  * @parm PWAVEALLOC | pClient | Client handle.
                    381:  *
                    382:  * @parm DWORD | dwSize | Size of the data
                    383:  *
                    384:  * @parm PVOID | pData | Data to send.
                    385:  *
                    386:  * @parm ULONG | Function | The Ioctl to use
                    387:  *
                    388:  * @rdesc MMSYS... return value.
                    389:  ***************************************************************************/
                    390: MMRESULT sndSetHandleData(HANDLE     hDev,
                    391:                           DWORD      dwSize,
                    392:                           PVOID      pData,
                    393:                           ULONG      Ioctl,
                    394:                           HANDLE     hEvent)
                    395: {
                    396:     OVERLAPPED Overlap;
                    397:     DWORD BytesReturned;
                    398: 
                    399:     WinAssert(hDev != NULL);
                    400: 
                    401:     memset((PVOID)&Overlap, 0, sizeof(Overlap));
                    402: 
                    403:     Overlap.hEvent = hEvent;
                    404: 
                    405:     //
                    406:     // Issue the IO control.  We must wait with our own event because
                    407:     // setting the overlapped object to null will complete if other
                    408:     // IOs complete.
                    409:     //
                    410: 
                    411:     if (!DeviceIoControl(hDev,
                    412:                          Ioctl,
                    413:                          pData,
                    414:                          dwSize,
                    415:                          NULL,
                    416:                          0,
                    417:                          &BytesReturned,
                    418:                          &Overlap)) {
                    419:          DWORD cbTransfer;
                    420: 
                    421:          //
                    422:          // Wait for completion if necessary
                    423:          //
                    424: 
                    425:          if (GetLastError() == ERROR_IO_PENDING) {
                    426:              if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer,
                    427:                                       TRUE)) {
                    428:                   return sndTranslateStatus();
                    429:              }
                    430:          } else {
                    431:              return sndTranslateStatus();
                    432:          }
                    433:     }
                    434: 
                    435:     //
                    436:     // We'd better peek aleratbly to flush out any IO
                    437:     // completions so that things like RESET only
                    438:     // return when all buffers have been completed
                    439:     //
                    440:     // This relies on the fact that SleepEx will return
                    441:     // WAIT_IO_COMPLETION in preference to OK
                    442:     //
                    443: 
                    444:     while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
                    445: 
                    446:     return MMSYSERR_NOERROR;
                    447: }

unix.superglobalmegacorp.com

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