Annotation of ntddk/src/scsi/cdaudio/cdaudio.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1992, 1993  Microsoft Corporation
                      4: 
                      5: Module Name:
                      6: 
                      7:     audio.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This driver filters scsi-2 cdrom audio commands for non-scsi-2
                     12:     compliant cdrom drives.  At initialization, the driver scans the
                     13:     scsi bus for a recognized non-scsi-2 cdrom drive, and if one is
                     14:     found attached, installs itself to intercept IO_DEVICE_CONTROL
                     15:     requests for this drive.
                     16: 
                     17: Author:
                     18: 
                     19:     Rick Turner
                     20: 
                     21: Environment:
                     22: 
                     23:     kernel mode only
                     24: 
                     25: Notes:
                     26: 
                     27: Revision History:
                     28: 
                     29: 
                     30: --*/
                     31: 
                     32: #include "ntddk.h"
                     33: #include "scsi.h"
                     34: #include "stdio.h"
                     35: #include "stdarg.h"
                     36: 
                     37: #include "cdaudio.h"
                     38: 
                     39: 
                     40: //
                     41: // Function declarations
                     42: //
                     43: 
                     44: NTSTATUS
                     45: DriverEntry (
                     46:     IN PDRIVER_OBJECT DriverObject,
                     47:     IN PUNICODE_STRING RegistryPath
                     48:     );
                     49: 
                     50: NTSTATUS
                     51: CdAudioInitialize(
                     52:     IN PDRIVER_OBJECT DriverObject
                     53:     );
                     54: 
                     55: NTSTATUS
                     56: CdAudioCreate(
                     57:     IN PDEVICE_OBJECT DeviceObject,
                     58:     IN PIRP Irp
                     59:     );
                     60: 
                     61: NTSTATUS
                     62: CdAudioReadWrite(
                     63:     IN PDEVICE_OBJECT DeviceObject,
                     64:     IN PIRP Irp
                     65:     );
                     66: 
                     67: NTSTATUS
                     68: CdAudioDeviceControl(
                     69:     IN PDEVICE_OBJECT DeviceObject,
                     70:     IN PIRP Irp
                     71:     );
                     72: 
                     73: NTSTATUS
                     74: CdAudioSendToNextDriver(
                     75:     IN PDEVICE_OBJECT DeviceObject,
                     76:     IN PIRP Irp
                     77:     );
                     78: 
                     79: BOOLEAN
                     80: CdAudioIsPlayActive(
                     81:     IN PDEVICE_OBJECT DeviceObject
                     82:     );
                     83: 
                     84: NTSTATUS
                     85: CdAudioNECDeviceControl(
                     86:     IN PDEVICE_OBJECT DeviceObject,
                     87:     IN PIRP Irp
                     88:     );
                     89: 
                     90: NTSTATUS
                     91: CdAudioNECInterpretSenseInfo(
                     92:     IN PDEVICE_OBJECT DeviceObject,
                     93:     IN PSCSI_REQUEST_BLOCK Srb,
                     94:     IN UCHAR MajorFunctionCode,
                     95:     IN ULONG IoDeviceCode,
                     96:     IN ULONG RetryCount,
                     97:     OUT NTSTATUS *Status
                     98:     );
                     99: 
                    100: NTSTATUS
                    101: CdAudioNECSendSrbSynchronous(
                    102:     PDEVICE_OBJECT DeviceObject,
                    103:     PSCSI_REQUEST_BLOCK Srb,
                    104:     PVOID BufferAddress,
                    105:     ULONG BufferLength,
                    106:     BOOLEAN WriteToDevice
                    107:     );
                    108: 
                    109: NTSTATUS
                    110: CdAudioPioneerDeviceControl(
                    111:     IN PDEVICE_OBJECT DeviceObject,
                    112:     IN PIRP Irp
                    113:     );
                    114: 
                    115: NTSTATUS
                    116: CdAudioDenonDeviceControl(
                    117:     IN PDEVICE_OBJECT DeviceObject,
                    118:     IN PIRP Irp
                    119:     );
                    120: 
                    121: NTSTATUS
                    122: CdAudioHitatchiSendPauseCommand(
                    123:     IN PDEVICE_OBJECT DeviceObject
                    124:     );
                    125: 
                    126: NTSTATUS
                    127: CdAudioHitatchiDeviceControl(
                    128:     IN PDEVICE_OBJECT DeviceObject,
                    129:     IN PIRP Irp
                    130:     );
                    131: 
                    132: NTSTATUS
                    133: CdAudio535DeviceControl(
                    134:     IN PDEVICE_OBJECT DeviceObject,
                    135:     IN PIRP Irp
                    136:     );
                    137: 
                    138: 
                    139: NTSTATUS
                    140: CdAudio435DeviceControl(
                    141:     IN PDEVICE_OBJECT DeviceObject,
                    142:     IN PIRP Irp
                    143:     );
                    144: 
                    145: 
                    146: NTSTATUS
                    147: CdAudioIoCompletion(
                    148:     IN PDEVICE_OBJECT DeviceObject,
                    149:     IN PIRP Irp,
                    150:     IN PVOID Context
                    151:     );
                    152: 
                    153: //
                    154: // from class.h
                    155: //
                    156: 
                    157: NTSTATUS
                    158: ScsiClassSendSrbSynchronous(
                    159:     PDEVICE_OBJECT DeviceObject,
                    160:     PSCSI_REQUEST_BLOCK Srb,
                    161:     PVOID BufferAddress,
                    162:     ULONG BufferLength,
                    163:     BOOLEAN WriteToDevice
                    164:     );
                    165: 
                    166: VOID
                    167: ScsiClassReleaseQueue(
                    168:     IN PDEVICE_OBJECT DeviceObject
                    169:     );
                    170: 
                    171: //
                    172: // define for private CdDump
                    173: //
                    174: 
                    175: int
                    176: sprintf(
                    177:     char *s,
                    178:     const char *format,
                    179:     ...
                    180:     );
                    181: 
                    182: 
                    183: NTSTATUS
                    184: DriverEntry(
                    185:     IN PDRIVER_OBJECT DriverObject,
                    186:     IN PUNICODE_STRING RegistryPath
                    187:     )
                    188: 
                    189: {
                    190:     return CdAudioInitialize(DriverObject);
                    191: }
                    192: 
                    193: 
                    194: 
                    195: NTSTATUS
                    196: CdAudioInitialize(
                    197:     IN PDRIVER_OBJECT DriverObject
                    198:     )
                    199: 
                    200: /*++
                    201: 
                    202: Routine Description:
                    203: 
                    204:     Initialize CdAudio driver.
                    205:     This is the system initialization entry point when
                    206:     the driver is linked into the kernel.
                    207: 
                    208: Arguments:
                    209: 
                    210:     DriverObject
                    211: 
                    212: Return Value:
                    213: 
                    214:     NTSTATUS
                    215: 
                    216: --*/
                    217: 
                    218: {
                    219:     PCONFIGURATION_INFORMATION configurationInformation;
                    220:     UCHAR               deviceNameBuffer[64];
                    221:     ANSI_STRING         deviceName;
                    222:     UNICODE_STRING      unicodeDeviceName;
                    223:     PDEVICE_OBJECT      cdaudioDevice;
                    224:     PCD_DEVICE_EXTENSION   deviceExtension;
                    225:     NTSTATUS            status;
                    226:     ULONG               disks,activedisks;
                    227:     SCSI_REQUEST_BLOCK  srb;
                    228:     PCDB                cdb = (PCDB)srb.Cdb;
                    229:     PUCHAR              inquiryDataPtr;
                    230: 
                    231:     //
                    232:     // Set up the device driver entry points.
                    233:     //
                    234: 
                    235:     DriverObject->MajorFunction[IRP_MJ_CREATE]         = CdAudioCreate;
                    236:     DriverObject->MajorFunction[IRP_MJ_READ]           = CdAudioReadWrite;
                    237:     DriverObject->MajorFunction[IRP_MJ_WRITE]          = CdAudioReadWrite;
                    238:     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CdAudioDeviceControl;
                    239: 
                    240:     //
                    241:     // Get the configuration information for this driver.
                    242:     //
                    243: 
                    244:     configurationInformation = IoGetConfigurationInformation();
                    245: 
                    246:     CdDump((1, "CdAudioInitialize: Found %d CdRom drives\n",
                    247:                 configurationInformation->CdRomCount));
                    248: 
                    249:     //
                    250:     // Find disk devices.
                    251:     //
                    252: 
                    253:     activedisks = 0;
                    254:     for (disks = 0; disks < configurationInformation->CdRomCount; disks++) {
                    255: 
                    256: 
                    257:         //
                    258:         // Create device name for CdAudio (one per CdRom).
                    259:         //
                    260: 
                    261:         sprintf(deviceNameBuffer,
                    262:                 "\\Device\\CdAudio%d",
                    263:                 disks);
                    264:         CdDump(( 5, "CdAudioInitialize: Checking \\Device\\CdRom%d\n",
                    265:                      disks ));
                    266:         RtlInitAnsiString(&deviceName,
                    267:                           deviceNameBuffer);
                    268:         RtlAnsiStringToUnicodeString(&unicodeDeviceName,
                    269:                                      &deviceName,
                    270:                                      TRUE);
                    271: 
                    272:         //
                    273:         // Create the device object for CdAudio.
                    274:         //
                    275: 
                    276:         status = IoCreateDevice(DriverObject,
                    277:                                 sizeof(CD_DEVICE_EXTENSION),
                    278:                                 &unicodeDeviceName,
                    279:                                 FILE_DEVICE_CD_ROM,
                    280:                                 0,
                    281:                                 FALSE,
                    282:                                 &cdaudioDevice);
                    283: 
                    284:         RtlFreeUnicodeString(&unicodeDeviceName);
                    285: 
                    286:         if (!NT_SUCCESS(status)) {
                    287:             CdDump((1, "CdAudioInitialize: IoCreateDevice( \"%s\" ) failed, 0x%lX\n",
                    288:                         deviceNameBuffer, status));
                    289:             continue;
                    290:         }
                    291: 
                    292:         //
                    293:         // Point device extension back at device object.
                    294:         //
                    295: 
                    296:         deviceExtension = cdaudioDevice->DeviceExtension;
                    297:         deviceExtension->DeviceObject = cdaudioDevice;
                    298: 
                    299:         //
                    300:         // Attach to cdrom drive. This call links the newly created
                    301:         // device to the target device, returning the target device
                    302:         // object.
                    303:         //
                    304: 
                    305:         sprintf(deviceNameBuffer,
                    306:                 "\\Device\\CdRom%d",
                    307:                 disks);
                    308:         RtlInitAnsiString(&deviceName,
                    309:                           deviceNameBuffer);
                    310:         RtlAnsiStringToUnicodeString(&unicodeDeviceName,
                    311:                                      &deviceName,
                    312:                                      TRUE);
                    313:         status = IoAttachDevice(cdaudioDevice,
                    314:                                 &unicodeDeviceName,
                    315:                                 &deviceExtension->TargetDeviceObject);
                    316:         RtlFreeUnicodeString(&unicodeDeviceName);
                    317: 
                    318:         if (!NT_SUCCESS(status)) {
                    319:             IoDeleteDevice(cdaudioDevice);
                    320:             CdDump((1, "CdAudioInialize: IoAttachDevice( \"%s\" ) failed, 0x%lX\n",
                    321:                         deviceNameBuffer, status));
                    322:             continue;
                    323:         }
                    324: 
                    325:         //
                    326:         // Initialize the class device extension. This is used by the
                    327:         // class commands such as ScsiClassSendSrbSynchronous.  The only fields used
                    328:         // are the port device object pointer which is set to the attached
                    329:         // device.  The DeviceNumber, DeviceObject, and TimeOutVlaue are also
                    330:         // used. The logical unit address will be set the the lower driver.
                    331:         //
                    332: 
                    333:         deviceExtension->ClassDeviceExtension.DeviceObject = cdaudioDevice;
                    334:         deviceExtension->ClassDeviceExtension.DeviceNumber = disks;
                    335:         deviceExtension->ClassDeviceExtension.PortDeviceObject =
                    336:             deviceExtension->TargetDeviceObject;
                    337:         deviceExtension->ClassDeviceExtension.TimeOutValue = AUDIO_TIMEOUT;
                    338: 
                    339:         //
                    340:         // Indicate to drivers above us that we want IRPs
                    341:         // with MDLs, so we can pass them directly on to
                    342:         // scsicdrm.sys when we don't handle the call.
                    343:         //
                    344: 
                    345:         cdaudioDevice->Flags |= DO_DIRECT_IO;
                    346: 
                    347:         //
                    348:         // Check to see if we want to install for this
                    349:         // cdrom drive.  Build up cdb/srb, and send it
                    350:         // to this drive.
                    351:         //
                    352: 
                    353:         //
                    354:         // Zero CDB in SRB on stack
                    355:         //
                    356: 
                    357:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                    358: 
                    359:         //
                    360:         // Fill in CDB for INQUIRY to CDROM
                    361:         //
                    362: 
                    363:         cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
                    364:         cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
                    365: 
                    366:         //
                    367:         // Allocate buffer for returned inquiry data
                    368:         //
                    369: 
                    370:         inquiryDataPtr = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                    371:                                                  INQUIRYDATABUFFERSIZE
                    372:                                                 );
                    373: 
                    374:         //
                    375:         // Set length of CDB
                    376:         //
                    377: 
                    378:         srb.CdbLength = 6;
                    379: 
                    380:         //
                    381:         // Set timeout value.
                    382:         //
                    383: 
                    384:         srb.TimeOutValue = AUDIO_TIMEOUT;
                    385: 
                    386:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                    387:                                      &srb,
                    388:                                      inquiryDataPtr,
                    389:                                      INQUIRYDATABUFFERSIZE,
                    390:                                      FALSE
                    391:                                     );
                    392: 
                    393:         if (!NT_SUCCESS(status)) {
                    394: 
                    395:             CdDump(( 1, "CdAudioInitialize: Inquiry failed! (0x%lx)\n",
                    396:                          status ));
                    397: 
                    398:             ExFreePool( inquiryDataPtr );
                    399:             IoDetachDevice(deviceExtension->TargetDeviceObject);
                    400:             IoDeleteDevice(cdaudioDevice);
                    401: 
                    402:         } else {
                    403: 
                    404:             //
                    405:             // Initialize device extension data
                    406:             //
                    407: 
                    408:             deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
                    409:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                    410:             deviceExtension->PausedM  = 0;
                    411:             deviceExtension->PausedS  = 0;
                    412:             deviceExtension->PausedF  = 0;
                    413:             deviceExtension->LastEndM = 0;
                    414:             deviceExtension->LastEndS = 0;
                    415:             deviceExtension->LastEndF = 0;
                    416: 
                    417:             //
                    418:             // Check for NEC drive
                    419:             //
                    420: 
                    421:             if ((inquiryDataPtr[8] =='N') &&
                    422:                 (inquiryDataPtr[9] =='E') &&
                    423:                 (inquiryDataPtr[10]=='C')) {
                    424: 
                    425:                 deviceExtension->Active = CDAUDIO_NEC;
                    426:                 CdDump(( 3, "CdAudioInitialize: %s is a NEC drive.\n",
                    427:                              deviceNameBuffer ));
                    428:             }
                    429: 
                    430:             //
                    431:             // Check for PIONEER DRM-6xx drive
                    432:             //
                    433: 
                    434:             if ((inquiryDataPtr[8] =='P') &&
                    435:                 (inquiryDataPtr[9] =='I') &&
                    436:                 (inquiryDataPtr[10]=='O') &&
                    437:                 (inquiryDataPtr[23]=='D') &&
                    438:                 (inquiryDataPtr[24]=='R') &&
                    439:                 (inquiryDataPtr[25]=='M') &&
                    440:                 (inquiryDataPtr[27]=='6')) {
                    441: 
                    442:                 deviceExtension->Active = CDAUDIO_PIONEER;
                    443:                 CdDump(( 3, "CdAudioInitialize: %s is a PIONEER DRM-6xx drive.\n",
                    444:                              deviceNameBuffer ));
                    445:             }
                    446: 
                    447:             //
                    448:             // Check for DENON drive
                    449:             //
                    450: 
                    451:             if ((inquiryDataPtr[8] =='D') &&
                    452:                 (inquiryDataPtr[9] =='E') &&
                    453:                 (inquiryDataPtr[10]=='N') &&
                    454:                 (inquiryDataPtr[16]=='D') &&
                    455:                 (inquiryDataPtr[17]=='R') &&
                    456:                 (inquiryDataPtr[18]=='D') &&
                    457:                 (inquiryDataPtr[20]=='2') &&
                    458:                 (inquiryDataPtr[21]=='5') &&
                    459:                 (inquiryDataPtr[22]=='X')) {
                    460: 
                    461:                 deviceExtension->Active = CDAUDIO_DENON;
                    462:                 CdDump(( 3, "CdAudioInitialize: %s is a DENON DRD-25X drive.\n",
                    463:                              deviceNameBuffer ));
                    464:             }
                    465:                 
                    466:             //
                    467:             // Check for Chinon CDS-535
                    468:             //
                    469:             
                    470:             if ((inquiryDataPtr[8] =='C') &&
                    471:                 (inquiryDataPtr[9] =='H') &&
                    472:                 (inquiryDataPtr[10]=='I') &&
                    473:                 (inquiryDataPtr[11]=='N') &&
                    474:                 (inquiryDataPtr[12]=='O') &&
                    475:                 (inquiryDataPtr[13]=='N') &&
                    476:                 (inquiryDataPtr[27]=='5') &&
                    477:                 (inquiryDataPtr[28]=='3') &&
                    478:                 (inquiryDataPtr[29]=='5') &&
                    479:                 (inquiryDataPtr[32]=='Q')) {
                    480:             
                    481:                 deviceExtension->Active = CDAUDIO_CDS535;
                    482:                 CdDump(( 3, "CdAudioInitialize: %s is a Chinon CDS-535 drive.\n",
                    483:                              deviceNameBuffer ));
                    484:             }
                    485:             
                    486:             //
                    487:             // Check for Chinon CDS-435 or CDS-431
                    488:             //  (willing to handle versions M/N, S/U, and H)
                    489:             
                    490:             if ((inquiryDataPtr[8] =='C') &&
                    491:                 (inquiryDataPtr[9] =='H') &&
                    492:                 (inquiryDataPtr[10]=='I') &&
                    493:                 (inquiryDataPtr[11]=='N') &&
                    494:                 (inquiryDataPtr[12]=='O') &&
                    495:                 (inquiryDataPtr[13]=='N') &&
                    496:                 (inquiryDataPtr[27]=='4') &&
                    497:                 (inquiryDataPtr[28]=='3') &&
                    498:                 ((inquiryDataPtr[29]=='5') || (inquiryDataPtr[29]=='1')) &&
                    499:                 ((inquiryDataPtr[32]=='M') ||
                    500:                  (inquiryDataPtr[32]=='N') ||
                    501:                  (inquiryDataPtr[32]=='S') ||
                    502:                  (inquiryDataPtr[32]=='U') ||
                    503:                  (inquiryDataPtr[32]=='H')
                    504:                 )) {
                    505:             
                    506:                 deviceExtension->Active = CDAUDIO_CDS435;
                    507:                 CdDump(( 3, "CdAudioInitialize: %s is a Chinon CDS-435/431 drive.\n",
                    508:                              deviceNameBuffer ));
                    509:             }
                    510: 
                    511:             //
                    512:             // Check for HITATCHI drives
                    513:             //
                    514: 
                    515:             if ((inquiryDataPtr[8] =='H') &&
                    516:                 (inquiryDataPtr[9] =='I') &&
                    517:                 (inquiryDataPtr[10]=='T') &&
                    518:                 (inquiryDataPtr[16]=='C') &&
                    519:                 (inquiryDataPtr[17]=='D') &&
                    520:                 (inquiryDataPtr[18]=='R')) {
                    521: 
                    522:                 //
                    523:                 // It's a Hitatchi drive...is it one we want to
                    524:                 // handle...?
                    525:                 //
                    526: 
                    527:                 if ( ((inquiryDataPtr[20]=='1') &&
                    528:                       (inquiryDataPtr[21]=='7') &&
                    529:                       (inquiryDataPtr[22]=='5') &&
                    530:                       (inquiryDataPtr[23]=='0') &&
                    531:                       (inquiryDataPtr[24]=='S'))  ||
                    532: 
                    533:                      ((inquiryDataPtr[20]=='1') &&
                    534:                       (inquiryDataPtr[21]=='6') &&
                    535:                       (inquiryDataPtr[22]=='5') &&
                    536:                       (inquiryDataPtr[23]=='0') &&
                    537:                       (inquiryDataPtr[24]=='S'))  ||
                    538: 
                    539:                      ((inquiryDataPtr[20]=='3') &&
                    540:                       (inquiryDataPtr[21]=='6') &&
                    541:                       (inquiryDataPtr[22]=='5') &&
                    542:                       (inquiryDataPtr[23]=='0'))
                    543: 
                    544:                    ) {
                    545: 
                    546:                         //
                    547:                         // Yes, we want to handle this HITATCHI drive...
                    548:                         //
                    549: 
                    550:                         deviceExtension->Active = CDAUDIO_HITATCHI;
                    551:                         inquiryDataPtr[25] = (UCHAR)0;
                    552:                         CdDump(( 3,
                    553:                             "CdAudioInitialize: %s is a HITATCHI %s drive.\n",
                    554:                             deviceNameBuffer, &inquiryDataPtr[16] ));
                    555:                     }
                    556:                 
                    557:             }
                    558: 
                    559:             ExFreePool( inquiryDataPtr );
                    560: 
                    561:             //
                    562:             // Check to see if we attached to ANY drives.
                    563:             //
                    564: 
                    565:             if (deviceExtension->Active==CDAUDIO_NOT_ACTIVE) {
                    566: 
                    567:                 IoDetachDevice(deviceExtension->TargetDeviceObject);
                    568:                 IoDeleteDevice(cdaudioDevice);
                    569:                 CdDump((1, "CdAudioInitialize: failed attach to %s\n",
                    570:                             deviceNameBuffer));
                    571: 
                    572:             } else
                    573: 
                    574:                 activedisks++;
                    575: 
                    576:         } // end inquiry was successful
                    577: 
                    578:     } // end for (disks ...)
                    579: 
                    580:     CdDump((1, "CdAudioInitialize: Done searching all cdrom drives\n"));
                    581: 
                    582:     if (activedisks==0)
                    583: 
                    584:         return STATUS_NO_SUCH_DEVICE;
                    585: 
                    586:     else
                    587: 
                    588:         return STATUS_SUCCESS;
                    589: 
                    590: } // end CdAudioInitialize()
                    591: 
                    592: 
                    593: NTSTATUS
                    594: CdAudioCreate(
                    595:     IN PDEVICE_OBJECT DeviceObject,
                    596:     IN PIRP Irp
                    597:     )
                    598: 
                    599: /*++
                    600: 
                    601: Routine Description:
                    602: 
                    603:     This routine serves create commands. It does no more than
                    604:     establish the drivers existance by returning status success.
                    605: 
                    606: Arguments:
                    607: 
                    608:     DeviceObject
                    609:     IRP
                    610: 
                    611: Return Value:
                    612: 
                    613:     NT Status
                    614: 
                    615: --*/
                    616: 
                    617: {
                    618:     UNREFERENCED_PARAMETER(DeviceObject);
                    619: 
                    620:     Irp->IoStatus.Status = STATUS_SUCCESS;
                    621: 
                    622:     IoCompleteRequest(Irp, 0);
                    623:     return STATUS_SUCCESS;
                    624: 
                    625: } // end CdAudioCreate()
                    626: 
                    627: 
                    628: NTSTATUS
                    629: CdAudioReadWrite(
                    630:     IN PDEVICE_OBJECT DeviceObject,
                    631:     IN PIRP Irp
                    632:     )
                    633: 
                    634: /*++
                    635: 
                    636: Routine Description:
                    637: 
                    638:     This is the driver entry point for read and write requests
                    639:     to the cdrom.  Since we only want to trap device control requests,
                    640:     we will just pass these requests on to the original driver.
                    641: 
                    642: Arguments:
                    643: 
                    644:     DeviceObject - pointer to device object for disk partition
                    645:     Irp - NT IO Request Packet
                    646: 
                    647: Return Value:
                    648: 
                    649:     NTSTATUS - status of request
                    650: 
                    651: --*/
                    652: 
                    653: {
                    654:     PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
                    655: 
                    656:     //
                    657:     // If the cd is playing music then reject this request.
                    658:     //
                    659: 
                    660:     if (deviceExtension->PlayActive) {
                    661:         Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
                    662:         IoCompleteRequest(Irp, IO_NO_INCREMENT);
                    663:         return STATUS_DEVICE_BUSY;
                    664:     }
                    665: 
                    666:     //
                    667:     // simply return status of driver below us...
                    668:     //
                    669: 
                    670:     return CdAudioSendToNextDriver( DeviceObject, Irp );
                    671: 
                    672: } // end CdAudioReadWrite()
                    673: 
                    674: 
                    675: NTSTATUS
                    676: CdAudioDeviceControl(
                    677:     PDEVICE_OBJECT DeviceObject,
                    678:     PIRP Irp
                    679:     )
                    680: 
                    681: /*++
                    682: 
                    683: Routine Description:
                    684: 
                    685:     This routine is called by the I/O subsystem for device controls.
                    686: 
                    687: Arguments:
                    688: 
                    689:     DeviceObject
                    690:     Irp
                    691: 
                    692: Return Value:
                    693: 
                    694:     NTSTATUS
                    695: 
                    696: --*/
                    697: 
                    698: {
                    699:     PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
                    700:     NTSTATUS status;
                    701: 
                    702:     switch( deviceExtension->Active ) {
                    703: 
                    704:         case CDAUDIO_NOT_ACTIVE:
                    705:             CdDump(( 3,
                    706:                 "CdAudioDeviceControl: NOT ACTIVE for this drive.\n"
                    707:                 ));
                    708:             status = CdAudioSendToNextDriver( DeviceObject, Irp );
                    709:             break;
                    710: 
                    711:         case CDAUDIO_NEC:
                    712:             status = CdAudioNECDeviceControl( DeviceObject, Irp );
                    713:             break;
                    714: 
                    715:         case CDAUDIO_PIONEER:
                    716:             status = CdAudioPioneerDeviceControl( DeviceObject, Irp );
                    717:             break;
                    718: 
                    719:         case CDAUDIO_DENON:
                    720:             status = CdAudioDenonDeviceControl( DeviceObject, Irp );
                    721:             break;
                    722: 
                    723:         case CDAUDIO_HITATCHI:
                    724:             status = CdAudioHitatchiDeviceControl( DeviceObject, Irp );
                    725:             break;
                    726: 
                    727:         case CDAUDIO_CDS535:
                    728:             status = CdAudio535DeviceControl( DeviceObject, Irp );
                    729:             break;
                    730: 
                    731:         case CDAUDIO_CDS435:
                    732:             status = CdAudio435DeviceControl( DeviceObject, Irp );
                    733:             break;
                    734: 
                    735:         default:
                    736:             CdDump(( 1,
                    737:                 "CdAudioDeviceControl: Active==UNKNOWN!!! This is bad!\n"
                    738:                 ));
                    739:             status = STATUS_UNSUCCESSFUL;
                    740: 
                    741:     }
                    742: 
                    743:     return status;
                    744: 
                    745: } // end CdAudioDeviceControl()
                    746: 
                    747: 
                    748: 
                    749: NTSTATUS
                    750: CdAudioSendToNextDriver(
                    751:     PDEVICE_OBJECT DeviceObject,
                    752:     PIRP Irp
                    753:     )
                    754: 
                    755: /*++
                    756: 
                    757: Routine Description:
                    758: 
                    759:     This routine is sends the Irp to the next driver in line
                    760:     when the Irp is not processed by this driver.
                    761: 
                    762: Arguments:
                    763: 
                    764:     DeviceObject
                    765:     Irp
                    766: 
                    767: Return Value:
                    768: 
                    769:     NTSTATUS
                    770: 
                    771: --*/
                    772: 
                    773: {
                    774:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                    775:     PIO_STACK_LOCATION nextIrpStack    = IoGetNextIrpStackLocation(Irp);
                    776:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                    777: 
                    778:     //
                    779:     // Copy stack parameters to next stack.
                    780:     //
                    781: 
                    782:     RtlMoveMemory(nextIrpStack,
                    783:                   currentIrpStack,
                    784:                   sizeof(IO_STACK_LOCATION));
                    785: 
                    786:     //
                    787:     // Set IRP so IoComplete calls our completion routine.
                    788:     //
                    789: 
                    790:     IoSetCompletionRoutine(Irp,
                    791:                            CdAudioIoCompletion,
                    792:                            deviceExtension,
                    793:                            TRUE,
                    794:                            TRUE,
                    795:                            TRUE);
                    796: 
                    797:     //
                    798:     // Pass unrecognized device control requests
                    799:     // down to next driver layer.
                    800:     //
                    801: 
                    802:     return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
                    803: 
                    804: }
                    805: 
                    806: NTSTATUS
                    807: CdAudioIoCompletion(
                    808:     IN PDEVICE_OBJECT DeviceObject,
                    809:     IN PIRP Irp,
                    810:     IN PVOID Context
                    811:     )
                    812: 
                    813: /*++
                    814: 
                    815: Routine Description:
                    816: 
                    817:     This routine is called when the I/O request has completed.
                    818: 
                    819: Arguments:
                    820: 
                    821:     DeviceObject - SimBad device object.
                    822:     Irp          - Completed request.
                    823:     Context      - not used.  Set up to also be a pointer to the DeviceObject.
                    824: 
                    825: Return Value:
                    826: 
                    827:     NTSTATUS
                    828: 
                    829: --*/
                    830: 
                    831: {
                    832:     UNREFERENCED_PARAMETER(Context);
                    833:     UNREFERENCED_PARAMETER(DeviceObject);
                    834: 
                    835: 
                    836:     //
                    837:     // If pending is returned for this Irp then mark current stack
                    838:     // as pending
                    839:     //
                    840: 
                    841:     if (Irp->PendingReturned) {
                    842: 
                    843:         IoMarkIrpPending( Irp );
                    844: 
                    845:     }
                    846: 
                    847:     return Irp->IoStatus.Status;
                    848: 
                    849: }
                    850: 
                    851: BOOLEAN
                    852: CdAudioIsPlayActive(
                    853:     IN PDEVICE_OBJECT DeviceObject
                    854:     )
                    855: 
                    856: /*++
                    857: 
                    858: Routine Description:
                    859: 
                    860:     This routine determines if the cd is currently playing music.
                    861: 
                    862: Arguments:
                    863: 
                    864:     DeviceObject - Device object to test.
                    865: 
                    866: Return Value:
                    867: 
                    868:     TRUE if the device is playing music.
                    869: 
                    870: --*/
                    871: {
                    872:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                    873:     PIRP irp;
                    874:     IO_STATUS_BLOCK ioStatus;
                    875:     KEVENT event;
                    876:     NTSTATUS status;
                    877:     PSUB_Q_CURRENT_POSITION currentBuffer;
                    878:     BOOLEAN returnValue;
                    879: 
                    880:     if (!deviceExtension->PlayActive) {
                    881:         return(FALSE);
                    882:     }
                    883: 
                    884:     currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
                    885: 
                    886:     if (currentBuffer == NULL) {
                    887:         return(FALSE);
                    888:     }
                    889: 
                    890:     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
                    891:     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
                    892: 
                    893:     //
                    894:     // Create notification event object to be used to signal the
                    895:     // request completion.
                    896:     //
                    897: 
                    898:     KeInitializeEvent(&event, NotificationEvent, FALSE);
                    899: 
                    900:     //
                    901:     // Build the synchronous request  to be sent to the port driver
                    902:     // to perform the request.
                    903:     //
                    904: 
                    905:     irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
                    906:                                         deviceExtension->DeviceObject,
                    907:                                         currentBuffer,
                    908:                                         sizeof(CDROM_SUB_Q_DATA_FORMAT),
                    909:                                         currentBuffer,
                    910:                                         sizeof(SUB_Q_CURRENT_POSITION),
                    911:                                         FALSE,
                    912:                                         &event,
                    913:                                         &ioStatus);
                    914: 
                    915:     if (irp == NULL) {
                    916:         ExFreePool(currentBuffer);
                    917:         return FALSE;
                    918:     }
                    919: 
                    920:     //
                    921:     // Pass request to port driver and wait for request to complete.
                    922:     //
                    923: 
                    924:     status = IoCallDriver(deviceExtension->DeviceObject, irp);
                    925: 
                    926:     if (status == STATUS_PENDING) {
                    927:         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
                    928:         status = ioStatus.Status;
                    929:     }
                    930: 
                    931:     if (!NT_SUCCESS(status)) {
                    932:         ExFreePool(currentBuffer);
                    933:         return FALSE;
                    934:     }
                    935: 
                    936:     if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
                    937: 
                    938:         returnValue = TRUE;
                    939:     } else {
                    940:         returnValue = FALSE;
                    941:         deviceExtension->PlayActive = FALSE;
                    942:     }
                    943: 
                    944:     ExFreePool(currentBuffer);
                    945: 
                    946:     return(returnValue);
                    947: 
                    948: 
                    949: }
                    950: 
                    951: 
                    952: NTSTATUS
                    953: CdAudioNECInterpretSenseInfo(
                    954:     IN PDEVICE_OBJECT DeviceObject,
                    955:     IN PSCSI_REQUEST_BLOCK Srb,
                    956:     IN UCHAR MajorFunctionCode,
                    957:     IN ULONG IoDeviceCode,
                    958:     IN ULONG RetryCount,
                    959:     OUT NTSTATUS *Status
                    960:     )
                    961: 
                    962: /*++
                    963: 
                    964: Routine Description:
                    965: 
                    966:     This routine interprets the data returned from the SCSI
                    967:     request sense. It determines the status to return in the
                    968:     IRP and whether this request can be retried.
                    969: 
                    970: Arguments:
                    971: 
                    972:     DeviceObject - Supplies the device object associated with this request.
                    973: 
                    974:     Srb - Supplies the scsi request block which failed.
                    975: 
                    976:     MajorFunctionCode - Supplies the function code to be used for logging.
                    977: 
                    978:     IoDeviceCode - Supplies the device code to be used for logging.
                    979: 
                    980:     Status - Returns the status for the request.
                    981: 
                    982: Return Value:
                    983: 
                    984:     BOOLEAN TRUE: Drivers should retry this request.
                    985:             FALSE: Drivers should not retry this request.
                    986: 
                    987: --*/
                    988: 
                    989: {
                    990:     PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
                    991:     PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
                    992:     PIRP irp = Srb->OriginalRequest;
                    993:     BOOLEAN retry;
                    994:     BOOLEAN logError;
                    995:     ULONG uniqueId;
                    996:     NTSTATUS logStatus;
                    997:     PIO_ERROR_LOG_PACKET errorLogEntry;
                    998:     ULONG badSector;
                    999: 
                   1000:     logError = FALSE;
                   1001:     retry = TRUE;
                   1002:     badSector = 0;
                   1003: 
                   1004:     //
                   1005:     // Check that request sense buffer is valid.
                   1006:     //
                   1007: 
                   1008:     if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
                   1009: 
                   1010:         CdDump((1,"CdAudioNECInterpretSenseInfo: Error code is %x\n",
                   1011:                     senseBuffer->ErrorCode));
                   1012: 
                   1013:         CdDump((1,"CdAudioNECInterpretSenseInfo: Sense key is %x\n",
                   1014:                     senseBuffer->SenseKey));
                   1015: 
                   1016:         CdDump((1,"CdAudioNECInterpretSenseInfo: Additional sense code is %x\n",
                   1017:                     senseBuffer->CommandSpecificInformation[1]));
                   1018: 
                   1019:             switch (senseBuffer->SenseKey & 0xf) {
                   1020: 
                   1021:                 case SCSI_SENSE_NOT_READY:
                   1022: 
                   1023:                     CdDump((1,"CdAudioNECInterpretSenseInfo: Device not ready\n"));
                   1024: 
                   1025:                     *Status = STATUS_DEVICE_NOT_READY;
                   1026: 
                   1027:                     retry = TRUE;
                   1028: 
                   1029:                     switch (senseBuffer->CommandSpecificInformation[1]) {
                   1030: 
                   1031:                     case NEC_SCSI_ERROR_NO_DISC:
                   1032:                         CdDump(( 1, "CdAudioNECInterpretSenseInfo: No disc in drive\n" ));
                   1033:                         *Status = STATUS_NO_MEDIA_IN_DEVICE;
                   1034:                         retry = FALSE;
                   1035:                         break;
                   1036: 
                   1037:                     case NEC_SCSI_ERROR_ILLEGAL_DISC:
                   1038:                         CdDump(( 1, "CdAudioNECInterpretSenseInfo: Unrecognized media\n" ));
                   1039:                         *Status = STATUS_UNRECOGNIZED_MEDIA;
                   1040:                         retry = FALSE;
                   1041:                         break;
                   1042: 
                   1043:                     case NEC_SCSI_ERROR_TRAY_OPEN:
                   1044:                         CdDump(( 1, "CdAudioNECInterpretSenseInfo: Tray open\n" ));
                   1045:                         *Status = STATUS_NO_MEDIA_IN_DEVICE;
                   1046:                         retry = FALSE;
                   1047:                         break;
                   1048: 
                   1049:                     } // end switch
                   1050: 
                   1051:                     break;
                   1052: 
                   1053:                 case SCSI_SENSE_DATA_PROTECT:
                   1054: 
                   1055:                     CdDump((1,
                   1056:                                 "CdAudioNECInterpretSenseInfo: Media write protected\n"));
                   1057: 
                   1058:                     *Status = STATUS_MEDIA_WRITE_PROTECTED;
                   1059: 
                   1060:                     retry = FALSE;
                   1061: 
                   1062:                     break;
                   1063: 
                   1064:                 case SCSI_SENSE_MEDIUM_ERROR:
                   1065: 
                   1066:                     CdDump((1,"CdAudioNECInterpretSenseInfo: Bad media\n"));
                   1067:                     *Status = STATUS_DEVICE_DATA_ERROR;
                   1068: 
                   1069:                     retry = TRUE;
                   1070:                     logError = TRUE;
                   1071:                     uniqueId = 256;
                   1072:                     logStatus = IO_ERR_BAD_BLOCK;
                   1073:                     switch (senseBuffer->CommandSpecificInformation[1]) {
                   1074: 
                   1075:                     case NEC_SCSI_ERROR_SEEK_ERROR:
                   1076:                         CdDump(( 1, "CdAudioNECInterpretSenseInfo: Sector not found\n" ));
                   1077:                         *Status = STATUS_NONEXISTENT_SECTOR;
                   1078:                         retry = FALSE;
                   1079:                         break;
                   1080:                     case NEC_SCSI_ERROR_MUSIC_AREA:
                   1081:                         CdDump((1,"CdAudioNECInterpretSenseInfo: Music area\n"));
                   1082:                         break;
                   1083: 
                   1084:                     case NEC_SCSI_ERROR_DATA_AREA:
                   1085:                         CdDump((1,"CdAudioNECInterpretSenseInfo: Data area\n"));
                   1086:                         break;
                   1087: 
                   1088: 
                   1089:                     } // end switch
                   1090:                     break;
                   1091: 
                   1092:                 case SCSI_SENSE_HARDWARE_ERROR:
                   1093: 
                   1094:                     CdDump((1,"CdAudioNECInterpretSenseInfo: Hardware error\n"));
                   1095:                     *Status = STATUS_IO_DEVICE_ERROR;
                   1096: 
                   1097:                     retry = TRUE;
                   1098:                     logError = TRUE;
                   1099:                     uniqueId = 257;
                   1100:                     logStatus = IO_ERR_CONTROLLER_ERROR;
                   1101:                     switch (senseBuffer->CommandSpecificInformation[1]) {
                   1102: 
                   1103:                     case NEC_SCSI_ERROR_PARITY_ERROR:
                   1104:                         CdDump(( 1, "CdAudioNECInterpretSenseInfo: Parity error\n" ));
                   1105:                         *Status = STATUS_PARITY_ERROR;
                   1106:                         retry = FALSE;
                   1107:                         break;
                   1108: 
                   1109:                     } // end switch
                   1110: 
                   1111:                     break;
                   1112: 
                   1113:                 case SCSI_SENSE_ILLEGAL_REQUEST:
                   1114: 
                   1115:                     CdDump((1,
                   1116:                                 "CdAudioNECInterpretSenseInfo: Illegal SCSI request\n"));
                   1117: 
                   1118:                     *Status = STATUS_INVALID_DEVICE_REQUEST;
                   1119: 
                   1120:                     switch (senseBuffer->AdditionalSenseCode) {
                   1121: 
                   1122:                     case NEC_SCSI_ERROR_INVALID_COMMAND:
                   1123:                         CdDump((1,
                   1124:                                   "CdAudioNECInterpretSenseInfo: Illegal command\n"));
                   1125:                         break;
                   1126: 
                   1127:                     case NEC_SCSI_ERROR_INVALID_ADDRESS:
                   1128:                         CdDump((1,
                   1129:                             "CdAudioNECInterpretSenseInfo: Illegal block address\n"));
                   1130:                         *Status = STATUS_NONEXISTENT_SECTOR;
                   1131:                         break;
                   1132: 
                   1133:                     case NEC_SCSI_ERROR_END_OF_VOLUME:
                   1134:                         CdDump((1,
                   1135:                                   "CdAudioNECInterpretSenseInfo: Volume overflow\n"));
                   1136:                         *Status = STATUS_NONEXISTENT_SECTOR;
                   1137:                         break;
                   1138: 
                   1139:                     case NEC_SCSI_ERROR_MEDIA_CHANGED:
                   1140:                     case NEC_SCSI_ERROR_DEVICE_RESET:
                   1141:                         CdDump((1,
                   1142:                             "CdAudioNECInterpretSenseInfo: Media Changed or device reset\n"));
                   1143: 
                   1144:                         if (DeviceObject->Vpb->Flags & VPB_MOUNTED  &&
                   1145:                             DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
                   1146: 
                   1147:                             //
                   1148:                             // Set bit to indicate that media may have changed
                   1149:                             // and volume needs verification.
                   1150:                             //
                   1151: 
                   1152:                             DeviceObject->Flags |= DO_VERIFY_VOLUME;
                   1153: 
                   1154:                             *Status = STATUS_VERIFY_REQUIRED;
                   1155: 
                   1156:                             retry = FALSE;
                   1157: 
                   1158:                         } else {
                   1159:                             *Status = STATUS_IO_DEVICE_ERROR;
                   1160: 
                   1161:                             retry = TRUE;
                   1162: 
                   1163:                         }
                   1164:                         break;
                   1165: 
                   1166: 
                   1167:                     } // end switch ...
                   1168: 
                   1169:                     retry = FALSE;
                   1170: 
                   1171:                     break;
                   1172: 
                   1173:                 case SCSI_SENSE_UNIT_ATTENTION:
                   1174: 
                   1175:                     CdDump((3,"CdAudioNECInterpretSenseInfo: Unit attention\n"));
                   1176: 
                   1177:                     if (DeviceObject->Vpb->Flags & VPB_MOUNTED  &&
                   1178:                         DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
                   1179: 
                   1180:                         //
                   1181:                         // Set bit to indicate that media may have changed
                   1182:                         // and volume needs verification.
                   1183:                         //
                   1184: 
                   1185:                         DeviceObject->Flags |= DO_VERIFY_VOLUME;
                   1186: 
                   1187:                         *Status = STATUS_VERIFY_REQUIRED;
                   1188: 
                   1189:                         retry = FALSE;
                   1190: 
                   1191:                     } else {
                   1192:                         *Status = STATUS_IO_DEVICE_ERROR;
                   1193: 
                   1194:                         retry = TRUE;
                   1195: 
                   1196:                     }
                   1197: 
                   1198:                     break;
                   1199: 
                   1200:                 case SCSI_SENSE_ABORTED_COMMAND:
                   1201: 
                   1202:                     CdDump((1,"CdAudioNECInterpretSenseInfo: Command aborted\n"));
                   1203: 
                   1204:                     *Status = STATUS_IO_DEVICE_ERROR;
                   1205: 
                   1206:                     retry = TRUE;
                   1207: 
                   1208:                     break;
                   1209: 
                   1210:                 case SCSI_SENSE_RECOVERED_ERROR:
                   1211:                     CdDump((1,"CdAudioNECInterpretSenseInfo: Recovered error\n"));
                   1212:                     *Status = STATUS_SUCCESS;
                   1213:                     retry = FALSE;
                   1214:                     logError = TRUE;
                   1215:                     uniqueId = 258;
                   1216:                     logStatus = IO_ERR_CONTROLLER_ERROR;
                   1217:                     break;
                   1218: 
                   1219:                 case SCSI_SENSE_NO_SENSE:
                   1220:                     CdDump((1,
                   1221:                     "CdAudioNECInterpretSenseInfo: No specific sense key\n"));
                   1222:                     *Status = STATUS_IO_DEVICE_ERROR;
                   1223:                     retry   = TRUE;
                   1224:                     break;
                   1225: 
                   1226:                 case SCSI_SENSE_BLANK_CHECK:
                   1227:                     CdDump((1,
                   1228:                                 "CdAudioNECInterpretSenseInfo: Media blank check\n"));
                   1229:                     *Status = STATUS_NO_DATA_DETECTED;
                   1230:                     retry = FALSE;
                   1231:                     break;
                   1232: 
                   1233:                 default:
                   1234: 
                   1235:                     CdDump((1,
                   1236:                         "CdAudioNECInterpretSenseInfo: Unrecognized sense code\n"));
                   1237:                     *Status = STATUS_IO_DEVICE_ERROR;
                   1238:                     retry = TRUE;
                   1239: 
                   1240:         } // end switch
                   1241: 
                   1242:     } else {
                   1243: 
                   1244:         //
                   1245:         // Request sense buffer not valid. No sense information
                   1246:         // to pinpoint the error. Return general request fail.
                   1247:         //
                   1248: 
                   1249:         CdDump((1,"CdAudioNECInterpretSenseInfo: Request sense info not valid\n"));
                   1250:         retry = TRUE;
                   1251: 
                   1252:         switch (SRB_STATUS(Srb->SrbStatus)) {
                   1253:         case SRB_STATUS_INVALID_LUN:
                   1254:         case SRB_STATUS_INVALID_TARGET_ID:
                   1255:         case SRB_STATUS_NO_DEVICE:
                   1256:         case SRB_STATUS_NO_HBA:
                   1257:             *Status = STATUS_NO_SUCH_DEVICE;
                   1258:             retry = FALSE;
                   1259:             break;
                   1260: 
                   1261:         case SRB_STATUS_COMMAND_TIMEOUT:
                   1262:         case SRB_STATUS_TIMEOUT:
                   1263:             *Status = STATUS_IO_TIMEOUT;
                   1264:             break;
                   1265: 
                   1266:         case SRB_STATUS_SELECTION_TIMEOUT:
                   1267:             *Status = STATUS_DEVICE_NOT_CONNECTED;
                   1268:             break;
                   1269: 
                   1270:         case SRB_STATUS_DATA_OVERRUN:
                   1271:             *Status = STATUS_DATA_OVERRUN;
                   1272:             retry = FALSE;
                   1273:             break;
                   1274: 
                   1275:         case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
                   1276:             *Status = STATUS_IO_DEVICE_ERROR;
                   1277: 
                   1278:             //
                   1279:             // If there was  phase sequence error then limit the number of
                   1280:             // retries.
                   1281:             //
                   1282: 
                   1283:             if (RetryCount > 1 ) {
                   1284:                 retry = FALSE;
                   1285:             }
                   1286: 
                   1287:             break;
                   1288: 
                   1289:         case SRB_STATUS_REQUEST_FLUSHED:
                   1290: 
                   1291:             //
                   1292:             // If the status needs verification bit is set.  Then set
                   1293:             // the status to need verificaiton and no retry; otherwise,
                   1294:             // just retry the request.
                   1295:             //
                   1296: 
                   1297:             if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
                   1298: 
                   1299:                 *Status = STATUS_VERIFY_REQUIRED;
                   1300:                 retry = FALSE;
                   1301:             } else {
                   1302:                 *Status = STATUS_IO_DEVICE_ERROR;
                   1303:                 retry = TRUE;
                   1304: 
                   1305:             }
                   1306: 
                   1307:             break;
                   1308: 
                   1309:         default:
                   1310:             *Status = STATUS_IO_DEVICE_ERROR;
                   1311:             break;
                   1312: 
                   1313:         }
                   1314: 
                   1315:     }
                   1316: 
                   1317:     //
                   1318:     // If there is a class specific error handler call it.
                   1319:     //
                   1320: 
                   1321: //    if (deviceExtension->ClassError != NULL) {
                   1322: //
                   1323: //        deviceExtension->ClassError(
                   1324: //            DeviceObject,
                   1325: //            Srb
                   1326: //            );
                   1327: //    }
                   1328: 
                   1329:     if (logError) {
                   1330: 
                   1331:         errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
                   1332:             DeviceObject,
                   1333:             sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG)
                   1334:             );
                   1335: 
                   1336:         if (errorLogEntry == NULL) {
                   1337: 
                   1338:             return retry;
                   1339: 
                   1340:         }
                   1341: 
                   1342:         if (retry && RetryCount < MAXIMUM_RETRIES) {
                   1343:             errorLogEntry->FinalStatus = STATUS_SUCCESS;
                   1344:         } else {
                   1345:             errorLogEntry->FinalStatus = *Status;
                   1346:         }
                   1347: 
                   1348:         errorLogEntry->ErrorCode = logStatus;
                   1349:         errorLogEntry->SequenceNumber = 0;
                   1350:         errorLogEntry->MajorFunctionCode = MajorFunctionCode;
                   1351:         errorLogEntry->IoControlCode = IoDeviceCode;
                   1352:         errorLogEntry->RetryCount = RetryCount;
                   1353:         errorLogEntry->DumpDataSize = 5 * sizeof(ULONG);
                   1354:         errorLogEntry->UniqueErrorValue = uniqueId;
                   1355:         errorLogEntry->DumpDataSize = 5 * sizeof(ULONG);
                   1356:         errorLogEntry->DumpData[0] = Srb->PathId;
                   1357:         errorLogEntry->DumpData[1] = Srb->TargetId;
                   1358:         errorLogEntry->DumpData[2] = Srb->Lun;
                   1359:         errorLogEntry->DumpData[3] = 0;
                   1360:         errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
                   1361:         errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
                   1362:                                  senseBuffer->AdditionalSenseCode << 8 |
                   1363:                                  senseBuffer->AdditionalSenseCodeQualifier;
                   1364: 
                   1365:         IoWriteErrorLogEntry(errorLogEntry);
                   1366:     }
                   1367: 
                   1368:     return retry;
                   1369: 
                   1370: } // end InterpretSenseInfo()
                   1371: 
                   1372: NTSTATUS
                   1373: CdAudioNECSendSrbSynchronous(
                   1374:     PDEVICE_OBJECT DeviceObject,
                   1375:     PSCSI_REQUEST_BLOCK Srb,
                   1376:     PVOID BufferAddress,
                   1377:     ULONG BufferLength,
                   1378:     BOOLEAN WriteToDevice
                   1379:     )
                   1380: 
                   1381: /*++
                   1382: 
                   1383: Routine Description:
                   1384: 
                   1385:     This routine is called by SCSI device controls to complete an
                   1386:     SRB and send it to the port driver synchronously (ie wait for
                   1387:     completion).
                   1388:     The CDB is already completed along with the SRB CDB size and
                   1389:     request timeout value.
                   1390: 
                   1391: Arguments:
                   1392: 
                   1393:     Device Object
                   1394:     SRB
                   1395:     Buffer address and length (if transfer)
                   1396:     WriteToDevice
                   1397: 
                   1398: Return Value:
                   1399: 
                   1400:     NTSTATUS
                   1401: 
                   1402: --*/
                   1403: 
                   1404: {
                   1405:     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
                   1406:     IO_STATUS_BLOCK ioStatus;
                   1407:     PIRP irp;
                   1408:     PIO_STACK_LOCATION irpStack;
                   1409:     KEVENT event;
                   1410:     PUCHAR senseInfoBuffer;
                   1411:     LARGE_INTEGER largeInt = RtlConvertUlongToLargeInteger(0);
                   1412:     ULONG retryCount = MAXIMUM_RETRIES;
                   1413:     NTSTATUS status;
                   1414:     BOOLEAN retry;
                   1415: 
                   1416:     //
                   1417:     // Write length to SRB.
                   1418:     //
                   1419: 
                   1420:     Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
                   1421: 
                   1422:     //
                   1423:     // Set SCSI bus address.
                   1424:     //
                   1425: 
                   1426:     Srb->PathId = deviceExtension->PathId;
                   1427:     Srb->TargetId = deviceExtension->TargetId;
                   1428:     Srb->Lun = deviceExtension->Lun;
                   1429: 
                   1430:     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
                   1431: 
                   1432:     //
                   1433:     // BUGBUG:  This is a violation of the SCSI spec but it is required for
                   1434:     // some targets.
                   1435:     //
                   1436: 
                   1437:     Srb->Cdb[1] |= deviceExtension->Lun << 5;
                   1438: 
                   1439:     //
                   1440:     // Enable auto request sense.
                   1441:     //
                   1442: 
                   1443:     Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
                   1444: 
                   1445:     //
                   1446:     // Sense buffer is in non-paged pool.
                   1447:     //
                   1448: 
                   1449:     senseInfoBuffer = ExAllocatePool( NonPagedPoolCacheAligned,
                   1450:                                       SENSE_BUFFER_SIZE
                   1451:                                      );
                   1452: 
                   1453:     if (senseInfoBuffer == NULL) {
                   1454: 
                   1455:         CdDump((1,
                   1456:             "CdAudioNECSendSrbSynchronous: Can't allocate request sense buffer\n"));
                   1457:         return(STATUS_INSUFFICIENT_RESOURCES);
                   1458:     }
                   1459: 
                   1460:     Srb->SenseInfoBuffer = senseInfoBuffer;
                   1461: 
                   1462:     Srb->DataBuffer = BufferAddress;
                   1463: 
                   1464:     //
                   1465:     // Start retries here.
                   1466:     //
                   1467: 
                   1468: retry:
                   1469: 
                   1470:     if (BufferAddress != NULL) {
                   1471: 
                   1472:         //
                   1473:         // Build the synchronous request with data transfer.
                   1474:         //
                   1475: 
                   1476:         irp = IoBuildSynchronousFsdRequest(
                   1477:                WriteToDevice ? IRP_MJ_WRITE : IRP_MJ_READ,
                   1478:                deviceExtension->PortDeviceObject,
                   1479:                BufferAddress,
                   1480:                BufferLength,
                   1481:                &largeInt,
                   1482:                &event,
                   1483:                &ioStatus);
                   1484: 
                   1485:         if (irp == NULL) {
                   1486:             ExFreePool(senseInfoBuffer);
                   1487:             CdDump((1, "CdAudioNECSendSrbSynchronous: Can't allocate Irp\n"));
                   1488:             return(STATUS_INSUFFICIENT_RESOURCES);
                   1489:         }
                   1490: 
                   1491:         //
                   1492:         // Set read flag.
                   1493:         //
                   1494: 
                   1495:         Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
                   1496: 
                   1497:     } else {
                   1498: 
                   1499:         //
                   1500:         // Build synchronous request with no transfer.
                   1501:         //
                   1502: 
                   1503:         irp = IoBuildDeviceIoControlRequest(
                   1504:                     IRP_MJ_DEVICE_CONTROL,
                   1505:                     deviceExtension->PortDeviceObject,
                   1506:                     NULL,
                   1507:                     0,
                   1508:                     NULL,
                   1509:                     0,
                   1510:                     TRUE,
                   1511:                     &event,
                   1512:                     &ioStatus
                   1513:                        );
                   1514: 
                   1515:         if (irp == NULL) {
                   1516:             ExFreePool(senseInfoBuffer);
                   1517:             CdDump((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
                   1518:             return(STATUS_INSUFFICIENT_RESOURCES);
                   1519:         }
                   1520: 
                   1521:         //
                   1522:         // Clear flags.
                   1523:         //
                   1524: 
                   1525:         Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
                   1526:     }
                   1527: 
                   1528:     //
                   1529:     // Disable synchronous transfer for these requests.
                   1530:     //
                   1531: 
                   1532:     Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
                   1533: 
                   1534:     //
                   1535:     // Set the event object to the unsignaled state.
                   1536:     // It will be used to signal request completion.
                   1537:     //
                   1538: 
                   1539:     KeInitializeEvent(&event, NotificationEvent, FALSE);
                   1540: 
                   1541:     //
                   1542:     // Set the transfer length.
                   1543:     //
                   1544: 
                   1545:     Srb->DataTransferLength = BufferLength;
                   1546: 
                   1547:     //
                   1548:     // Zero out status.
                   1549:     //
                   1550: 
                   1551:     Srb->ScsiStatus = Srb->SrbStatus = 0;
                   1552: 
                   1553:     Srb->NextSrb = 0;
                   1554: 
                   1555:     //
                   1556:     // Get next stack location and
                   1557:     // set major function code.
                   1558:     //
                   1559: 
                   1560:     irpStack = IoGetNextIrpStackLocation(irp);
                   1561: 
                   1562:     irpStack->MajorFunction = IRP_MJ_SCSI;
                   1563: 
                   1564:     //
                   1565:     // Set up SRB for execute scsi request.
                   1566:     // Save SRB address in next stack for port driver.
                   1567:     //
                   1568: 
                   1569:     irpStack->Parameters.Others.Argument1 = (PVOID)Srb;
                   1570: 
                   1571:     //
                   1572:     // Set up IRP Address.
                   1573:     //
                   1574: 
                   1575:     Srb->OriginalRequest = irp;
                   1576: 
                   1577:     //
                   1578:     // No need to check the following 2 returned statuses as
                   1579:     // SRB will have ending status.
                   1580:     //
                   1581: 
                   1582:     status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
                   1583: 
                   1584:     if (status == STATUS_PENDING) {
                   1585:         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
                   1586:     }
                   1587: 
                   1588:     //
                   1589:     // Check that request completed without error.
                   1590:     //
                   1591: 
                   1592:     if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
                   1593: 
                   1594:         //
                   1595:         // Release the queue if it is frozen.
                   1596:         //
                   1597: 
                   1598:         if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
                   1599:             ScsiClassReleaseQueue(DeviceObject);
                   1600:         }
                   1601: 
                   1602:         //
                   1603:         // Update status and determine if request should be retried.
                   1604:         //
                   1605: 
                   1606:         retry = CdAudioNECInterpretSenseInfo(
                   1607:             DeviceObject,
                   1608:             Srb,
                   1609:             IRP_MJ_SCSI,
                   1610:             0,
                   1611:             MAXIMUM_RETRIES  - retryCount,
                   1612:             &status
                   1613:             );
                   1614: 
                   1615:         if (retry) {
                   1616: 
                   1617:             if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
                   1618:                 ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
                   1619:                 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
                   1620: 
                   1621:                 LARGE_INTEGER delay;
                   1622: 
                   1623:                 //
                   1624:                 // Delay for 2 seconds.
                   1625:                 //
                   1626: 
                   1627:                 delay.LowPart = - ( 10 * 1000 * 1000 * 2 );
                   1628:                 delay.HighPart = -1;
                   1629: 
                   1630: 
                   1631:                 //
                   1632:                 // Stall for a while to let the controller spinup.
                   1633:                 //
                   1634: 
                   1635:                 (VOID) KeDelayExecutionThread(
                   1636:                     KernelMode,
                   1637:                     FALSE,
                   1638:                     &delay
                   1639:                     );
                   1640: 
                   1641:             }
                   1642: 
                   1643: 
                   1644:             //
                   1645:             // If retries are not exhausted then
                   1646:             // retry this operation.
                   1647:             //
                   1648: 
                   1649:             if (retryCount--) {
                   1650:                 goto retry;
                   1651:             }
                   1652:         }
                   1653: 
                   1654:     } else {
                   1655: 
                   1656:         status = STATUS_SUCCESS;
                   1657:     }
                   1658: 
                   1659:     ExFreePool(senseInfoBuffer);
                   1660:     return status;
                   1661: 
                   1662: } // end CdAudioNECSendSrbSynchronous()
                   1663: 
                   1664: 
                   1665: NTSTATUS
                   1666: CdAudioNECDeviceControl(
                   1667:     PDEVICE_OBJECT DeviceObject,
                   1668:     PIRP Irp
                   1669:     )
                   1670: 
                   1671: /*++
                   1672: 
                   1673: Routine Description:
                   1674: 
                   1675:     This routine is called by CdAudioDeviceControl to handle
                   1676:     audio IOCTLs sent to NEC cdrom drives.
                   1677: 
                   1678: Arguments:
                   1679: 
                   1680:     DeviceObject
                   1681:     Irp
                   1682: 
                   1683: Return Value:
                   1684: 
                   1685:     NTSTATUS
                   1686: 
                   1687: --*/
                   1688: 
                   1689: {
                   1690:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   1691:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   1692:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   1693:     SCSI_REQUEST_BLOCK srb;
                   1694:     PNEC_CDB           cdb = (PNEC_CDB)srb.Cdb;
                   1695:     NTSTATUS           status;
                   1696:     ULONG              i,bytesTransfered;
                   1697:     PUCHAR             Toc;
                   1698:     ULONG              retryCount = 0;
                   1699:     ULONG              address;
                   1700:     LARGE_INTEGER delay;
                   1701: 
                   1702: 
                   1703: NECRestart:
                   1704: 
                   1705:     //
                   1706:     // Clear out cdb
                   1707:     //
                   1708: 
                   1709:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   1710: 
                   1711:     //
                   1712:     // What IOCTL do we need to execute?
                   1713:     //
                   1714: 
                   1715:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   1716: 
                   1717:     case IOCTL_CDROM_GET_LAST_SESSION:
                   1718: 
                   1719:         CdDump(( 2,
                   1720:                      "CdAudioNECDeviceControl: IOCTL_CDROM_GET_LAST_SESSION received.\n"
                   1721:                      ));
                   1722: 
                   1723:         if (currentIrpStack->Parameters.Read.Length <
                   1724:             FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
                   1725:             status = STATUS_INFO_LENGTH_MISMATCH;
                   1726:             break;
                   1727:             
                   1728:         }
                   1729: 
                   1730: 
                   1731:         //
                   1732:         // If the cd is playing music then reject this request.
                   1733:         //
                   1734: 
                   1735:         if (CdAudioIsPlayActive(DeviceObject)) {
                   1736:             status = STATUS_DEVICE_BUSY;
                   1737:             break;
                   1738:         }
                   1739: 
                   1740:         //
                   1741:         // Allocate storage to hold TOC from disc
                   1742:         //
                   1743: 
                   1744:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   1745:                                       NEC_CDROM_TOC_SIZE
                   1746:                                      );
                   1747: 
                   1748:         if (Toc==NULL) {
                   1749: 
                   1750:             status = STATUS_INSUFFICIENT_RESOURCES;
                   1751:             goto SetStatusAndReturn;
                   1752: 
                   1753:         }
                   1754: 
                   1755:         //
                   1756:         // Set up defaults
                   1757:         //
                   1758: 
                   1759:         RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
                   1760:         srb.CdbLength = 10;
                   1761: 
                   1762:         //
                   1763:         // Fill in CDB
                   1764:         //
                   1765: 
                   1766:         cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
                   1767:         cdb->NEC_READ_TOC.Type          = NEC_TRANSFER_WHOLE_TOC;
                   1768:         cdb->NEC_READ_TOC.TrackNumber   = NEC_TOC_TYPE_SESSION;        
                   1769:         srb.TimeOutValue      = AUDIO_TIMEOUT;
                   1770:         status = CdAudioNECSendSrbSynchronous(
                   1771:                                      deviceExtension->DeviceObject,
                   1772:                                      &srb,
                   1773:                                      Toc,
                   1774:                                      NEC_CDROM_TOC_SIZE,
                   1775:                                      FALSE
                   1776:                                     );
                   1777: 
                   1778:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   1779: 
                   1780:             CdDump(( 1,
                   1781:                 "CdAudioNECDeviceControl: READ_TOC error (0x%08lX)\n",
                   1782:                  status ));
                   1783: 
                   1784: 
                   1785:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   1786: 
                   1787:                 CdDump(( 1, "CdAudioNECDeviceControl: SRB ERROR (0x%lX)\n",
                   1788:                              srb.SrbStatus ));
                   1789:                 ExFreePool( Toc );
                   1790:                 goto SetStatusAndReturn;
                   1791:             }
                   1792: 
                   1793:         } else {
                   1794: 
                   1795:             status = STATUS_SUCCESS;
                   1796:         }
                   1797: 
                   1798:         //
                   1799:         // Translate data into our format.
                   1800:         //
                   1801: 
                   1802:         bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
                   1803:         Irp->IoStatus.Information = bytesTransfered;
                   1804: 
                   1805:         RtlZeroMemory(cdaudioDataOut, bytesTransfered);
                   1806:         
                   1807:         cdaudioDataOut->Length[0]  = bytesTransfered >> 8;
                   1808:         cdaudioDataOut->Length[1]  = (bytesTransfered & 0xFF);
                   1809: 
                   1810:         //
                   1811:         // Determine if this is a multisession cd.
                   1812:         //
                   1813: 
                   1814:         if (*((ULONG UNALIGNED *) &Toc[14]) == 0) {
                   1815: 
                   1816:             //
                   1817:             // This is a single session disk.  Just return.
                   1818:             //
                   1819: 
                   1820:             ExFreePool(Toc);
                   1821:             break;
                   1822:         }
                   1823: 
                   1824:         //
                   1825:         // Fake the session information.
                   1826:         //
                   1827:         
                   1828:         cdaudioDataOut->FirstTrack = 1;
                   1829:         cdaudioDataOut->LastTrack  = 2;
                   1830: 
                   1831:         CdDump(( 4,
                   1832:                      "CdAudioNECDeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
                   1833:                      cdaudioDataOut->FirstTrack,
                   1834:                      cdaudioDataOut->LastTrack,
                   1835:                      bytesTransfered
                   1836:                      ));
                   1837: 
                   1838: 
                   1839:         //
                   1840:         // Grab Information for the last session.
                   1841:         //
                   1842: 
                   1843:         cdaudioDataOut->TrackData[0].Reserved = 0;
                   1844:         cdaudioDataOut->TrackData[0].Control =
                   1845:             ((Toc[2] & 0x0F) << 4) | (Toc[2] >> 4);
                   1846:         cdaudioDataOut->TrackData[0].TrackNumber = 1;
                   1847: 
                   1848:         cdaudioDataOut->TrackData[0].Reserved1 = 0;
                   1849: 
                   1850:         //
                   1851:         // Convert the minutes, seconds and frames to an absolute block
                   1852:         // address.  The formula comes from NEC.
                   1853:         //
                   1854: 
                   1855:         address = (BCD_TO_DEC(Toc[15]) * 60 + BCD_TO_DEC(Toc[16])) * 75 + BCD_TO_DEC(Toc[17]);
                   1856: 
                   1857:         //
                   1858:         // Put the address in big-endian in the the user's TOC.
                   1859:         //
                   1860: 
                   1861:         cdaudioDataOut->TrackData[0].Address[0] = (UCHAR) (address >> 24);
                   1862:         cdaudioDataOut->TrackData[0].Address[1] = (UCHAR) (address >> 16);
                   1863:         cdaudioDataOut->TrackData[0].Address[2] = (UCHAR) (address >> 8);
                   1864:         cdaudioDataOut->TrackData[0].Address[3] = (UCHAR) address;        
                   1865: 
                   1866:         //
                   1867:         // Free storage now that we've stored it elsewhere
                   1868:         //
                   1869: 
                   1870:         ExFreePool( Toc );
                   1871:         break;
                   1872: 
                   1873:     case IOCTL_CDROM_READ_TOC:
                   1874: 
                   1875:         CdDump(( 2,
                   1876:                      "CdAudioNECDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   1877:                      ));
                   1878: 
                   1879:         //
                   1880:         // If the cd is playing music then reject this request.
                   1881:         //
                   1882: 
                   1883:         if (CdAudioIsPlayActive(DeviceObject)) {
                   1884:             status = STATUS_DEVICE_BUSY;
                   1885:             break;
                   1886:         }
                   1887: 
                   1888:         //
                   1889:         // Allocate storage to hold TOC from disc
                   1890:         //
                   1891: 
                   1892:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   1893:                                       NEC_CDROM_TOC_SIZE
                   1894:                                      );
                   1895: 
                   1896:         if (Toc==NULL) {
                   1897: 
                   1898:             status = STATUS_INSUFFICIENT_RESOURCES;
                   1899:             goto SetStatusAndReturn;
                   1900: 
                   1901:         }
                   1902: 
                   1903:         CdDump(( 4,
                   1904:                      "CdAudioNECDeviceControl: Toc = 0x%lX  cdaudioDataOut = 0x%lX\n",
                   1905:                      Toc, cdaudioDataOut
                   1906:                     ));
                   1907: 
                   1908:         //
                   1909:         // Set up defaults
                   1910:         //
                   1911: 
                   1912:         RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
                   1913:         srb.CdbLength = 10;
                   1914: 
                   1915:         //
                   1916:         // Fill in CDB
                   1917:         //
                   1918: 
                   1919:         cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
                   1920:         cdb->NEC_READ_TOC.Type          = NEC_TRANSFER_WHOLE_TOC;
                   1921:         srb.TimeOutValue      = AUDIO_TIMEOUT;
                   1922:         status = CdAudioNECSendSrbSynchronous(
                   1923:                                      deviceExtension->DeviceObject,
                   1924:                                      &srb,
                   1925:                                      Toc,
                   1926:                                      NEC_CDROM_TOC_SIZE,
                   1927:                                      FALSE
                   1928:                                     );
                   1929: 
                   1930:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   1931: 
                   1932:             CdDump(( 1,
                   1933:                 "CdAudioNECDeviceControl: READ_TOC error (0x%08lX)\n",
                   1934:                  status ));
                   1935: 
                   1936: 
                   1937:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   1938: 
                   1939:                 CdDump(( 1, "CdAudioNECDeviceControl: SRB ERROR (0x%lX)\n",
                   1940:                              srb.SrbStatus ));
                   1941:                 ExFreePool( Toc );
                   1942:                 goto SetStatusAndReturn;
                   1943:             }
                   1944: 
                   1945:         } else {
                   1946: 
                   1947:             status = STATUS_SUCCESS;
                   1948:         }
                   1949: 
                   1950:         //
                   1951:         // Translate data into our format.
                   1952:         //
                   1953: 
                   1954:         bytesTransfered =
                   1955:             currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
                   1956:             sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
                   1957:         Irp->IoStatus.Information = bytesTransfered;
                   1958: 
                   1959:         cdaudioDataOut->Length[0]  = bytesTransfered >> 8;
                   1960:         cdaudioDataOut->Length[1]  = (bytesTransfered & 0xFF);
                   1961:         cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[9]);
                   1962:         cdaudioDataOut->LastTrack  = BCD_TO_DEC(Toc[19]);
                   1963: 
                   1964:         CdDump(( 4,
                   1965:                      "CdAudioNECDeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
                   1966:                      cdaudioDataOut->FirstTrack,
                   1967:                      cdaudioDataOut->LastTrack,
                   1968:                      bytesTransfered
                   1969:                      ));
                   1970: 
                   1971: 
                   1972:         for( i=0;
                   1973:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   1974:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   1975:              i++
                   1976:             ) {
                   1977: 
                   1978:             //
                   1979:             // Grab Information for each track
                   1980:             //
                   1981: 
                   1982:             cdaudioDataOut->TrackData[i].Reserved = 0;
                   1983:             cdaudioDataOut->TrackData[i].Control =
                   1984:                 ((Toc[(i*10)+32] & 0x0F) << 4) | (Toc[(i*10)+32] >> 4);
                   1985:             cdaudioDataOut->TrackData[i].TrackNumber =
                   1986:                 (i + cdaudioDataOut->FirstTrack);
                   1987: 
                   1988:             cdaudioDataOut->TrackData[i].Reserved1 = 0;
                   1989:             cdaudioDataOut->TrackData[i].Address[0] = 0;
                   1990:             cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC((Toc[(i*10)+39]));
                   1991:             cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC((Toc[(i*10)+40]));
                   1992:             cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC((Toc[(i*10)+41]));
                   1993: 
                   1994:             CdDump(( 4,
                   1995:                          "CdAudioNECDeviceControl: Track %d  %d:%d:%d\n",
                   1996:                          cdaudioDataOut->TrackData[i].TrackNumber,
                   1997:                          cdaudioDataOut->TrackData[i].Address[1],
                   1998:                          cdaudioDataOut->TrackData[i].Address[2],
                   1999:                          cdaudioDataOut->TrackData[i].Address[3]
                   2000:                        ));
                   2001: 
                   2002: 
                   2003: 
                   2004:         }
                   2005: 
                   2006:         //
                   2007:         // Fake "lead out track" info
                   2008:         //
                   2009: 
                   2010:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   2011:         cdaudioDataOut->TrackData[i].Control     = 0x10;
                   2012:         cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
                   2013:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   2014:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   2015:         cdaudioDataOut->TrackData[i].Address[1]  = BCD_TO_DEC(Toc[29]);
                   2016:         cdaudioDataOut->TrackData[i].Address[2]  = BCD_TO_DEC(Toc[30]);
                   2017:         cdaudioDataOut->TrackData[i].Address[3]  = BCD_TO_DEC(Toc[31]);
                   2018: 
                   2019:         CdDump(( 4,
                   2020:                      "CdAudioNECDeviceControl: Track %d  %d:%d:%d\n",
                   2021:                      cdaudioDataOut->TrackData[i].TrackNumber,
                   2022:                      cdaudioDataOut->TrackData[i].Address[1],
                   2023:                      cdaudioDataOut->TrackData[i].Address[2],
                   2024:                      cdaudioDataOut->TrackData[i].Address[3]
                   2025:                    ));
                   2026: 
                   2027:         //
                   2028:         // Free storage now that we've stored it elsewhere
                   2029:         //
                   2030: 
                   2031:         ExFreePool( Toc );
                   2032:         break;
                   2033: 
                   2034:     case IOCTL_CDROM_STOP_AUDIO:
                   2035: 
                   2036:         deviceExtension->PlayActive = FALSE;
                   2037: 
                   2038:         //
                   2039:         // Same as scsi-2 spec, so just send to default driver
                   2040:         //
                   2041: 
                   2042:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   2043:         break;
                   2044: 
                   2045:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   2046:         {
                   2047: 
                   2048:         PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   2049: 
                   2050:         CdDump(( 3,
                   2051:             "CdAudioNECDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
                   2052:             ));
                   2053: 
                   2054:         //
                   2055:         // First, seek to Starting MSF and enter play mode.
                   2056:         //
                   2057: 
                   2058:         srb.CdbLength                 = 10;
                   2059:         srb.TimeOutValue              = AUDIO_TIMEOUT;
                   2060:         cdb->NEC_PLAY_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
                   2061:         cdb->NEC_PLAY_AUDIO.PlayMode      = NEC_ENTER_PLAY_MODE;
                   2062:         cdb->NEC_PLAY_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->StartingM);
                   2063:         cdb->NEC_PLAY_AUDIO.Second        = DEC_TO_BCD(inputBuffer->StartingS);
                   2064:         cdb->NEC_PLAY_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->StartingF);
                   2065:         cdb->NEC_PLAY_AUDIO.Control       = NEC_TYPE_ATIME;
                   2066: 
                   2067:         CdDump(( 3,
                   2068:                      "CdAudioNECDeviceControl: play start MSF is BCD(%x:%x:%x)\n",
                   2069:                      cdb->NEC_PLAY_AUDIO.Minute,
                   2070:                      cdb->NEC_PLAY_AUDIO.Second,
                   2071:                      cdb->NEC_PLAY_AUDIO.Frame
                   2072:                    ));
                   2073: 
                   2074: 
                   2075:         status = CdAudioNECSendSrbSynchronous(deviceExtension->DeviceObject,
                   2076:                                               &srb,
                   2077:                                               NULL,
                   2078:                                               0,
                   2079:                                               FALSE
                   2080:                                              );
                   2081:         if (NT_SUCCESS(status)) {
                   2082: 
                   2083:             //
                   2084:             // Indicate the play actition is active.
                   2085:             //
                   2086: 
                   2087:             deviceExtension->PlayActive = TRUE;
                   2088: 
                   2089:             //
                   2090:             // Now, set the termination point for the play operation
                   2091:             //
                   2092: 
                   2093:             RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2094:             cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
                   2095:             cdb->NEC_PLAY_AUDIO.PlayMode      = NEC_PLAY_STEREO;
                   2096:             cdb->NEC_PLAY_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->EndingM);
                   2097:             cdb->NEC_PLAY_AUDIO.Second        = DEC_TO_BCD(inputBuffer->EndingS);
                   2098:             cdb->NEC_PLAY_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->EndingF);
                   2099:             cdb->NEC_PLAY_AUDIO.Control       = NEC_TYPE_ATIME;
                   2100: 
                   2101:             CdDump(( 3,
                   2102:                          "CdAudioNECDeviceControl: play end MSF is BCD(%x:%x:%x)\n",
                   2103:                          cdb->NEC_PLAY_AUDIO.Minute,
                   2104:                          cdb->NEC_PLAY_AUDIO.Second,
                   2105:                          cdb->NEC_PLAY_AUDIO.Frame
                   2106:                        ));
                   2107: 
                   2108:             status = CdAudioNECSendSrbSynchronous(
                   2109:                                          deviceExtension->DeviceObject,
                   2110:                                          &srb,
                   2111:                                          NULL,
                   2112:                                          0,
                   2113:                                          FALSE
                   2114:                                         );
                   2115: 
                   2116: 
                   2117:         }
                   2118:         }
                   2119:         break;
                   2120: 
                   2121:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   2122:         {
                   2123: 
                   2124:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   2125: 
                   2126:         CdDump(( 3,
                   2127:             "CdAudioNECDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   2128:              ));
                   2129: 
                   2130:         //
                   2131:         // seek to MSF and enter pause (still) mode.
                   2132:         //
                   2133: 
                   2134:         srb.CdbLength                 = 10;
                   2135:         srb.TimeOutValue              = AUDIO_TIMEOUT;
                   2136:         cdb->NEC_SEEK_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
                   2137:         cdb->NEC_SEEK_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->M);
                   2138:         cdb->NEC_SEEK_AUDIO.Second        = DEC_TO_BCD(inputBuffer->S);
                   2139:         cdb->NEC_SEEK_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->F);
                   2140:         cdb->NEC_SEEK_AUDIO.Control       = NEC_TYPE_ATIME;
                   2141:         CdDump(( 4,
                   2142:                      "CdAudioNECDeviceControl: seek MSF is %d:%d:%d\n",
                   2143:                      cdb->NEC_SEEK_AUDIO.Minute,
                   2144:                      cdb->NEC_SEEK_AUDIO.Second,
                   2145:                      cdb->NEC_SEEK_AUDIO.Frame
                   2146:                    ));
                   2147: 
                   2148:         status = CdAudioNECSendSrbSynchronous(
                   2149:                                      deviceExtension->DeviceObject,
                   2150:                                      &srb,
                   2151:                                      NULL,
                   2152:                                      0,
                   2153:                                      FALSE
                   2154:                                     );
                   2155: 
                   2156:         }
                   2157:         break;
                   2158: 
                   2159:     case IOCTL_CDROM_PAUSE_AUDIO:
                   2160: 
                   2161:         CdDump(( 3,
                   2162:             "CdAudioNECDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
                   2163:             ));
                   2164: 
                   2165:         deviceExtension->PlayActive = FALSE;
                   2166: 
                   2167:         //
                   2168:         // Enter pause (still ) mode
                   2169:         //
                   2170: 
                   2171:         srb.CdbLength                  = 10;
                   2172:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   2173:         cdb->NEC_PAUSE_AUDIO.OperationCode = NEC_STILL_CODE;
                   2174:         status = CdAudioNECSendSrbSynchronous(
                   2175:                                      deviceExtension->DeviceObject,
                   2176:                                      &srb,
                   2177:                                      NULL,
                   2178:                                      0,
                   2179:                                      FALSE
                   2180:                                     );
                   2181: 
                   2182:         break;
                   2183: 
                   2184:     case IOCTL_CDROM_RESUME_AUDIO:
                   2185: 
                   2186:         CdDump(( 3,
                   2187:             "CdAudioNECDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
                   2188:             ));
                   2189: 
                   2190:         //
                   2191:         // Resume play
                   2192:         //
                   2193: 
                   2194:         srb.CdbLength                 = 10;
                   2195:         srb.TimeOutValue              = AUDIO_TIMEOUT;
                   2196:         cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
                   2197:         cdb->NEC_PLAY_AUDIO.PlayMode      = NEC_PLAY_STEREO;
                   2198:         cdb->NEC_PLAY_AUDIO.Control       = NEC_TYPE_NO_CHANGE;
                   2199:         status = CdAudioNECSendSrbSynchronous(
                   2200:                                      deviceExtension->DeviceObject,
                   2201:                                      &srb,
                   2202:                                      NULL,
                   2203:                                      0,
                   2204:                                      FALSE
                   2205:                                     );
                   2206:         break;
                   2207: 
                   2208:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   2209:         {
                   2210: 
                   2211:         PSUB_Q_CURRENT_POSITION userPtr =
                   2212:             Irp->AssociatedIrp.SystemBuffer;
                   2213:         PUCHAR SubQPtr =
                   2214:             ExAllocatePool( NonPagedPoolCacheAligned,
                   2215:                             NEC_Q_CHANNEL_TRANSFER_SIZE
                   2216:                            );
                   2217: 
                   2218:         CdDump(( 5,
                   2219:             "CdAudioNECDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   2220:             ));
                   2221: 
                   2222:         if (SubQPtr==NULL) {
                   2223: 
                   2224:             CdDump(( 1,
                   2225:                 "CdAudioNECDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   2226:                 ));
                   2227: 
                   2228:             status = STATUS_INSUFFICIENT_RESOURCES;
                   2229:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   2230:             goto SetStatusAndReturn;
                   2231: 
                   2232:         }
                   2233: 
                   2234:         RtlZeroMemory( SubQPtr, NEC_Q_CHANNEL_TRANSFER_SIZE );
                   2235: 
                   2236:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   2237:              IOCTL_CDROM_CURRENT_POSITION) {
                   2238: 
                   2239:             CdDump(( 1,
                   2240:                 "CdAudioNECDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
                   2241:                 ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   2242:                 ));
                   2243: 
                   2244:             ExFreePool( SubQPtr );
                   2245:             status = STATUS_UNSUCCESSFUL;
                   2246:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   2247:             goto SetStatusAndReturn;
                   2248:         }
                   2249: 
                   2250: NECSeek:
                   2251: 
                   2252:         //
                   2253:         // Set up to read Q Channel
                   2254:         //
                   2255: 
                   2256:         srb.CdbLength                     = 10;
                   2257:         srb.TimeOutValue                  = AUDIO_TIMEOUT;
                   2258:         cdb->NEC_READ_Q_CHANNEL.OperationCode = NEC_READ_SUB_Q_CHANNEL_CODE;
                   2259:         cdb->NEC_READ_Q_CHANNEL.TransferSize  = NEC_Q_CHANNEL_TRANSFER_SIZE;  // Transfer Length
                   2260:         CdDump(( 4, "CdAudioNECDeviceControl: cdb = 0x%lx  srb = 0x%x  SubQPtr = 0x%lx\n",
                   2261:                        cdb,
                   2262:                        &srb,
                   2263:                        SubQPtr
                   2264:                       ));
                   2265: #if DBG
                   2266:         if (CdAudioDebug>5) {
                   2267: 
                   2268:             DbgBreakPoint();
                   2269: 
                   2270:         }
                   2271: #endif
                   2272:         status = CdAudioNECSendSrbSynchronous(
                   2273:                                      deviceExtension->DeviceObject,
                   2274:                                      &srb,
                   2275:                                      SubQPtr,
                   2276:                                      NEC_Q_CHANNEL_TRANSFER_SIZE,
                   2277:                                      FALSE
                   2278:                                     );
                   2279:         CdDump(( 4, "CdAudioNECDeviceControl: READ_Q_CHANNEL, status is 0x%lX\n",
                   2280:                        status
                   2281:                      ));
                   2282: 
                   2283:         if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
                   2284: 
                   2285:             userPtr->Header.Reserved = 0;
                   2286:             if (SubQPtr[0]==0x00)
                   2287:                 userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
                   2288:             else if (SubQPtr[0]==0x01) {
                   2289: 
                   2290:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   2291:                 deviceExtension->PlayActive = FALSE;
                   2292:             } else if (SubQPtr[0]==0x02) {
                   2293:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   2294:                 deviceExtension->PlayActive = FALSE;
                   2295:             } else if (SubQPtr[0]==0x03) {
                   2296: 
                   2297:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
                   2298:                 deviceExtension->PlayActive = FALSE;
                   2299: 
                   2300:             } else {
                   2301:                 deviceExtension->PlayActive = FALSE;
                   2302: 
                   2303:             }
                   2304: 
                   2305:             userPtr->Header.DataLength[0] = 0;
                   2306:             userPtr->Header.DataLength[0] = 12;
                   2307: 
                   2308:             userPtr->FormatCode = 0x01;
                   2309:             userPtr->Control = SubQPtr[1] & 0x0F;
                   2310:             userPtr->ADR     = 0;
                   2311:             userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
                   2312:             userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
                   2313:             userPtr->AbsoluteAddress[0] = 0;
                   2314:             userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
                   2315:             userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
                   2316:             userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
                   2317:             userPtr->TrackRelativeAddress[0] = 0;
                   2318:             userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
                   2319:             userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
                   2320:             userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
                   2321:             Irp->IoStatus.Information = 16;
                   2322:             CdDump(( 5,
                   2323:                            "CdAudioNECDeviceControl: <SubQPtr> Status = 0x%lx, [%x %x:%x]  (%x:%x:%x)\n",
                   2324:                            SubQPtr[0],
                   2325:                            SubQPtr[2],
                   2326:                            SubQPtr[4],
                   2327:                            SubQPtr[5],
                   2328:                            SubQPtr[7],
                   2329:                            SubQPtr[8],
                   2330:                            SubQPtr[9]
                   2331:                           ));
                   2332:             CdDump(( 5,
                   2333:                            "CdAudioNECDeviceControl: <userPtr> Status = 0x%lx, [%d %d:%d]  (%d:%d:%d)\n",
                   2334:                            userPtr->Header.AudioStatus,
                   2335:                            userPtr->TrackNumber,
                   2336:                            userPtr->TrackRelativeAddress[1],
                   2337:                            userPtr->TrackRelativeAddress[2],
                   2338:                            userPtr->AbsoluteAddress[1],
                   2339:                            userPtr->AbsoluteAddress[2],
                   2340:                            userPtr->AbsoluteAddress[3]
                   2341:                           ));
                   2342: 
                   2343:             //
                   2344:             // Sometimes the NEC will return a bogus value for track number.
                   2345:             // if this occurs just retry.
                   2346:             //
                   2347: 
                   2348:             if (userPtr->TrackNumber > MAXIMUM_NUMBER_TRACKS) {
                   2349: 
                   2350:                 //
                   2351:                 // Delay for .5 seconds.
                   2352:                 //
                   2353: 
                   2354:                 delay = LiFromLong( - 10 * 1000 * 100 * 5 );
                   2355: 
                   2356:                 //
                   2357:                 // Stall for a while to let the controller spinup.
                   2358:                 //
                   2359: 
                   2360:                 KeDelayExecutionThread(KernelMode,
                   2361:                                        FALSE,
                   2362:                                        &delay);
                   2363: 
                   2364:                 if (retryCount++ < MAXIMUM_RETRIES) {
                   2365:                     goto NECSeek;
                   2366:                 } else {
                   2367:                     status = STATUS_DEVICE_PROTOCOL_ERROR;
                   2368:                 }
                   2369: 
                   2370:             } else {
                   2371:                 status = STATUS_SUCCESS;
                   2372:             }
                   2373: 
                   2374:         } else {
                   2375: 
                   2376:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   2377:             CdDump(( 1,
                   2378:                 "CdAudioNECDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
                   2379:                 status
                   2380:                 ));
                   2381: 
                   2382:         }
                   2383: 
                   2384:         ExFreePool( SubQPtr );
                   2385: 
                   2386:         }
                   2387:         break;
                   2388: 
                   2389:     case IOCTL_CDROM_EJECT_MEDIA:
                   2390: 
                   2391:         CdDump(( 3,
                   2392:             "CdAudioNECDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   2393:             ));
                   2394: 
                   2395:         deviceExtension->PlayActive = FALSE;
                   2396: 
                   2397:         //
                   2398:         // Set up to read Q Channel
                   2399:         //
                   2400: 
                   2401:         srb.CdbLength            = 10;
                   2402:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   2403:         cdb->NEC_EJECT.OperationCode = NEC_EJECT_CODE;
                   2404:         status = CdAudioNECSendSrbSynchronous(
                   2405:                                      deviceExtension->DeviceObject,
                   2406:                                      &srb,
                   2407:                                      NULL,
                   2408:                                      0,
                   2409:                                      FALSE
                   2410:                                     );
                   2411: 
                   2412:         CdDump(( 3,
                   2413:                      "CdAudioNECDeviceControl: invalidating cached TOC!\n"
                   2414:                      ));
                   2415:         break;
                   2416: 
                   2417:     case IOCTL_CDROM_GET_CONTROL:
                   2418:     case IOCTL_CDROM_GET_VOLUME:
                   2419:     case IOCTL_CDROM_SET_VOLUME:
                   2420: 
                   2421:         CdDump(( 3, "CdAudioNECDeviceControl: Not Supported yet.\n" ));
                   2422:         status = STATUS_INVALID_DEVICE_REQUEST;
                   2423:         break;
                   2424: 
                   2425:     case IOCTL_CDROM_CHECK_VERIFY:
                   2426: 
                   2427:         //
                   2428:         // Update the play active flag.
                   2429:         //
                   2430: 
                   2431:         CdAudioIsPlayActive(DeviceObject);
                   2432: 
                   2433:         //
                   2434:         // Fall through and pass the request to the next driver.
                   2435:         //
                   2436: 
                   2437:     default:
                   2438: 
                   2439:         CdDump(( 5,
                   2440:                        "CdAudioNECDeviceControl: Unsupported device IOCTL (0x%lX)\n",
                   2441:                        currentIrpStack->Parameters.DeviceIoControl.IoControlCode
                   2442:                        ));
                   2443:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   2444:         break;
                   2445: 
                   2446:     } // end switch( IOCTL )
                   2447: 
                   2448: SetStatusAndReturn:
                   2449: 
                   2450:     //
                   2451:     // set status code and return
                   2452:     //
                   2453: 
                   2454:     if (status == STATUS_VERIFY_REQUIRED) {
                   2455: 
                   2456: 
                   2457:         //
                   2458:         // If the status is verified required and the this request
                   2459:         // should bypass verify required then retry the request.
                   2460:         //
                   2461: 
                   2462:         if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
                   2463: 
                   2464:             status = STATUS_IO_DEVICE_ERROR;
                   2465:             goto NECRestart;
                   2466: 
                   2467:         }
                   2468: 
                   2469:         IoSetHardErrorOrVerifyDevice( Irp,
                   2470:                                       deviceExtension->TargetDeviceObject
                   2471:                                      );
                   2472: 
                   2473:         Irp->IoStatus.Information = 0;
                   2474:     }
                   2475: 
                   2476:     Irp->IoStatus.Status = status;
                   2477:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   2478:     return status;
                   2479: 
                   2480: }
                   2481: 
                   2482: 
                   2483: NTSTATUS
                   2484: CdAudioPioneerDeviceControl(
                   2485:     PDEVICE_OBJECT DeviceObject,
                   2486:     PIRP Irp
                   2487:     )
                   2488: 
                   2489: /*++
                   2490: 
                   2491: Routine Description:
                   2492: 
                   2493:     This routine is called by CdAudioDeviceControl to handle
                   2494:     audio IOCTLs sent to PIONEER DRM-6xx cdrom drives.
                   2495: 
                   2496: Arguments:
                   2497: 
                   2498:     DeviceObject
                   2499:     Irp
                   2500: 
                   2501: Return Value:
                   2502: 
                   2503:     NTSTATUS
                   2504: 
                   2505: --*/
                   2506: 
                   2507: {
                   2508:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   2509:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   2510:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   2511:     SCSI_REQUEST_BLOCK srb;
                   2512:     PPNR_CDB           cdb = (PPNR_CDB)srb.Cdb;
                   2513:     NTSTATUS           status;
                   2514:     ULONG              i,bytesTransfered,retry;
                   2515:     PUCHAR             Toc;
                   2516: 
                   2517: PioneerRestart:
                   2518: 
                   2519:     //
                   2520:     // Clear out cdb
                   2521:     //
                   2522: 
                   2523:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2524: 
                   2525:     //
                   2526:     // What IOCTL do we need to execute?
                   2527:     //
                   2528: 
                   2529:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   2530: 
                   2531:     case IOCTL_CDROM_READ_TOC:
                   2532:         CdDump(( 3,
                   2533:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   2534:                      ));
                   2535: 
                   2536:         //
                   2537:         // If the cd is playing music then reject this request.
                   2538:         //
                   2539: 
                   2540:         if (CdAudioIsPlayActive(DeviceObject)) {
                   2541:             status = STATUS_DEVICE_BUSY;
                   2542:             break;
                   2543:         }
                   2544: 
                   2545:         //
                   2546:         // Allocate storage to hold TOC from disc
                   2547:         //
                   2548: 
                   2549:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   2550:                                       CDROM_TOC_SIZE
                   2551:                                      );
                   2552: 
                   2553:         if (Toc==NULL) {
                   2554: 
                   2555:             status = STATUS_INSUFFICIENT_RESOURCES;
                   2556:             goto SetStatusAndReturn;
                   2557: 
                   2558:         }
                   2559: 
                   2560:         //
                   2561:         // Set up defaults
                   2562:         //
                   2563: 
                   2564:         RtlZeroMemory( Toc, CDROM_TOC_SIZE );
                   2565: 
                   2566:         //
                   2567:         // mount this disc (via START/STOP unit), which is
                   2568:         // necessary since we don't know which is the
                   2569:         // currently loaded disc.
                   2570:         //
                   2571: 
                   2572:         cdb->PNR_START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
                   2573:         cdb->PNR_START_STOP.Start         = 1;
                   2574:         srb.CdbLength = 6;
                   2575:         srb.TimeOutValue = AUDIO_TIMEOUT;
                   2576:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2577:                                      &srb,
                   2578:                                      NULL,
                   2579:                                      0,
                   2580:                                      FALSE
                   2581:                                     );
                   2582: 
                   2583:         if (!NT_SUCCESS(status)) {
                   2584: 
                   2585:             CdDump(( 1,
                   2586:                 "CdAudioPioneerDeviceControl: Start Unit failed (0x%lx)\n",
                   2587:                 status ));
                   2588:             ExFreePool( Toc );
                   2589:             goto SetStatusAndReturn;
                   2590: 
                   2591:         }
                   2592: 
                   2593:         //
                   2594:         // Get first and last tracks
                   2595:         //
                   2596: 
                   2597:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2598:         srb.CdbLength = 10;
                   2599:         cdb->PNR_READ_TOC.OperationCode     = PIONEER_READ_TOC_CODE;
                   2600:         cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
                   2601:         cdb->PNR_READ_TOC.Type              = PIONEER_READ_FIRST_AND_LAST;
                   2602:         srb.TimeOutValue                    = AUDIO_TIMEOUT;
                   2603:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2604:                                      &srb,
                   2605:                                      Toc,
                   2606:                                      PIONEER_TRANSFER_SIZE,
                   2607:                                      FALSE
                   2608:                                     );
                   2609: 
                   2610:         if (!NT_SUCCESS(status)) {
                   2611: 
                   2612:             CdDump(( 1,
                   2613:                 "CdAudioPioneerDeviceControl: ReadTOC, First/Last Tracks failed (0x%lx)\n",
                   2614:                 status ));
                   2615:             ExFreePool( Toc );
                   2616:             goto SetStatusAndReturn;
                   2617: 
                   2618:         }
                   2619: 
                   2620:         cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[0]);
                   2621:         cdaudioDataOut->LastTrack  = BCD_TO_DEC(Toc[1]);
                   2622: 
                   2623:         //
                   2624:         // Now, get info about each track
                   2625:         //
                   2626: 
                   2627:         for( i=0;
                   2628:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   2629:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   2630:              i++
                   2631:             ) {
                   2632: 
                   2633:             //
                   2634:             // Get TOC info for this track
                   2635:             //
                   2636: 
                   2637:             RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2638:             cdb->PNR_READ_TOC.OperationCode     = PIONEER_READ_TOC_CODE;
                   2639:             cdb->PNR_READ_TOC.TrackNumber       = DEC_TO_BCD((i+cdaudioDataOut->FirstTrack)); // track
                   2640:             cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
                   2641:             cdb->PNR_READ_TOC.Type              = PIONEER_READ_TRACK_INFO;
                   2642:             srb.TimeOutValue                    = AUDIO_TIMEOUT;
                   2643:             status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2644:                                          &srb,
                   2645:                                          Toc,
                   2646:                                          PIONEER_TRANSFER_SIZE,
                   2647:                                          FALSE
                   2648:                                         );
                   2649: 
                   2650:             if (!NT_SUCCESS(status)) {
                   2651: 
                   2652:                 CdDump(( 1,
                   2653:                     "CdAudioPioneerDeviceControl: ReadTOC, Track #%d, failed (0x%lx)\n",
                   2654:                     i+cdaudioDataOut->FirstTrack,
                   2655:                     status ));
                   2656:                 ExFreePool( Toc );
                   2657:                 goto SetStatusAndReturn;
                   2658: 
                   2659:             }
                   2660: 
                   2661:             cdaudioDataOut->TrackData[i].Reserved = 0;
                   2662:             cdaudioDataOut->TrackData[i].Control  = Toc[0];
                   2663:             cdaudioDataOut->TrackData[i].TrackNumber =
                   2664:                 (i + cdaudioDataOut->FirstTrack);
                   2665:             cdaudioDataOut->TrackData[i].Reserved1 = 0;
                   2666:             cdaudioDataOut->TrackData[i].Address[0]=0;
                   2667:             cdaudioDataOut->TrackData[i].Address[1]=BCD_TO_DEC(Toc[1]);
                   2668:             cdaudioDataOut->TrackData[i].Address[2]=BCD_TO_DEC(Toc[2]);
                   2669:             cdaudioDataOut->TrackData[i].Address[3]=BCD_TO_DEC(Toc[3]);
                   2670: 
                   2671:         }
                   2672: 
                   2673:         //
                   2674:         // Get info for lead out track
                   2675:         //
                   2676: 
                   2677:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2678:         cdb->PNR_READ_TOC.OperationCode     = PIONEER_READ_TOC_CODE;
                   2679:         cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
                   2680:         cdb->PNR_READ_TOC.Type              = PIONEER_READ_LEAD_OUT_INFO;
                   2681:         srb.TimeOutValue                    = AUDIO_TIMEOUT;
                   2682:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2683:                                      &srb,
                   2684:                                      Toc,
                   2685:                                      PIONEER_TRANSFER_SIZE,
                   2686:                                      FALSE
                   2687:                                     );
                   2688: 
                   2689:         if (!NT_SUCCESS(status)) {
                   2690: 
                   2691:             CdDump(( 1,
                   2692:                 "CdAudioPioneerDeviceControl: ReadTOC, read LeadOutTrack failed (0x%lx)\n",
                   2693:                 status ));
                   2694:             ExFreePool( Toc );
                   2695:             goto SetStatusAndReturn;
                   2696: 
                   2697:         }
                   2698: 
                   2699:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   2700:         cdaudioDataOut->TrackData[i].Control     = 0x10;
                   2701:         cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
                   2702:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   2703:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   2704:         cdaudioDataOut->TrackData[i].Address[1]  = BCD_TO_DEC(Toc[0]);
                   2705:         cdaudioDataOut->TrackData[i].Address[2]  = BCD_TO_DEC(Toc[1]);
                   2706:         cdaudioDataOut->TrackData[i].Address[3]  = BCD_TO_DEC(Toc[2]);
                   2707: 
                   2708:         //
                   2709:         // Set size of information transfered to
                   2710:         // max size possible for CDROM Table of Contents
                   2711:         //
                   2712: 
                   2713:         Irp->IoStatus.Information  = CDROM_TOC_SIZE;
                   2714:         cdaudioDataOut->Length[0]  = CDROM_TOC_SIZE >> 8;
                   2715:         cdaudioDataOut->Length[1]  = CDROM_TOC_SIZE & 0xFF;
                   2716:         break;
                   2717: 
                   2718:     case IOCTL_CDROM_STOP_AUDIO:
                   2719: 
                   2720:         CdDump(( 3,
                   2721:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
                   2722:                      ));
                   2723: 
                   2724: 
                   2725:         deviceExtension->PlayActive = FALSE;
                   2726: 
                   2727:         //
                   2728:         // Same as scsi-2 spec, so just send to default driver
                   2729:         //
                   2730: 
                   2731:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   2732:         break;
                   2733: 
                   2734:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   2735:         {
                   2736: 
                   2737:         PCDROM_PLAY_AUDIO_MSF inputBuffer =
                   2738:             Irp->AssociatedIrp.SystemBuffer;
                   2739: 
                   2740:         CdDump(( 3,
                   2741:                  "CdAudioPioneerDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
                   2742:                 ));
                   2743: 
                   2744: 
                   2745:         //
                   2746:         // First, set play END point for the play operation
                   2747:         //
                   2748: 
                   2749:         retry = 5;
                   2750:         do {
                   2751: 
                   2752:             srb.CdbLength                     = 10;
                   2753:             srb.TimeOutValue                  = AUDIO_TIMEOUT;
                   2754:             cdb->PNR_SEEK_AUDIO.OperationCode = PIONEER_AUDIO_TRACK_SEARCH_CODE;
                   2755:             cdb->PNR_SEEK_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->StartingM);
                   2756:             cdb->PNR_SEEK_AUDIO.Second        = DEC_TO_BCD(inputBuffer->StartingS);
                   2757:             cdb->PNR_SEEK_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->StartingF);
                   2758:             cdb->PNR_SEEK_AUDIO.Type          = PIONEER_TYPE_ATIME;
                   2759:             status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2760:                                          &srb,
                   2761:                                          NULL,
                   2762:                                          0,
                   2763:                                          FALSE
                   2764:                                         );
                   2765: 
                   2766:         } while( !NT_SUCCESS(status) && ((retry--)>0) );
                   2767: 
                   2768:         if (NT_SUCCESS(status)) {
                   2769: 
                   2770:             //
                   2771:             // Now, set play start position and start playing.
                   2772:             //
                   2773: 
                   2774:             RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   2775:             retry = 5;
                   2776:             do {
                   2777:                 srb.CdbLength = 10;
                   2778:                 srb.TimeOutValue = AUDIO_TIMEOUT;
                   2779:                 cdb->PNR_PLAY_AUDIO.OperationCode = PIONEER_PLAY_AUDIO_CODE;
                   2780:                 cdb->PNR_PLAY_AUDIO.StopAddr      = 1;
                   2781:                 cdb->PNR_PLAY_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->EndingM);
                   2782:                 cdb->PNR_PLAY_AUDIO.Second        = DEC_TO_BCD(inputBuffer->EndingS);
                   2783:                 cdb->PNR_PLAY_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->EndingF);
                   2784:                 cdb->PNR_PLAY_AUDIO.Type          = PIONEER_TYPE_ATIME;
                   2785:                 status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2786:                                              &srb,
                   2787:                                              NULL,
                   2788:                                              0,
                   2789:                                              FALSE
                   2790:                                             );
                   2791:             } while( !NT_SUCCESS(status) && ((retry--)>0) );
                   2792: 
                   2793:             if (NT_SUCCESS(status)) {
                   2794: 
                   2795:                 //
                   2796:                 // Indicate the play actition is active.
                   2797:                 //
                   2798: 
                   2799:                 deviceExtension->PlayActive = TRUE;
                   2800: 
                   2801: 
                   2802:             }
                   2803: 
                   2804: #if DBG
                   2805:             if (!NT_SUCCESS(status)) {
                   2806:                 CdDump(( 1,
                   2807:                          "CdAudioPioneerDeviceControl: PLAY_AUDIO_MSF(stop) failed 0x%lx\n",
                   2808:                          status
                   2809:                         ));
                   2810: 
                   2811:                 CdDump(( 3,
                   2812:                          "CdAudioPioneerDeviceControl: cdb = 0x%lx, srb = 0x%lx\n",
                   2813:                          cdb, &srb
                   2814:                         ));
                   2815: 
                   2816:                 if (CdAudioDebug>2)
                   2817:                     DbgBreakPoint();
                   2818:             }
                   2819: #endif
                   2820:         }
                   2821: #if DBG
                   2822:         else {
                   2823: 
                   2824:             CdDump(( 1,
                   2825:                      "CdAudioPioneerDeviceControl: PLAY_AUDIO_MSF(start) failed 0x%lx\n",
                   2826:                      status
                   2827:                     ));
                   2828:             CdDump(( 3,
                   2829:                      "CdAudioPioneerDeviceControl: cdb = 0x%lx, srb = 0x%lx\n",
                   2830:                      cdb, &srb
                   2831:                     ));
                   2832: 
                   2833:             if (CdAudioDebug>2)
                   2834:                 DbgBreakPoint();
                   2835: 
                   2836: 
                   2837:         }
                   2838: #endif
                   2839:         }
                   2840:         break;
                   2841: 
                   2842:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   2843:         {
                   2844: 
                   2845:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   2846: 
                   2847:         CdDump(( 1,
                   2848:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   2849:                      ));
                   2850: 
                   2851: 
                   2852:         retry = 5;
                   2853:         do {
                   2854: 
                   2855:             //
                   2856:             // seek to MSF and enter pause (still) mode.
                   2857:             //
                   2858: 
                   2859:             srb.CdbLength                     = 10;
                   2860:             srb.TimeOutValue                  = AUDIO_TIMEOUT;
                   2861:             cdb->PNR_SEEK_AUDIO.OperationCode = PIONEER_AUDIO_TRACK_SEARCH_CODE;
                   2862:             cdb->PNR_SEEK_AUDIO.Minute        = DEC_TO_BCD(inputBuffer->M);
                   2863:             cdb->PNR_SEEK_AUDIO.Second        = DEC_TO_BCD(inputBuffer->S);
                   2864:             cdb->PNR_SEEK_AUDIO.Frame         = DEC_TO_BCD(inputBuffer->F);
                   2865:             cdb->PNR_SEEK_AUDIO.Type          = PIONEER_TYPE_ATIME;
                   2866:             CdDump(( 3,
                   2867:                      "CdAudioPioneerDeviceControl: Seek to MSF %d:%d:%d, BCD(%x:%x:%x)\n",
                   2868:                      inputBuffer->M,
                   2869:                      inputBuffer->S,
                   2870:                      inputBuffer->F,
                   2871:                      cdb->PNR_SEEK_AUDIO.Minute,
                   2872:                      cdb->PNR_SEEK_AUDIO.Second,
                   2873:                      cdb->PNR_SEEK_AUDIO.Frame
                   2874:                     ));
                   2875:             CdDump(( 3,
                   2876:                      "CdAudioPioneerDeviceControl: Seek to MSF, cdb is 0x%x, srb is 0x%x\n",
                   2877:                       cdb,
                   2878:                       &srb
                   2879:                      ));
                   2880:     #if DBG
                   2881:             if (CdAudioDebug>2) {
                   2882: 
                   2883:                 DbgBreakPoint();
                   2884: 
                   2885:             }
                   2886:     #endif
                   2887:             status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2888:                                          &srb,
                   2889:                                          NULL,
                   2890:                                          0,
                   2891:                                          FALSE
                   2892:                                         );
                   2893: 
                   2894:         } while( !NT_SUCCESS(status) && ((retry--)>0) );
                   2895: #if DBG
                   2896:         if (!NT_SUCCESS(status)) {
                   2897: 
                   2898:             CdDump(( 1, "CdAudioPioneerDeviceControl: Seek to MSF failed 0x%lx\n",
                   2899:                      status
                   2900:                     ));
                   2901: 
                   2902:             if (CdAudioDebug>5) {
                   2903: 
                   2904:                 DbgBreakPoint();
                   2905: 
                   2906:             }
                   2907:         }
                   2908: #endif
                   2909:         }
                   2910:         break;
                   2911: 
                   2912:     case IOCTL_CDROM_PAUSE_AUDIO:
                   2913: 
                   2914:         CdDump(( 3,
                   2915:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
                   2916:                      ));
                   2917: 
                   2918:         deviceExtension->PlayActive = FALSE;
                   2919: 
                   2920:         //
                   2921:         // Enter pause (still ) mode
                   2922:         //
                   2923: 
                   2924:         srb.CdbLength                      = 10;
                   2925:         srb.TimeOutValue                   = AUDIO_TIMEOUT;
                   2926:         cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
                   2927:         cdb->PNR_PAUSE_AUDIO.Pause         = 1;
                   2928:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2929:                                      &srb,
                   2930:                                      NULL,
                   2931:                                      0,
                   2932:                                      FALSE
                   2933:                                     );
                   2934:         break;
                   2935: 
                   2936:     case IOCTL_CDROM_RESUME_AUDIO:
                   2937: 
                   2938:         CdDump(( 3,
                   2939:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
                   2940:                      ));
                   2941: 
                   2942: 
                   2943:         //
                   2944:         // Resume Play
                   2945:         //
                   2946: 
                   2947:         srb.CdbLength                      = 10;
                   2948:         srb.TimeOutValue                   = AUDIO_TIMEOUT;
                   2949:         cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
                   2950:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   2951:                                      &srb,
                   2952:                                      NULL,
                   2953:                                      0,
                   2954:                                      FALSE
                   2955:                                     );
                   2956:         break;
                   2957: 
                   2958:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   2959:         {
                   2960:         PSUB_Q_CURRENT_POSITION userPtr =
                   2961:             Irp->AssociatedIrp.SystemBuffer;
                   2962:         PUCHAR SubQPtr =
                   2963:             ExAllocatePool( NonPagedPoolCacheAligned,
                   2964:                             PIONEER_Q_CHANNEL_TRANSFER_SIZE
                   2965:                            );
                   2966: 
                   2967:         CdDump(( 5,
                   2968:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   2969:                      ));
                   2970: 
                   2971:         if (SubQPtr==NULL) {
                   2972: 
                   2973:             CdDump(( 1,
                   2974:                          "CdAudioPioneerDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   2975:                          ));
                   2976: 
                   2977:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   2978:             status = STATUS_INSUFFICIENT_RESOURCES;
                   2979:             goto SetStatusAndReturn;
                   2980: 
                   2981:         }
                   2982: 
                   2983:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   2984:              IOCTL_CDROM_CURRENT_POSITION) {
                   2985: 
                   2986:             CdDump(( 1,
                   2987:                          "CdAudioPioneerDeviceControl: READ_Q_CHANNEL, Illegal Format (%d)!\n",
                   2988:                          ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   2989:                          ));
                   2990: 
                   2991:             ExFreePool( SubQPtr );
                   2992:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   2993:             status = STATUS_INVALID_DEVICE_REQUEST;
                   2994:             goto SetStatusAndReturn;
                   2995:         }
                   2996: 
                   2997:         //
                   2998:         // Read audio play status
                   2999:         //
                   3000: 
                   3001:         retry = 5;
                   3002:         do {
                   3003:             srb.CdbLength = 10;
                   3004:             srb.TimeOutValue = AUDIO_TIMEOUT;
                   3005:             cdb->PNR_AUDIO_STATUS.OperationCode  = PIONEER_AUDIO_STATUS_CODE;
                   3006:             cdb->PNR_AUDIO_STATUS.AssignedLength = PIONEER_AUDIO_STATUS_TRANSFER_SIZE;  // Transfer Length
                   3007:             status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3008:                                          &srb,
                   3009:                                          SubQPtr,
                   3010:                                          6,
                   3011:                                          FALSE
                   3012:                                         );
                   3013:         } while( !NT_SUCCESS(status) && ((retry--)>0) && status != STATUS_DEVICE_NOT_READY);
                   3014:         if (NT_SUCCESS(status)) {
                   3015: 
                   3016:             userPtr->Header.Reserved = 0;
                   3017:             if (SubQPtr[0]==0x00)
                   3018:                 userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
                   3019:             else if (SubQPtr[0]==0x01) {
                   3020:                 deviceExtension->PlayActive = FALSE;
                   3021:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   3022:             } else if (SubQPtr[0]==0x02) {
                   3023:                 deviceExtension->PlayActive = FALSE;
                   3024:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   3025:             } else if (SubQPtr[0]==0x03) {
                   3026: 
                   3027:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
                   3028:                 deviceExtension->PlayActive = FALSE;
                   3029: 
                   3030:             } else {
                   3031:                 deviceExtension->PlayActive = FALSE;
                   3032: 
                   3033:             }
                   3034: 
                   3035:         } else {
                   3036: 
                   3037:             CdDump(( 1,
                   3038:                          "CdAudioPioneerDeviceControl: read status code (Q) failed (0x%lx)\n",
                   3039:                          status
                   3040:                          ));
                   3041: 
                   3042:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   3043:             ExFreePool( SubQPtr );
                   3044:             goto SetStatusAndReturn;
                   3045: 
                   3046:         }
                   3047: 
                   3048:         //
                   3049:         // Set up to read current position from Q Channel
                   3050:         //
                   3051: 
                   3052:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   3053:         retry =  5;
                   3054:         do {
                   3055:             srb.CdbLength = 10;
                   3056:             srb.TimeOutValue = AUDIO_TIMEOUT;
                   3057:             cdb->PNR_READ_Q_CHANNEL.OperationCode  = PIONEER_READ_SUB_Q_CHANNEL_CODE;
                   3058:             cdb->PNR_READ_Q_CHANNEL.AssignedLength = PIONEER_Q_CHANNEL_TRANSFER_SIZE;  // Transfer Length
                   3059:             status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3060:                                          &srb,
                   3061:                                          SubQPtr,
                   3062:                                          PIONEER_Q_CHANNEL_TRANSFER_SIZE,
                   3063:                                          FALSE
                   3064:                                         );
                   3065: 
                   3066:         } while( !NT_SUCCESS(status) && ((retry--)>0) );
                   3067: 
                   3068:         if (NT_SUCCESS(status)) {
                   3069: 
                   3070:             userPtr->Header.DataLength[0] = 0;
                   3071:             userPtr->Header.DataLength[0] = 12;
                   3072: 
                   3073:             userPtr->FormatCode = 0x01;
                   3074:             userPtr->Control = SubQPtr[0] & 0x0F;
                   3075:             userPtr->ADR     = 0;
                   3076:             userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[1]);
                   3077:             userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[2]);
                   3078:             userPtr->AbsoluteAddress[0] = 0;
                   3079:             userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[6]));
                   3080:             userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[7]));
                   3081:             userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[8]));
                   3082:             userPtr->TrackRelativeAddress[0] = 0;
                   3083:             userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[3]));
                   3084:             userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[4]));
                   3085:             userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[5]));
                   3086:             Irp->IoStatus.Information = 16;
                   3087: 
                   3088:         } else {
                   3089: 
                   3090:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   3091:             CdDump(( 1,
                   3092:                          "CdAudioPioneerDeviceControl: read q channel failed (0x%lx)\n",
                   3093:                          status
                   3094:                          ));
                   3095: 
                   3096: 
                   3097:         }
                   3098: 
                   3099:         ExFreePool( SubQPtr );
                   3100:         }
                   3101:         break;
                   3102: 
                   3103:     case IOCTL_CDROM_EJECT_MEDIA:
                   3104: 
                   3105:         CdDump(( 3,
                   3106:                      "CdAudioPioneerDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   3107:                      ));
                   3108: 
                   3109: 
                   3110:         deviceExtension->PlayActive = FALSE;
                   3111: 
                   3112:         //
                   3113:         // Build cdb to eject cartridge
                   3114:         //
                   3115: 
                   3116:         srb.CdbLength            = 10;
                   3117:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   3118:         cdb->PNR_EJECT.OperationCode = PIONEER_EJECT_CODE;
                   3119:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3120:                                      &srb,
                   3121:                                      NULL,
                   3122:                                      0,
                   3123:                                      FALSE
                   3124:                                     );
                   3125:         break;
                   3126: 
                   3127:     case IOCTL_CDROM_GET_CONTROL:
                   3128:     case IOCTL_CDROM_GET_VOLUME:
                   3129:     case IOCTL_CDROM_SET_VOLUME:
                   3130: 
                   3131:         CdDump(( 3, "CdAudioPioneerDeviceControl: Not Supported yet.\n" ));
                   3132:         status = STATUS_INVALID_DEVICE_REQUEST;
                   3133:         break;
                   3134: 
                   3135:     case IOCTL_CDROM_CHECK_VERIFY:
                   3136: 
                   3137:         //
                   3138:         // Update the play active flag.
                   3139:         //
                   3140: 
                   3141:         CdAudioIsPlayActive(DeviceObject);
                   3142: 
                   3143:     default:
                   3144: 
                   3145:         CdDump((5,"CdAudioPioneerDeviceControl: Unsupported device IOCTL\n"));
                   3146:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   3147:         break;
                   3148: 
                   3149: 
                   3150: 
                   3151:     } // end switch( IOCTL )
                   3152: 
                   3153: SetStatusAndReturn:
                   3154:     //
                   3155:     // set status code and return
                   3156:     //
                   3157: 
                   3158:     if (status == STATUS_VERIFY_REQUIRED) {
                   3159: 
                   3160:         //
                   3161:         // If the status is verified required and the this request
                   3162:         // should bypass verify required then retry the request.
                   3163:         //
                   3164: 
                   3165:         if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
                   3166: 
                   3167:             status = STATUS_IO_DEVICE_ERROR;
                   3168:             goto PioneerRestart;
                   3169: 
                   3170:         }
                   3171: 
                   3172: 
                   3173:         IoSetHardErrorOrVerifyDevice( Irp,
                   3174:                                       deviceExtension->TargetDeviceObject
                   3175:                                      );
                   3176: 
                   3177:         Irp->IoStatus.Information = 0;
                   3178:     }
                   3179: 
                   3180:     Irp->IoStatus.Status = status;
                   3181:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   3182:     return status;
                   3183: 
                   3184: }
                   3185: 
                   3186: 
                   3187: NTSTATUS
                   3188: CdAudioDenonDeviceControl(
                   3189:     PDEVICE_OBJECT DeviceObject,
                   3190:     PIRP Irp
                   3191:     )
                   3192: 
                   3193: /*++
                   3194: 
                   3195: Routine Description:
                   3196: 
                   3197:     This routine is called by CdAudioDeviceControl to handle
                   3198:     audio IOCTLs sent to DENON DRD-253 cdrom drive.
                   3199: 
                   3200: Arguments:
                   3201: 
                   3202:     DeviceObject
                   3203:     Irp
                   3204: 
                   3205: Return Value:
                   3206: 
                   3207:     NTSTATUS
                   3208: 
                   3209: --*/
                   3210: 
                   3211: {
                   3212:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   3213:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   3214:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   3215:     SCSI_REQUEST_BLOCK srb;
                   3216:     PCDB               cdb = (PCDB)srb.Cdb;
                   3217:     NTSTATUS           status;
                   3218:     ULONG              i,bytesTransfered;
                   3219:     PUCHAR             Toc;
                   3220: 
                   3221: DenonRestart:
                   3222: 
                   3223:     //
                   3224:     // Clear out cdb
                   3225:     //
                   3226: 
                   3227:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   3228: 
                   3229:     //
                   3230:     // What IOCTL do we need to execute?
                   3231:     //
                   3232: 
                   3233:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   3234: 
                   3235:     case IOCTL_CDROM_READ_TOC:
                   3236:         CdDump(( 3,
                   3237:                      "CdAudioDenonDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   3238:                      ));
                   3239: 
                   3240:         //
                   3241:         // If the cd is playing music then reject this request.
                   3242:         //
                   3243: 
                   3244:         if (CdAudioIsPlayActive(DeviceObject)) {
                   3245:             status = STATUS_DEVICE_BUSY;
                   3246:             break;
                   3247:         }
                   3248: 
                   3249: 
                   3250:         //
                   3251:         // Allocate storage to hold TOC from disc
                   3252:         //
                   3253: 
                   3254:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   3255:                                       CDROM_TOC_SIZE
                   3256:                                      );
                   3257: 
                   3258:         if (Toc==NULL) {
                   3259: 
                   3260:             status = STATUS_INSUFFICIENT_RESOURCES;
                   3261:             goto SetStatusAndReturn;
                   3262: 
                   3263:         }
                   3264: 
                   3265:         //
                   3266:         // Set up defaults
                   3267:         //
                   3268: 
                   3269:         RtlZeroMemory( Toc, CDROM_TOC_SIZE );
                   3270: 
                   3271:         //
                   3272:         // Fill in cdb for this operation
                   3273:         //
                   3274: 
                   3275:         cdb->CDB6GENERIC.OperationCode = DENON_READ_TOC_CODE;
                   3276:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   3277:         srb.CdbLength                  = 6;
                   3278:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3279:                                      &srb,
                   3280:                                      Toc,
                   3281:                                      CDROM_TOC_SIZE,
                   3282:                                      FALSE
                   3283:                                     );
                   3284: 
                   3285:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   3286: 
                   3287:             CdDump(( 1,
                   3288:                 "CdAudioDenonDeviceControl: READ_TOC error (0x%08lX)\n",
                   3289:                  status ));
                   3290: 
                   3291:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   3292: 
                   3293:                 CdDump(( 1, "CdAudioDenonDeviceControl: SRB ERROR (0x%lX)\n",
                   3294:                              srb.SrbStatus ));
                   3295:                 ExFreePool( Toc );
                   3296:                 goto SetStatusAndReturn;
                   3297:             }
                   3298: 
                   3299:         }
                   3300: 
                   3301:         //
                   3302:         // Set the status to success since data under runs are not an error.
                   3303:         //
                   3304: 
                   3305:         status = STATUS_SUCCESS;
                   3306: 
                   3307:         //
                   3308:         // Since the Denon manual didn't define the format of
                   3309:         // the buffer returned from this call, here it is:
                   3310:         //
                   3311:         // Byte  Data (4 byte "packets")
                   3312:         //
                   3313:         //  00   a0 FT 00 00 (FT       == BCD of first track number on disc)
                   3314:         //  04   a1 LT 00 00 (LT       == BCD of last  track number on disc)
                   3315:         //  08   a2 MM SS FF (MM SS FF == BCD of total disc time, in MSF)
                   3316:         //
                   3317:         //  For each track on disc:
                   3318:         //
                   3319:         //  0C   XX   MM SS FF (MM SS FF == BCD MSF start position of track XX)
                   3320:         //  0C+4 XX+1 MM SS FF (MM SS FF == BCD MSF start position of track XX+1)
                   3321:         //
                   3322:         //  etc., for each track
                   3323:         //
                   3324: 
                   3325:         //
                   3326:         // Translate data into our format
                   3327:         //
                   3328: 
                   3329:         bytesTransfered =
                   3330:             currentIrpStack->Parameters.Read.Length > srb.DataTransferLength ?
                   3331:             srb.DataTransferLength : currentIrpStack->Parameters.Read.Length;
                   3332:         Irp->IoStatus.Information = bytesTransfered;
                   3333:         cdaudioDataOut->Length[0]  = bytesTransfered >> 8;
                   3334:         cdaudioDataOut->Length[1]  = (bytesTransfered & 0xFF);
                   3335:         cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[1]);
                   3336:         cdaudioDataOut->LastTrack  = BCD_TO_DEC(Toc[5]);
                   3337: 
                   3338:         for( i=0;
                   3339:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   3340:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   3341:              i++
                   3342:             ) {
                   3343: 
                   3344:             //
                   3345:             // Grab Information for each track
                   3346:             //
                   3347: 
                   3348:             cdaudioDataOut->TrackData[i].Reserved = 0;
                   3349:             cdaudioDataOut->TrackData[i].Control  = Toc[(i*4)+12];
                   3350:             cdaudioDataOut->TrackData[i].TrackNumber =
                   3351:                 (i + cdaudioDataOut->FirstTrack);
                   3352: 
                   3353:             cdaudioDataOut->TrackData[i].Reserved1  = 0;
                   3354:             cdaudioDataOut->TrackData[i].Address[0] = 0;
                   3355:             cdaudioDataOut->TrackData[i].Address[1] =
                   3356:                 BCD_TO_DEC((Toc[(i*4)+13]));
                   3357:             cdaudioDataOut->TrackData[i].Address[2] =
                   3358:                 BCD_TO_DEC((Toc[(i*4)+14]));
                   3359:             cdaudioDataOut->TrackData[i].Address[3] =
                   3360:                 BCD_TO_DEC((Toc[(i*4)+15]));
                   3361: 
                   3362:         }
                   3363: 
                   3364:         //
                   3365:         // Fake "lead out track" info
                   3366:         //
                   3367: 
                   3368:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   3369:         cdaudioDataOut->TrackData[i].Control     = 0;
                   3370:         cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
                   3371:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   3372:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   3373:         cdaudioDataOut->TrackData[i].Address[1]  = BCD_TO_DEC(Toc[9]);
                   3374:         cdaudioDataOut->TrackData[i].Address[2]  = BCD_TO_DEC(Toc[10]);
                   3375:         cdaudioDataOut->TrackData[i].Address[3]  = BCD_TO_DEC(Toc[11]);
                   3376: 
                   3377:         //
                   3378:         // Clear out deviceExtension data
                   3379:         //
                   3380: 
                   3381:         deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   3382:         deviceExtension->PausedM = 0;
                   3383:         deviceExtension->PausedS = 0;
                   3384:         deviceExtension->PausedF = 0;
                   3385:         deviceExtension->LastEndM = 0;
                   3386:         deviceExtension->LastEndS = 0;
                   3387:         deviceExtension->LastEndF = 0;
                   3388: 
                   3389:         //
                   3390:         // Free storage now that we've stored it elsewhere
                   3391:         //
                   3392: 
                   3393:         ExFreePool( Toc );
                   3394:         break;
                   3395: 
                   3396:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   3397:     case IOCTL_CDROM_STOP_AUDIO:
                   3398:         {
                   3399: 
                   3400:         PCDROM_PLAY_AUDIO_MSF inputBuffer =
                   3401:             Irp->AssociatedIrp.SystemBuffer;
                   3402: 
                   3403:         deviceExtension->PlayActive = FALSE;
                   3404: 
                   3405:         srb.CdbLength                  = 6;
                   3406:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   3407:         cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
                   3408:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3409:                                      &srb,
                   3410:                                      NULL,
                   3411:                                      0,
                   3412:                                      FALSE
                   3413:                                     );
                   3414: 
                   3415:         if (NT_SUCCESS(status)) {
                   3416: 
                   3417:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   3418:             deviceExtension->PausedM = 0;
                   3419:             deviceExtension->PausedS = 0;
                   3420:             deviceExtension->PausedF = 0;
                   3421:             deviceExtension->LastEndM = 0;
                   3422:             deviceExtension->LastEndS = 0;
                   3423:             deviceExtension->LastEndF = 0;
                   3424: 
                   3425:         } else {
                   3426: 
                   3427:             CdDump(( 3,
                   3428:                 "CdAudioDenonDeviceControl: STOP failed (0x%08lX)\n",
                   3429:                 status ));
                   3430: 
                   3431:         }
                   3432: 
                   3433: 
                   3434:         if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
                   3435:             IOCTL_CDROM_STOP_AUDIO
                   3436:            ) {
                   3437: 
                   3438:             CdDump(( 3,
                   3439:                          "CdAudioDenonDeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
                   3440:                          ));
                   3441: 
                   3442:             goto SetStatusAndReturn;
                   3443: 
                   3444:         }
                   3445: 
                   3446:         CdDump(( 3,
                   3447:             "CdAudioDenonDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
                   3448:             ));
                   3449: 
                   3450:         //
                   3451:         // Fill in cdb for this operation
                   3452:         //
                   3453: 
                   3454:         srb.CdbLength                = 10;
                   3455:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   3456:         cdb->CDB10.OperationCode     = DENON_PLAY_AUDIO_EXTENDED_CODE;
                   3457:         cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->StartingM);
                   3458:         cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->StartingS);
                   3459:         cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->StartingF);
                   3460:         cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->EndingM);
                   3461:         cdb->CDB10.Reserved2         = DEC_TO_BCD(inputBuffer->EndingS);
                   3462:         cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->EndingF);
                   3463:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3464:                                      &srb,
                   3465:                                      NULL,
                   3466:                                      0,
                   3467:                                      FALSE
                   3468:                                     );
                   3469: 
                   3470:         if (NT_SUCCESS(status)) {
                   3471: 
                   3472:             //
                   3473:             // Indicate the play actition is active.
                   3474:             //
                   3475: 
                   3476:             deviceExtension->PlayActive = TRUE;
                   3477:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   3478: 
                   3479:             //
                   3480:             // Set last play ending address for next pause command
                   3481:             //
                   3482: 
                   3483:             deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->EndingM);
                   3484:             deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->EndingS);
                   3485:             deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->EndingF);
                   3486:             CdDump(( 3,
                   3487:                 "CdAudioDenonDeviceControl: PLAY  ==> BcdLastEnd set to (%x %x %x)\n",
                   3488:                 deviceExtension->LastEndM,
                   3489:                 deviceExtension->LastEndS,
                   3490:                 deviceExtension->LastEndF ));
                   3491: 
                   3492:         } else {
                   3493: 
                   3494:             CdDump(( 3,
                   3495:                 "CdAudioDenonDeviceControl: PLAY failed (0x%08lX)\n",
                   3496:                 status ));
                   3497: 
                   3498:             //
                   3499:             // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
                   3500:             // when we ask to play an invalid address, so we need
                   3501:             // to map to STATUS_NONEXISTENT_SECTOR in order to be
                   3502:             // consistent with the other drives.
                   3503:             //
                   3504: 
                   3505:             if (status==STATUS_INVALID_DEVICE_REQUEST) {
                   3506: 
                   3507:                 status = STATUS_NONEXISTENT_SECTOR;
                   3508:             }
                   3509: 
                   3510:         }
                   3511:         }
                   3512:         break;
                   3513: 
                   3514:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   3515:         {
                   3516: 
                   3517:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   3518: 
                   3519:         CdDump(( 3,
                   3520:             "CdAudioDenonDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   3521:             ));
                   3522: 
                   3523:         //
                   3524:         // Fill in cdb for this operation
                   3525:         //
                   3526: 
                   3527:         srb.CdbLength                = 10;
                   3528:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   3529:         cdb->CDB10.OperationCode     = DENON_PLAY_AUDIO_EXTENDED_CODE;
                   3530:         cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->M);
                   3531:         cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->S);
                   3532:         cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->F);
                   3533:         cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->M);
                   3534:         cdb->CDB10.Reserved2         = DEC_TO_BCD(inputBuffer->S);
                   3535:         cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->F);
                   3536:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3537:                                      &srb,
                   3538:                                      NULL,
                   3539:                                      0,
                   3540:                                      FALSE
                   3541:                                     );
                   3542: 
                   3543:         if (NT_SUCCESS(status)) {
                   3544: 
                   3545:             deviceExtension->Paused = CDAUDIO_PAUSED;
                   3546:             deviceExtension->PausedM = DEC_TO_BCD(inputBuffer->M);
                   3547:             deviceExtension->PausedS = DEC_TO_BCD(inputBuffer->S);
                   3548:             deviceExtension->PausedF = DEC_TO_BCD(inputBuffer->F);
                   3549:             deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->M);
                   3550:             deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->S);
                   3551:             deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->F);
                   3552:             CdDump(( 3,
                   3553:                 "CdAudioDenonDeviceControl: SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
                   3554:                 deviceExtension->PausedM,
                   3555:                 deviceExtension->PausedS,
                   3556:                 deviceExtension->PausedF,
                   3557:                 deviceExtension->LastEndM,
                   3558:                 deviceExtension->LastEndS,
                   3559:                 deviceExtension->LastEndF ));
                   3560: 
                   3561:         } else {
                   3562: 
                   3563:             CdDump(( 3,
                   3564:                 "CdAudioDenonDeviceControl: SEEK failed (0x%08lX)\n",
                   3565:                 status ));
                   3566: 
                   3567:             //
                   3568:             // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
                   3569:             // when we ask to play an invalid address, so we need
                   3570:             // to map to STATUS_NONEXISTENT_SECTOR in order to be
                   3571:             // consistent with the other drives.
                   3572:             //
                   3573: 
                   3574:             if (status==STATUS_INVALID_DEVICE_REQUEST) {
                   3575: 
                   3576:                 status = STATUS_NONEXISTENT_SECTOR;
                   3577:             }
                   3578: 
                   3579:         }
                   3580:         }
                   3581:         break;
                   3582: 
                   3583:     case IOCTL_CDROM_PAUSE_AUDIO:
                   3584:         {
                   3585:         PUCHAR SubQPtr =
                   3586:             ExAllocatePool( NonPagedPoolCacheAligned,
                   3587:                             10
                   3588:                            );
                   3589: 
                   3590:         CdDump(( 3,
                   3591:                      "CdAudioDenonDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
                   3592:                      ));
                   3593: 
                   3594:         deviceExtension->PlayActive = FALSE;
                   3595: 
                   3596:         if (SubQPtr==NULL) {
                   3597: 
                   3598:             status = STATUS_INSUFFICIENT_RESOURCES;
                   3599:             goto SetStatusAndReturn;
                   3600: 
                   3601:         }
                   3602: 
                   3603:         //
                   3604:         // Enter pause (still ) mode
                   3605:         //
                   3606: 
                   3607:         if (deviceExtension->Paused==CDAUDIO_PAUSED) {
                   3608: 
                   3609:             CdDump(( 3,
                   3610:                 "CdAudioDenonDeviceControl: PAUSE: Already Paused!\n"
                   3611:                 ));
                   3612: 
                   3613:             ExFreePool( SubQPtr );
                   3614:             status = STATUS_SUCCESS;
                   3615:             goto SetStatusAndReturn;
                   3616: 
                   3617:         }
                   3618: 
                   3619:         //
                   3620:         // Since the Denon doesn't have a pause mode,
                   3621:         // we'll just record the current position and
                   3622:         // stop the drive.
                   3623:         //
                   3624: 
                   3625:         srb.CdbLength                  = 6;
                   3626:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   3627:         cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
                   3628:         cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
                   3629:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3630:                                      &srb,
                   3631:                                      SubQPtr,
                   3632:                                      10,
                   3633:                                      FALSE
                   3634:                                     );
                   3635:         if (!NT_SUCCESS(status)) {
                   3636: 
                   3637:                 CdDump(( 1,
                   3638:                     "CdAudioDenonDeviceControl: Pause, Read Q Channel failed (0x%lx)\n",
                   3639:                     status ));
                   3640:                 ExFreePool( SubQPtr );
                   3641:                 goto SetStatusAndReturn;
                   3642:         }
                   3643: 
                   3644:         deviceExtension->PausedM = SubQPtr[7];
                   3645:         deviceExtension->PausedS = SubQPtr[8];
                   3646:         deviceExtension->PausedF = SubQPtr[9];
                   3647: 
                   3648:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   3649:         srb.CdbLength                  = 6;
                   3650:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   3651:         cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
                   3652:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3653:                                      &srb,
                   3654:                                      NULL,
                   3655:                                      0,
                   3656:                                      FALSE
                   3657:                                     );
                   3658:         if (!NT_SUCCESS(status)) {
                   3659: 
                   3660:                 CdDump(( 1,
                   3661:                     "CdAudioDenonDeviceControl: PAUSE, StopAudio failed! (0x%08lX)\n",
                   3662:                     status ));
                   3663:                 ExFreePool( SubQPtr );
                   3664:                 goto SetStatusAndReturn;
                   3665:         }
                   3666: 
                   3667:         deviceExtension->Paused = CDAUDIO_PAUSED;
                   3668:         deviceExtension->PausedM = SubQPtr[7];
                   3669:         deviceExtension->PausedS = SubQPtr[8];
                   3670:         deviceExtension->PausedF = SubQPtr[9];
                   3671: 
                   3672:         CdDump((3,
                   3673:             "CdAudioDenonDeviceControl: PAUSE ==> Paused  set to (%x %x %x)\n",
                   3674:             deviceExtension->PausedM,
                   3675:             deviceExtension->PausedS,
                   3676:             deviceExtension->PausedF ));
                   3677: 
                   3678:         ExFreePool( SubQPtr );
                   3679:         }
                   3680:         break;
                   3681: 
                   3682:     case IOCTL_CDROM_RESUME_AUDIO:
                   3683: 
                   3684:         //
                   3685:         // Resume cdrom
                   3686:         //
                   3687: 
                   3688:         CdDump(( 3,
                   3689:                      "CdAudioDenonDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
                   3690:                      ));
                   3691: 
                   3692: 
                   3693:         //
                   3694:         // Since the Denon doesn't have a resume IOCTL,
                   3695:         // we'll just start playing (if paused) from the
                   3696:         // last recored paused position to the last recorded
                   3697:         // "end of play" position.
                   3698:         //
                   3699: 
                   3700:         if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
                   3701: 
                   3702:             status = STATUS_UNSUCCESSFUL;
                   3703:             goto SetStatusAndReturn;
                   3704: 
                   3705:         }
                   3706: 
                   3707: 
                   3708: 
                   3709:         //
                   3710:         // Fill in cdb for this operation
                   3711:         //
                   3712: 
                   3713:         srb.CdbLength                = 10;
                   3714:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   3715:         cdb->CDB10.OperationCode     = DENON_PLAY_AUDIO_EXTENDED_CODE;
                   3716:         cdb->CDB10.LogicalBlockByte0 = deviceExtension->PausedM;
                   3717:         cdb->CDB10.LogicalBlockByte1 = deviceExtension->PausedS;
                   3718:         cdb->CDB10.LogicalBlockByte2 = deviceExtension->PausedF;
                   3719:         cdb->CDB10.LogicalBlockByte3 = deviceExtension->LastEndM;
                   3720:         cdb->CDB10.Reserved2         = deviceExtension->LastEndS;
                   3721:         cdb->CDB10.TransferBlocksMsb = deviceExtension->LastEndF;
                   3722:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3723:                                      &srb,
                   3724:                                      NULL,
                   3725:                                      0,
                   3726:                                      FALSE
                   3727:                                     );
                   3728: 
                   3729:         if (NT_SUCCESS(status)) {
                   3730: 
                   3731:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   3732: 
                   3733:         } else {
                   3734: 
                   3735:             CdDump(( 1,
                   3736:                 "CdAudioDenonDeviceControl: RESUME (%x %x %x) - (%x %x %x) failed (0x%08lX)\n",
                   3737:                 deviceExtension->PausedM,
                   3738:                 deviceExtension->PausedS,
                   3739:                 deviceExtension->PausedF,
                   3740:                 deviceExtension->LastEndM,
                   3741:                 deviceExtension->LastEndS,
                   3742:                 deviceExtension->LastEndF,
                   3743:                 status ));
                   3744: 
                   3745:         }
                   3746:         break;
                   3747: 
                   3748:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   3749:         {
                   3750:         PSUB_Q_CURRENT_POSITION userPtr =
                   3751:             Irp->AssociatedIrp.SystemBuffer;
                   3752:         PUCHAR SubQPtr =
                   3753:             ExAllocatePool( NonPagedPoolCacheAligned,
                   3754:                             sizeof(SUB_Q_CHANNEL_DATA)
                   3755:                            );
                   3756: 
                   3757:         CdDump(( 5,
                   3758:                      "CdAudioDenonDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   3759:                      ));
                   3760: 
                   3761:         if (SubQPtr==NULL) {
                   3762: 
                   3763:             CdDump(( 1,
                   3764:                          "CdAudioDenonDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   3765:                          ));
                   3766: 
                   3767:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   3768:             status = STATUS_INSUFFICIENT_RESOURCES;
                   3769:             goto SetStatusAndReturn;
                   3770: 
                   3771:         }
                   3772: 
                   3773:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   3774:              IOCTL_CDROM_CURRENT_POSITION) {
                   3775: 
                   3776:             CdDump(( 1,
                   3777:                          "CdAudioDenonDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
                   3778:                          ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   3779:                          ));
                   3780: 
                   3781:             ExFreePool( SubQPtr );
                   3782:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   3783:             status = STATUS_UNSUCCESSFUL;
                   3784:             goto SetStatusAndReturn;
                   3785:         }
                   3786: 
                   3787:         //
                   3788:         // Read audio play status
                   3789:         //
                   3790: 
                   3791:         srb.CdbLength            = 6;
                   3792:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   3793:         cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
                   3794:         cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
                   3795:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3796:                                      &srb,
                   3797:                                      SubQPtr,
                   3798:                                      10,
                   3799:                                      FALSE
                   3800:                                     );
                   3801:         if (NT_SUCCESS(status)) {
                   3802: 
                   3803:             userPtr->Header.Reserved = 0;
                   3804: 
                   3805:             if (deviceExtension->Paused==CDAUDIO_PAUSED) {
                   3806: 
                   3807:                 deviceExtension->PlayActive = FALSE;
                   3808:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   3809: 
                   3810:             } else {
                   3811: 
                   3812:                 if (SubQPtr[0]==0x01)
                   3813:                     userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
                   3814:                 else if (SubQPtr[0]==0x00){
                   3815:                     userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
                   3816:                     deviceExtension->PlayActive = FALSE;
                   3817: 
                   3818:                 } else {
                   3819:                     deviceExtension->PlayActive = FALSE;
                   3820:                 }
                   3821: 
                   3822:             }
                   3823: 
                   3824:             userPtr->Header.DataLength[0] = 0;
                   3825:             userPtr->Header.DataLength[0] = 12;
                   3826: 
                   3827:             userPtr->FormatCode = 0x01;
                   3828:             userPtr->Control = SubQPtr[1];
                   3829:             userPtr->ADR     = 0;
                   3830:             userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
                   3831:             userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
                   3832:             userPtr->AbsoluteAddress[0] = 0;
                   3833:             userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
                   3834:             userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
                   3835:             userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
                   3836:             userPtr->TrackRelativeAddress[0] = 0;
                   3837:             userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
                   3838:             userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
                   3839:             userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
                   3840:             Irp->IoStatus.Information = 16;
                   3841: 
                   3842:         } else {
                   3843: 
                   3844:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   3845:             CdDump(( 1,
                   3846:                          "CdAudioDenonDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
                   3847:                          status
                   3848:                          ));
                   3849: 
                   3850: 
                   3851:         }
                   3852: 
                   3853:         ExFreePool( SubQPtr );
                   3854:         }
                   3855:         break;
                   3856: 
                   3857:     case IOCTL_CDROM_EJECT_MEDIA:
                   3858: 
                   3859:         //
                   3860:         // Build cdb to eject cartridge
                   3861:         //
                   3862: 
                   3863:         CdDump(( 3,
                   3864:                      "CdAudioDenonDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   3865:                      ));
                   3866: 
                   3867:         deviceExtension->PlayActive = FALSE;
                   3868: 
                   3869:         srb.CdbLength                  = 6;
                   3870:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   3871:         cdb->CDB6GENERIC.OperationCode = DENON_EJECT_CODE;
                   3872:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3873:                                      &srb,
                   3874:                                      NULL,
                   3875:                                      0,
                   3876:                                      FALSE
                   3877:                                     );
                   3878:         break;
                   3879: 
                   3880:     case IOCTL_CDROM_GET_CONTROL:
                   3881:     case IOCTL_CDROM_GET_VOLUME:
                   3882:     case IOCTL_CDROM_SET_VOLUME:
                   3883:         CdDump(( 3, "CdAudioDenonDeviceControl: Not Supported yet.\n" ));
                   3884:         status = STATUS_INVALID_DEVICE_REQUEST;
                   3885:         break;
                   3886: 
                   3887:     case IOCTL_CDROM_CHECK_VERIFY:
                   3888: 
                   3889:         //
                   3890:         // Update the play active flag.
                   3891:         //
                   3892: 
                   3893:         CdAudioIsPlayActive(DeviceObject);
                   3894: 
                   3895:     default:
                   3896: 
                   3897:         CdDump((5,"CdAudioDenonDeviceControl: Unsupported device IOCTL\n"));
                   3898:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   3899:         break;
                   3900: 
                   3901:     } // end switch( IOCTL )
                   3902: 
                   3903: SetStatusAndReturn:
                   3904:     //
                   3905:     // set status code and return
                   3906:     //
                   3907: 
                   3908:     if (status == STATUS_VERIFY_REQUIRED) {
                   3909: 
                   3910:         //
                   3911:         // If the status is verified required and the this request
                   3912:         // should bypass verify required then retry the request.
                   3913:         //
                   3914: 
                   3915:         if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
                   3916: 
                   3917:             status = STATUS_IO_DEVICE_ERROR;
                   3918:             goto DenonRestart;
                   3919: 
                   3920:         }
                   3921: 
                   3922: 
                   3923:         IoSetHardErrorOrVerifyDevice( Irp,
                   3924:                                       deviceExtension->TargetDeviceObject
                   3925:                                      );
                   3926: 
                   3927:         Irp->IoStatus.Information = 0;
                   3928:     }
                   3929: 
                   3930:     Irp->IoStatus.Status = status;
                   3931:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   3932:     return status;
                   3933: 
                   3934: }
                   3935: 
                   3936: NTSTATUS
                   3937: CdAudioHitatchiSendPauseCommand(
                   3938:     IN PDEVICE_OBJECT DeviceObject
                   3939:     )
                   3940: 
                   3941: /*++
                   3942: 
                   3943: Routine Description:
                   3944: 
                   3945:     This routine sends a PAUSE cdb to the Hitatchi drive.  The Hitatchi
                   3946:     drive returns a "busy" condition whenever a play audio command is in
                   3947:     progress...so we need to bump the drive out of audio play to issue
                   3948:     a new command.  This routine is in place for this purpose.
                   3949: 
                   3950: Arguments:
                   3951: 
                   3952:     DeviceObject
                   3953:     Irp
                   3954: 
                   3955: Return Value:
                   3956: 
                   3957:     NTSTATUS
                   3958: 
                   3959: --*/
                   3960: 
                   3961: {
                   3962:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   3963:     SCSI_REQUEST_BLOCK srb;
                   3964:     PCDB12             cdb = (PCDB12)srb.Cdb;
                   3965:     NTSTATUS           status;
                   3966:     PUCHAR             PausePos;
                   3967: 
                   3968:     //
                   3969:     // Allocate buffer for pause data
                   3970:     //
                   3971: 
                   3972:     PausePos = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned, 3 );
                   3973: 
                   3974:     if (PausePos==NULL) {
                   3975: 
                   3976:         return(STATUS_INSUFFICIENT_RESOURCES);
                   3977: 
                   3978:     }
                   3979: 
                   3980:     RtlZeroMemory( PausePos, 3 );
                   3981: 
                   3982:     //
                   3983:     // Clear out cdb
                   3984:     //
                   3985: 
                   3986:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   3987: 
                   3988:     //
                   3989:     // Clear audio play command so that next command will be issued
                   3990:     //
                   3991: 
                   3992:     srb.CdbLength    = 12;
                   3993:     srb.TimeOutValue = AUDIO_TIMEOUT;
                   3994:     cdb->PAUSE_AUDIO.OperationCode = HITATCHI_PAUSE_AUDIO_CODE;
                   3995:     status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   3996:                                  &srb,
                   3997:                                  PausePos,
                   3998:                                  3,
                   3999:                                  FALSE
                   4000:                                 );
                   4001: 
                   4002:     ExFreePool( PausePos );
                   4003: 
                   4004:     return status;
                   4005: }
                   4006: 
                   4007: NTSTATUS
                   4008: CdAudioHitatchiDeviceControl(
                   4009:     IN PDEVICE_OBJECT DeviceObject,
                   4010:     IN PIRP Irp
                   4011:     )
                   4012: 
                   4013: /*++
                   4014: 
                   4015: Routine Description:
                   4016: 
                   4017:     This routine is called by CdAudioDeviceControl to handle
                   4018:     audio IOCTLs sent to Hitatchi cdrom drives.
                   4019: 
                   4020: Arguments:
                   4021: 
                   4022:     DeviceObject
                   4023:     Irp
                   4024: 
                   4025: Return Value:
                   4026: 
                   4027:     NTSTATUS
                   4028: 
                   4029: --*/
                   4030: 
                   4031: {
                   4032:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   4033:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   4034:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   4035:     SCSI_REQUEST_BLOCK srb;
                   4036:     PCDB12             cdb = (PCDB12)srb.Cdb;
                   4037:     NTSTATUS           status;
                   4038:     ULONG              i,bytesTransfered;
                   4039:     PUCHAR             Toc;
                   4040: 
                   4041: HitatchiRestart:
                   4042: 
                   4043:     //
                   4044:     // Clear out cdb
                   4045:     //
                   4046: 
                   4047:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   4048: 
                   4049:     //
                   4050:     // What IOCTL do we need to execute?
                   4051:     //
                   4052: 
                   4053:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   4054: 
                   4055:     case IOCTL_CDROM_READ_TOC:
                   4056:         CdDump(( 3,
                   4057:                      "CdAudioHitatchiDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   4058:                      ));
                   4059: 
                   4060:         //
                   4061:         // If the cd is playing music then reject this request.
                   4062:         //
                   4063: 
                   4064:         if (CdAudioIsPlayActive(DeviceObject)) {
                   4065:             status = STATUS_DEVICE_BUSY;
                   4066:             break;
                   4067:         }
                   4068: 
                   4069:         //
                   4070:         // Allocate storage to hold TOC from disc
                   4071:         //
                   4072: 
                   4073:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   4074:                                       CDROM_TOC_SIZE
                   4075:                                      );
                   4076: 
                   4077:         if (Toc==NULL) {
                   4078: 
                   4079:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4080:             goto SetStatusAndReturn;
                   4081: 
                   4082:         }
                   4083: 
                   4084:         //
                   4085:         // Set up defaults
                   4086:         //
                   4087: 
                   4088:         RtlZeroMemory( Toc, CDROM_TOC_SIZE );
                   4089:         srb.CdbLength = 12;
                   4090: 
                   4091:         //
                   4092:         // Fill in CDB
                   4093:         //
                   4094: 
                   4095:         cdb->READ_DISC_INFO.OperationCode       = HITATCHI_READ_TOC_CODE;
                   4096:         cdb->READ_DISC_INFO.AllocationLength[0] = CDROM_TOC_SIZE >> 8;
                   4097:         cdb->READ_DISC_INFO.AllocationLength[1] = CDROM_TOC_SIZE & 0xFF;
                   4098:         srb.TimeOutValue                        = AUDIO_TIMEOUT;
                   4099:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4100:                                      &srb,
                   4101:                                      Toc,
                   4102:                                      CDROM_TOC_SIZE,
                   4103:                                      FALSE
                   4104:                                     );
                   4105: 
                   4106:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   4107: 
                   4108:             CdDump(( 1,
                   4109:                 "CdAudioHitatchiDeviceControl: READ_TOC error (0x%08lX)\n",
                   4110:                  status ));
                   4111: 
                   4112: 
                   4113:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   4114: 
                   4115:                 CdDump(( 1, "CdAudioHitatchiDeviceControl: SRB ERROR (0x%lX)\n",
                   4116:                              srb.SrbStatus ));
                   4117:                 ExFreePool( Toc );
                   4118:                 goto SetStatusAndReturn;
                   4119:             }
                   4120: 
                   4121:         } else
                   4122: 
                   4123:             status = STATUS_SUCCESS;
                   4124: 
                   4125:         //
                   4126:         // Translate data into our format
                   4127:         //
                   4128: 
                   4129:         bytesTransfered =
                   4130:             currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
                   4131:             sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
                   4132:         Irp->IoStatus.Information  = bytesTransfered;
                   4133:         cdaudioDataOut->Length[0]  = bytesTransfered >> 8;
                   4134:         cdaudioDataOut->Length[1]  = (bytesTransfered & 0xFF);
                   4135:         cdaudioDataOut->FirstTrack = Toc[2];
                   4136:         cdaudioDataOut->LastTrack  = Toc[3];
                   4137: 
                   4138:         for( i=0;
                   4139:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   4140:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   4141:              i++
                   4142:             ) {
                   4143: 
                   4144:             //
                   4145:             // Grab Information for each track
                   4146:             //
                   4147: 
                   4148:             cdaudioDataOut->TrackData[i].Reserved    = 0;
                   4149:             cdaudioDataOut->TrackData[i].Control     =
                   4150:                 ((Toc[(i*4)+8] & 0x0F) << 4) | (Toc[(i*4)+8] >> 4);
                   4151:             cdaudioDataOut->TrackData[i].TrackNumber =
                   4152:                 (i + cdaudioDataOut->FirstTrack);
                   4153: 
                   4154:             cdaudioDataOut->TrackData[i].Reserved1 =  0;
                   4155:             cdaudioDataOut->TrackData[i].Address[0] = 0;
                   4156:             cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*4)+9];
                   4157:             cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*4)+10];
                   4158:             cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*4)+11];
                   4159: 
                   4160:         }
                   4161: 
                   4162:         //
                   4163:         // Fake "lead out track" info
                   4164:         //
                   4165: 
                   4166:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   4167:         cdaudioDataOut->TrackData[i].Control     = 0x10;
                   4168:         cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
                   4169:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   4170:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   4171:         cdaudioDataOut->TrackData[i].Address[1]  = Toc[5];
                   4172:         cdaudioDataOut->TrackData[i].Address[2]  = Toc[6];
                   4173:         cdaudioDataOut->TrackData[i].Address[3]  = Toc[7];
                   4174: 
                   4175:         //
                   4176:         // Clear out device extension data
                   4177:         //
                   4178: 
                   4179:         deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   4180:         deviceExtension->PausedM = 0;
                   4181:         deviceExtension->PausedS = 0;
                   4182:         deviceExtension->PausedF = 0;
                   4183:         deviceExtension->LastEndM = 0;
                   4184:         deviceExtension->LastEndS = 0;
                   4185:         deviceExtension->LastEndF = 0;
                   4186: 
                   4187:         //
                   4188:         // Free storage now that we've stored it elsewhere
                   4189:         //
                   4190: 
                   4191:         ExFreePool( Toc );
                   4192:         break;
                   4193: 
                   4194:     case IOCTL_CDROM_STOP_AUDIO:
                   4195: 
                   4196:         deviceExtension->PlayActive = FALSE;
                   4197: 
                   4198:         //
                   4199:         // Kill any current play operation
                   4200:         //
                   4201: 
                   4202:         CdAudioHitatchiSendPauseCommand( DeviceObject );
                   4203: 
                   4204:         //
                   4205:         // Same as scsi-2 spec, so just send to default driver
                   4206:         //
                   4207: 
                   4208:         deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   4209:         deviceExtension->PausedM = 0;
                   4210:         deviceExtension->PausedS = 0;
                   4211:         deviceExtension->PausedF = 0;
                   4212:         deviceExtension->LastEndM = 0;
                   4213:         deviceExtension->LastEndS = 0;
                   4214:         deviceExtension->LastEndF = 0;
                   4215: 
                   4216:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   4217:         break;
                   4218: 
                   4219:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   4220:         {
                   4221: 
                   4222:         PCDROM_PLAY_AUDIO_MSF inputBuffer =
                   4223:             Irp->AssociatedIrp.SystemBuffer;
                   4224: 
                   4225:         CdDump(( 3,
                   4226:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
                   4227:             ));
                   4228: 
                   4229:         //
                   4230:         // Kill any current play operation
                   4231:         //
                   4232: 
                   4233:         CdAudioHitatchiSendPauseCommand( DeviceObject );
                   4234: 
                   4235:         //
                   4236:         // Fill in CDB for PLAY operation
                   4237:         //
                   4238: 
                   4239:         srb.CdbLength                 = 12;
                   4240:         srb.TimeOutValue              = AUDIO_TIMEOUT;
                   4241:         cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
                   4242:         cdb->PLAY_AUDIO.Immediate     = 1;
                   4243:         cdb->PLAY_AUDIO.StartingM     = inputBuffer->StartingM;
                   4244:         cdb->PLAY_AUDIO.StartingS     = inputBuffer->StartingS;
                   4245:         cdb->PLAY_AUDIO.StartingF     = inputBuffer->StartingF;
                   4246:         cdb->PLAY_AUDIO.EndingM       = inputBuffer->EndingM;
                   4247:         cdb->PLAY_AUDIO.EndingS       = inputBuffer->EndingS;
                   4248:         cdb->PLAY_AUDIO.EndingF       = inputBuffer->EndingF;
                   4249:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4250:                                      &srb,
                   4251:                                      NULL,
                   4252:                                      0,
                   4253:                                      FALSE
                   4254:                                     );
                   4255: 
                   4256:         if (NT_SUCCESS(status)) {
                   4257: 
                   4258:             //
                   4259:             // Indicate the play actition is active.
                   4260:             //
                   4261: 
                   4262:             deviceExtension->PlayActive = TRUE;
                   4263: 
                   4264:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   4265: 
                   4266: 
                   4267:             //
                   4268:             // Set last play ending address for next pause command
                   4269:             //
                   4270: 
                   4271:             deviceExtension->PausedM  = inputBuffer->StartingM;
                   4272:             deviceExtension->PausedS  = inputBuffer->StartingS;
                   4273:             deviceExtension->PausedF  = inputBuffer->StartingF;
                   4274:             deviceExtension->LastEndM = inputBuffer->EndingM;
                   4275:             deviceExtension->LastEndS = inputBuffer->EndingS;
                   4276:             deviceExtension->LastEndF = inputBuffer->EndingF;
                   4277: 
                   4278:         } else {
                   4279: 
                   4280:             CdDump(( 3,
                   4281:                 "CdAudioHitatchiDeviceControl: PLAY failed (0x%08lX)\n",
                   4282:                 status ));
                   4283:         }
                   4284: 
                   4285:         }
                   4286:         break;
                   4287: 
                   4288:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   4289:         {
                   4290: 
                   4291:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   4292: 
                   4293:         CdDump(( 3,
                   4294:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   4295:              ));
                   4296: 
                   4297:         //
                   4298:         // Kill any current play operation
                   4299:         //
                   4300: 
                   4301:         CdAudioHitatchiSendPauseCommand( DeviceObject );
                   4302: 
                   4303:         //
                   4304:         // seek to MSF and enter pause (still) mode.
                   4305:         //
                   4306: 
                   4307:         //
                   4308:         // Fill in CDB for PLAY operation
                   4309:         //
                   4310: 
                   4311:         srb.CdbLength                 = 12;
                   4312:         srb.TimeOutValue              = AUDIO_TIMEOUT;
                   4313:         cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
                   4314:         cdb->PLAY_AUDIO.Immediate     = 1;
                   4315:         cdb->PLAY_AUDIO.StartingM     = inputBuffer->M;
                   4316:         cdb->PLAY_AUDIO.StartingS     = inputBuffer->S;
                   4317:         cdb->PLAY_AUDIO.StartingF     = inputBuffer->F;
                   4318:         cdb->PLAY_AUDIO.EndingM       = inputBuffer->M;
                   4319:         cdb->PLAY_AUDIO.EndingS       = inputBuffer->S;
                   4320:         cdb->PLAY_AUDIO.EndingF       = inputBuffer->F;
                   4321: 
                   4322:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4323:                                      &srb,
                   4324:                                      NULL,
                   4325:                                      0,
                   4326:                                      FALSE
                   4327:                                     );
                   4328:         if (NT_SUCCESS(status)) {
                   4329: 
                   4330:             deviceExtension->PausedM = inputBuffer->M;
                   4331:             deviceExtension->PausedS = inputBuffer->S;
                   4332:             deviceExtension->PausedF = inputBuffer->F;
                   4333:             deviceExtension->LastEndM = inputBuffer->M;
                   4334:             deviceExtension->LastEndS = inputBuffer->S;
                   4335:             deviceExtension->LastEndF = inputBuffer->F;
                   4336: 
                   4337:         } else {
                   4338: 
                   4339:             CdDump(( 3,
                   4340:                 "CdAudioHitatchiDeviceControl: SEEK failed (0x%08lX)\n",
                   4341:                 status ));
                   4342:         }
                   4343: 
                   4344:         }
                   4345:         break;
                   4346: 
                   4347:     case IOCTL_CDROM_PAUSE_AUDIO:
                   4348:         {
                   4349: 
                   4350:         PUCHAR PausePos = ExAllocatePool( NonPagedPoolCacheAligned, 3 );
                   4351:         if (PausePos==NULL) {
                   4352: 
                   4353:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4354:             goto SetStatusAndReturn;
                   4355: 
                   4356:         }
                   4357: 
                   4358:         deviceExtension->PlayActive = FALSE;
                   4359: 
                   4360:         RtlZeroMemory( PausePos, 3 );
                   4361: 
                   4362:         CdDump(( 3,
                   4363:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
                   4364:             ));
                   4365: 
                   4366:         //
                   4367:         // Enter pause (still ) mode
                   4368:         //
                   4369: 
                   4370:         srb.CdbLength    = 12;
                   4371:         srb.TimeOutValue = AUDIO_TIMEOUT;
                   4372:         cdb->PAUSE_AUDIO.OperationCode = HITATCHI_PAUSE_AUDIO_CODE;
                   4373:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4374:                                      &srb,
                   4375:                                      PausePos,
                   4376:                                      3,
                   4377:                                      FALSE
                   4378:                                     );
                   4379: 
                   4380:         deviceExtension->Paused = CDAUDIO_PAUSED;
                   4381:         deviceExtension->PausedM = PausePos[0];
                   4382:         deviceExtension->PausedS = PausePos[1];
                   4383:         deviceExtension->PausedF = PausePos[2];
                   4384: 
                   4385:         ExFreePool( PausePos );
                   4386:         }
                   4387:         break;
                   4388: 
                   4389:     case IOCTL_CDROM_RESUME_AUDIO:
                   4390: 
                   4391:         CdDump(( 3,
                   4392:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
                   4393:             ));
                   4394: 
                   4395:         //
                   4396:         // Kill any current play operation
                   4397:         //
                   4398: 
                   4399:         CdAudioHitatchiSendPauseCommand( DeviceObject );
                   4400: 
                   4401:         //
                   4402:         // Resume play
                   4403:         //
                   4404: 
                   4405:         //
                   4406:         // Fill in CDB for PLAY operation
                   4407:         //
                   4408: 
                   4409:         srb.CdbLength    = 12;
                   4410:         srb.TimeOutValue = AUDIO_TIMEOUT;
                   4411:         cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
                   4412:         cdb->PLAY_AUDIO.Immediate     = 1;
                   4413:         cdb->PLAY_AUDIO.StartingM     = deviceExtension->PausedM;
                   4414:         cdb->PLAY_AUDIO.StartingS     = deviceExtension->PausedS;
                   4415:         cdb->PLAY_AUDIO.StartingF     = deviceExtension->PausedF;
                   4416:         cdb->PLAY_AUDIO.EndingM       = deviceExtension->LastEndM;
                   4417:         cdb->PLAY_AUDIO.EndingS       = deviceExtension->LastEndS;
                   4418:         cdb->PLAY_AUDIO.EndingF       = deviceExtension->LastEndF;
                   4419:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4420:                                      &srb,
                   4421:                                      NULL,
                   4422:                                      0,
                   4423:                                      FALSE
                   4424:                                     );
                   4425: 
                   4426:         if (NT_SUCCESS(status)) {
                   4427: 
                   4428:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   4429: 
                   4430:         }
                   4431: 
                   4432:         break;
                   4433: 
                   4434:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   4435:         {
                   4436: 
                   4437:         PSUB_Q_CURRENT_POSITION userPtr =
                   4438:             Irp->AssociatedIrp.SystemBuffer;
                   4439:         PUCHAR SubQPtr =
                   4440:             ExAllocatePool( NonPagedPoolCacheAligned,
                   4441:                             sizeof(SUB_Q_CHANNEL_DATA)
                   4442:                            );
                   4443: 
                   4444:         CdDump(( 5,
                   4445:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   4446:             ));
                   4447: 
                   4448:         if (SubQPtr==NULL) {
                   4449: 
                   4450:             CdDump(( 1,
                   4451:                 "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   4452:                 ));
                   4453: 
                   4454:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4455:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   4456:             goto SetStatusAndReturn;
                   4457: 
                   4458:         }
                   4459: 
                   4460:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   4461:              IOCTL_CDROM_CURRENT_POSITION) {
                   4462: 
                   4463:             CdDump(( 1,
                   4464:                 "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
                   4465:                 ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   4466:                 ));
                   4467: 
                   4468:             ExFreePool( SubQPtr );
                   4469:             status = STATUS_UNSUCCESSFUL;
                   4470:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   4471:             goto SetStatusAndReturn;
                   4472:         }
                   4473: 
                   4474:         //
                   4475:         // Set up to read Q Channel
                   4476:         //
                   4477: 
                   4478:         srb.CdbLength            = 12;
                   4479:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   4480:         cdb->AUDIO_STATUS.OperationCode = HITATCHI_READ_SUB_Q_CHANNEL_CODE;
                   4481:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4482:                                      &srb,
                   4483:                                      SubQPtr,
                   4484:                                      sizeof(SUB_Q_CHANNEL_DATA),
                   4485:                                      FALSE
                   4486:                                     );
                   4487:         if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
                   4488: 
                   4489:             userPtr->Header.Reserved = 0;
                   4490:             if (deviceExtension->Paused == CDAUDIO_PAUSED) {
                   4491:             
                   4492:                 deviceExtension->PlayActive = FALSE;
                   4493:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   4494:             } else {
                   4495:                 if (SubQPtr[0]==0x01)
                   4496:                     userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
                   4497:                 else if (SubQPtr[0]==0x00){
                   4498:                     userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
                   4499:                     deviceExtension->PlayActive = FALSE;
                   4500: 
                   4501:                 } else {
                   4502:                     deviceExtension->PlayActive = FALSE;
                   4503:                 }
                   4504:             }
                   4505:             userPtr->Header.DataLength[0] = 0;
                   4506:             userPtr->Header.DataLength[0] = 12;
                   4507: 
                   4508:             userPtr->FormatCode = 0x01;
                   4509:             userPtr->Control = ((SubQPtr[1] & 0xF0) >> 4);
                   4510:             userPtr->ADR     = SubQPtr[1] & 0x0F;
                   4511:             userPtr->TrackNumber = SubQPtr[2];
                   4512:             userPtr->IndexNumber = SubQPtr[3];
                   4513:             userPtr->AbsoluteAddress[0] = 0;
                   4514:             userPtr->AbsoluteAddress[1] = SubQPtr[8];
                   4515:             userPtr->AbsoluteAddress[2] = SubQPtr[9];
                   4516:             userPtr->AbsoluteAddress[3] = SubQPtr[10];
                   4517:             userPtr->TrackRelativeAddress[0] = 0;
                   4518:             userPtr->TrackRelativeAddress[1] = SubQPtr[4];
                   4519:             userPtr->TrackRelativeAddress[2] = SubQPtr[5];
                   4520:             userPtr->TrackRelativeAddress[3] = SubQPtr[6];
                   4521:             Irp->IoStatus.Information = 16;
                   4522:             status = STATUS_SUCCESS;
                   4523: 
                   4524:         } else {
                   4525: 
                   4526:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   4527:             CdDump(( 1,
                   4528:                 "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
                   4529:                 status
                   4530:                 ));
                   4531: 
                   4532:         }
                   4533: 
                   4534:         ExFreePool( SubQPtr );
                   4535: 
                   4536:         }
                   4537:         break;
                   4538: 
                   4539:     case IOCTL_CDROM_EJECT_MEDIA:
                   4540:         {
                   4541: 
                   4542:         PUCHAR EjectStatus = ExAllocatePool( NonPagedPoolCacheAligned, 1 );
                   4543: 
                   4544:         if (EjectStatus==NULL) {
                   4545: 
                   4546:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4547:             goto SetStatusAndReturn;
                   4548: 
                   4549:         }
                   4550: 
                   4551:         deviceExtension->PlayActive = FALSE;
                   4552: 
                   4553:         CdDump(( 3,
                   4554:             "CdAudioHitatchiDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   4555:             ));
                   4556: 
                   4557:         //
                   4558:         // Set up to EJECT disc
                   4559:         //
                   4560: 
                   4561:         srb.CdbLength            = 12;
                   4562:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   4563:         cdb->EJECT.OperationCode = HITATCHI_EJECT_CODE;
                   4564:         cdb->EJECT.Eject         = 1;  // Set Eject flag
                   4565:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4566:                                      &srb,
                   4567:                                      EjectStatus,
                   4568:                                      1,
                   4569:                                      FALSE
                   4570:                                     );
                   4571:         if (NT_SUCCESS(status)) {
                   4572: 
                   4573:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   4574:             deviceExtension->PausedM = 0;
                   4575:             deviceExtension->PausedS = 0;
                   4576:             deviceExtension->PausedF = 0;
                   4577:             deviceExtension->LastEndM = 0;
                   4578:             deviceExtension->LastEndS = 0;
                   4579:             deviceExtension->LastEndF = 0;
                   4580: 
                   4581:         }
                   4582: 
                   4583:         ExFreePool( EjectStatus );
                   4584:         }
                   4585:         break;
                   4586: 
                   4587:     case IOCTL_CDROM_GET_CONTROL:
                   4588:     case IOCTL_CDROM_GET_VOLUME:
                   4589:     case IOCTL_CDROM_SET_VOLUME:
                   4590: 
                   4591:         CdDump(( 3, "CdAudioHitatchieviceControl: Not Supported yet.\n" ));
                   4592:         status = STATUS_INVALID_DEVICE_REQUEST;
                   4593:         break;
                   4594: 
                   4595:     case IOCTL_CDROM_CHECK_VERIFY:
                   4596: 
                   4597:         //
                   4598:         // Update the play active flag.
                   4599:         //
                   4600: 
                   4601:         CdAudioIsPlayActive(DeviceObject);
                   4602: 
                   4603:     default:
                   4604: 
                   4605:         CdDump((5,"CdAudioHitatchiDeviceControl: Unsupported device IOCTL\n"));
                   4606:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   4607:         break;
                   4608: 
                   4609:     } // end switch( IOCTL )
                   4610: 
                   4611: SetStatusAndReturn:
                   4612: 
                   4613:     //
                   4614:     // set status code and return
                   4615:     //
                   4616: 
                   4617:     if (status == STATUS_VERIFY_REQUIRED) {
                   4618: 
                   4619:         //
                   4620:         // If the status is verified required and the this request
                   4621:         // should bypass verify required then retry the request.
                   4622:         //
                   4623: 
                   4624:         if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
                   4625: 
                   4626:             status = STATUS_IO_DEVICE_ERROR;
                   4627:             goto HitatchiRestart;
                   4628: 
                   4629:         }
                   4630: 
                   4631: 
                   4632:         IoSetHardErrorOrVerifyDevice( Irp,
                   4633:                                       deviceExtension->TargetDeviceObject
                   4634:                                      );
                   4635: 
                   4636:         Irp->IoStatus.Information = 0;
                   4637:     }
                   4638: 
                   4639:     Irp->IoStatus.Status = status;
                   4640:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   4641:     return status;
                   4642: 
                   4643: }
                   4644: 
                   4645: NTSTATUS
                   4646: CdAudio535DeviceControl(
                   4647:     PDEVICE_OBJECT DeviceObject,
                   4648:     PIRP Irp
                   4649:     )
                   4650: 
                   4651: /*++
                   4652: 
                   4653: Routine Description:
                   4654: 
                   4655:     This routine is called by CdAudioDeviceControl to handle
                   4656:     audio IOCTLs sent to Chinon CDS-535 cdrom drive.
                   4657: 
                   4658: Arguments:
                   4659: 
                   4660:     DeviceObject
                   4661:     Irp
                   4662: 
                   4663: Return Value:
                   4664: 
                   4665:     NTSTATUS
                   4666: 
                   4667: --*/
                   4668: 
                   4669: {
                   4670:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   4671:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   4672:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   4673:     SCSI_REQUEST_BLOCK srb;
                   4674:     PREAD_CAPACITY_DATA lastSession;
                   4675:     PCDB               cdb = (PCDB)srb.Cdb;
                   4676:     NTSTATUS           status;
                   4677:     ULONG              i,bytesTransfered;
                   4678:     PUCHAR             Toc;
                   4679:     ULONG              retry;
                   4680:     ULONG              destblock;
                   4681: 
                   4682: 
                   4683:     //
                   4684:     // Clear out cdb
                   4685:     //
                   4686: 
                   4687:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   4688: 
                   4689:     //
                   4690:     // What IOCTL do we need to execute?
                   4691:     //
                   4692: 
                   4693:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   4694: 
                   4695:     case IOCTL_CDROM_GET_LAST_SESSION:
                   4696: 
                   4697:         //
                   4698:         // If the cd is playing music then reject this request.
                   4699:         //
                   4700: 
                   4701:         if (CdAudioIsPlayActive(DeviceObject)) {
                   4702:             status = STATUS_DEVICE_BUSY;
                   4703:             break;
                   4704:         }
                   4705: 
                   4706:         if (currentIrpStack->Parameters.Read.Length <
                   4707:             FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
                   4708:             status = STATUS_INFO_LENGTH_MISMATCH;
                   4709:             break;
                   4710:             
                   4711:         }
                   4712: 
                   4713:         // Allocate storage to hold lastSession from disc
                   4714:         //
                   4715: 
                   4716:         lastSession = ExAllocatePool( NonPagedPoolCacheAligned,
                   4717:                                       sizeof(READ_CAPACITY_DATA)
                   4718:                                      );
                   4719: 
                   4720:         if (lastSession==NULL) {
                   4721: 
                   4722:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4723:             goto SetStatusAndReturn;
                   4724: 
                   4725:         }
                   4726: 
                   4727:         //
                   4728:         // Set up defaults
                   4729:         //
                   4730: 
                   4731:         RtlZeroMemory( lastSession, sizeof(READ_CAPACITY_DATA));
                   4732:         srb.CdbLength = 10;
                   4733: 
                   4734:         //
                   4735:         // Fill in CDB
                   4736:         //
                   4737: 
                   4738:         cdb->CDB10.OperationCode = CDS535_GET_LAST_SESSION;
                   4739:         srb.TimeOutValue      = AUDIO_TIMEOUT;
                   4740:         status = ScsiClassSendSrbSynchronous(
                   4741:                                      deviceExtension->DeviceObject,
                   4742:                                      &srb,
                   4743:                                      lastSession,
                   4744:                                      sizeof(READ_CAPACITY_DATA),
                   4745:                                      FALSE
                   4746:                                     );
                   4747: 
                   4748:         if (!NT_SUCCESS(status)) {
                   4749: 
                   4750:             CdDump(( 1,
                   4751:                 "CdAudio535DeviceControl: READ_TOC error (0x%08lX)\n",
                   4752:                  status ));
                   4753: 
                   4754: 
                   4755:             ExFreePool( lastSession );
                   4756:             goto SetStatusAndReturn;
                   4757: 
                   4758:         } else {
                   4759: 
                   4760:             status = STATUS_SUCCESS;
                   4761:         }
                   4762: 
                   4763:         //
                   4764:         // Translate data into our format.
                   4765:         //
                   4766: 
                   4767:         bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
                   4768:         Irp->IoStatus.Information = bytesTransfered;
                   4769: 
                   4770:         RtlZeroMemory(cdaudioDataOut, bytesTransfered);
                   4771:         
                   4772:         cdaudioDataOut->Length[0]  = bytesTransfered >> 8;
                   4773:         cdaudioDataOut->Length[1]  = (bytesTransfered & 0xFF);
                   4774: 
                   4775:         //
                   4776:         // Determine if this is a multisession cd.
                   4777:         //
                   4778: 
                   4779:         if (lastSession->LogicalBlockAddress == 0) {
                   4780: 
                   4781:             //
                   4782:             // This is a single session disk.  Just return.
                   4783:             //
                   4784: 
                   4785:             ExFreePool(lastSession);
                   4786:             break;
                   4787:         }
                   4788: 
                   4789:         //
                   4790:         // Fake the session information.
                   4791:         //
                   4792:         
                   4793:         cdaudioDataOut->FirstTrack = 1;
                   4794:         cdaudioDataOut->LastTrack  = 2;
                   4795: 
                   4796:         CdDump(( 4,
                   4797:                      "CdAudio535DeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
                   4798:                      cdaudioDataOut->FirstTrack,
                   4799:                      cdaudioDataOut->LastTrack,
                   4800:                      bytesTransfered
                   4801:                      ));
                   4802: 
                   4803: 
                   4804:         //
                   4805:         // Grab Information for the last session.
                   4806:         //
                   4807: 
                   4808:         *((ULONG *)&cdaudioDataOut->TrackData[0].Address[0]) =
                   4809:             lastSession->LogicalBlockAddress;
                   4810: 
                   4811:         //
                   4812:         // Free storage now that we've stored it elsewhere
                   4813:         //
                   4814: 
                   4815:         ExFreePool( lastSession );
                   4816:         break;
                   4817: 
                   4818: 
                   4819:     case IOCTL_CDROM_READ_TOC:
                   4820:         CdDump(( 3,
                   4821:                      "CdAudio535DeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   4822:                      ));
                   4823: 
                   4824: 
                   4825:         //
                   4826:         // If the cd is playing music then reject this request.
                   4827:         //
                   4828: 
                   4829:         if (CdAudioIsPlayActive(DeviceObject)) {
                   4830:             status = STATUS_DEVICE_BUSY;
                   4831:             break;
                   4832:         }
                   4833: 
                   4834:         //
                   4835:         // Allocate storage to hold TOC from disc
                   4836:         //
                   4837: 
                   4838:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   4839:                                       CDROM_TOC_SIZE
                   4840:                                      );
                   4841: 
                   4842:         if (Toc==NULL) {
                   4843: 
                   4844:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4845:             goto SetStatusAndReturn;
                   4846: 
                   4847:         }
                   4848: 
                   4849:         //
                   4850:         // Set up defaults
                   4851:         //
                   4852: 
                   4853:         RtlZeroMemory( Toc, CDROM_TOC_SIZE );
                   4854: 
                   4855:         //
                   4856:         // Fill in cdb for this operation
                   4857:         //
                   4858: 
                   4859:         cdb->CDB10.OperationCode = CDS535_READ_TOC_CODE;
                   4860:         cdb->CDB10.Reserved1 = 1;       // MSF mode
                   4861:         cdb->CDB10.TransferBlocksMsb = (CDROM_TOC_SIZE >> 8);
                   4862:         cdb->CDB10.TransferBlocksLsb = (CDROM_TOC_SIZE & 0xFF);
                   4863:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   4864:         srb.CdbLength                  = 10;
                   4865:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4866:                                      &srb,
                   4867:                                      Toc,
                   4868:                                      CDROM_TOC_SIZE,
                   4869:                                      FALSE
                   4870:                                     );
                   4871: 
                   4872:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   4873: 
                   4874:             CdDump(( 1,
                   4875:                 "CdAudio535DeviceControl: READ_TOC error (0x%08lX)\n",
                   4876:                  status ));
                   4877: 
                   4878:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   4879: 
                   4880:                 CdDump(( 1, "CdAudio535DeviceControl: SRB ERROR (0x%lX)\n",
                   4881:                              srb.SrbStatus ));
                   4882:                 ExFreePool( Toc );
                   4883:                 goto SetStatusAndReturn;
                   4884:             }
                   4885: 
                   4886:         } else {
                   4887: 
                   4888:             status = STATUS_SUCCESS;
                   4889:         }
                   4890: 
                   4891:         //
                   4892:         // Translate data into SCSI-II format
                   4893:         //   (track numbers, except 0xAA, must be converted from BCD)
                   4894: 
                   4895:         bytesTransfered =
                   4896:             currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
                   4897:             sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
                   4898:         Irp->IoStatus.Information  = bytesTransfered;
                   4899: 
                   4900:         cdaudioDataOut->Length[0]  = Toc[0];
                   4901:         cdaudioDataOut->Length[1]  = Toc[1];
                   4902:         cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
                   4903:         cdaudioDataOut->LastTrack  = BCD_TO_DEC(Toc[3]);
                   4904: 
                   4905:         for( i=0;
                   4906:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   4907:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   4908:              i++
                   4909:             ) {
                   4910: 
                   4911:             //
                   4912:             // Grab Information for each track
                   4913:             //
                   4914: 
                   4915:             cdaudioDataOut->TrackData[i].Reserved    = 0;
                   4916:             cdaudioDataOut->TrackData[i].Control     = Toc[(i*8)+4+1];
                   4917:             cdaudioDataOut->TrackData[i].TrackNumber = BCD_TO_DEC(Toc[(i*8)+4+2]);
                   4918:             cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   4919:             cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   4920:             cdaudioDataOut->TrackData[i].Address[1]  = Toc[(i*8)+4+5];
                   4921:             cdaudioDataOut->TrackData[i].Address[2]  = Toc[(i*8)+4+6];
                   4922:             cdaudioDataOut->TrackData[i].Address[3]  = Toc[(i*8)+4+7];
                   4923: 
                   4924:         }
                   4925: 
                   4926:         //
                   4927:         // Copy "lead out track" info
                   4928:         //
                   4929: 
                   4930:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   4931:         cdaudioDataOut->TrackData[i].Control     = Toc[(i*8)+4+1];
                   4932:         cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2];  /* leave as 0xAA */
                   4933:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   4934:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   4935:         cdaudioDataOut->TrackData[i].Address[1]  = Toc[(i*8)+4+5];
                   4936:         cdaudioDataOut->TrackData[i].Address[2]  = Toc[(i*8)+4+6];
                   4937:         cdaudioDataOut->TrackData[i].Address[3]  = Toc[(i*8)+4+7];
                   4938: 
                   4939:         //
                   4940:         // Free storage now that we've stored it elsewhere
                   4941:         //
                   4942: 
                   4943:         ExFreePool( Toc );
                   4944:         break;
                   4945: 
                   4946:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   4947:         {
                   4948:         PSUB_Q_CURRENT_POSITION userPtr =
                   4949:             Irp->AssociatedIrp.SystemBuffer;
                   4950:         PUCHAR SubQPtr =
                   4951:             ExAllocatePool( NonPagedPoolCacheAligned,
                   4952:                             sizeof(SUB_Q_CURRENT_POSITION)
                   4953:                            );
                   4954: 
                   4955:         CdDump(( 5,
                   4956:                      "CdAudio535DeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   4957:                      ));
                   4958: 
                   4959:         if (SubQPtr==NULL) {
                   4960: 
                   4961:             CdDump(( 1,
                   4962:                          "CdAudio535DeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   4963:                          ));
                   4964: 
                   4965:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   4966:             status = STATUS_INSUFFICIENT_RESOURCES;
                   4967:             goto SetStatusAndReturn;
                   4968: 
                   4969:         }
                   4970: 
                   4971:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   4972:              IOCTL_CDROM_CURRENT_POSITION) {
                   4973: 
                   4974:             CdDump(( 1,
                   4975:                          "CdAudio535DeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
                   4976:                          ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   4977:                          ));
                   4978: 
                   4979:             ExFreePool( SubQPtr );
                   4980:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   4981:             status = STATUS_UNSUCCESSFUL;
                   4982:             goto SetStatusAndReturn;
                   4983:         }
                   4984: 
                   4985:         //
                   4986:         // Get Current Position
                   4987:         //
                   4988: 
                   4989:         srb.CdbLength            = 10;
                   4990:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   4991:         cdb->SUBCHANNEL.OperationCode = CDS535_READ_SUB_Q_CHANNEL_CODE;
                   4992:         cdb->SUBCHANNEL.Msf = 1;
                   4993:         cdb->SUBCHANNEL.SubQ = 1;
                   4994:         cdb->SUBCHANNEL.Format = 1;
                   4995:         cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CURRENT_POSITION);
                   4996:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   4997:                                      &srb,
                   4998:                                      SubQPtr,
                   4999:                                      sizeof(SUB_Q_CURRENT_POSITION),
                   5000:                                      FALSE
                   5001:                                     );
                   5002: 
                   5003:         //
                   5004:         // Copy current position, converting track and index from BCD
                   5005:         //
                   5006: 
                   5007:         if (NT_SUCCESS(status)) {
                   5008:             if(SubQPtr[1] == 0x11) deviceExtension->PlayActive = TRUE;
                   5009:             else deviceExtension->PlayActive = FALSE;
                   5010: 
                   5011:             userPtr->Header.Reserved = 0;
                   5012:             userPtr->Header.AudioStatus = SubQPtr[1];
                   5013:             userPtr->Header.DataLength[0] = 0;
                   5014:             userPtr->Header.DataLength[1] = 12;
                   5015:             userPtr->FormatCode = 0x01;
                   5016:             userPtr->Control = SubQPtr[5];
                   5017:             userPtr->ADR     = 0;
                   5018:             userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
                   5019:             userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
                   5020:             userPtr->AbsoluteAddress[0] = 0;
                   5021:             userPtr->AbsoluteAddress[1] = SubQPtr[9];
                   5022:             userPtr->AbsoluteAddress[2] = SubQPtr[10];
                   5023:             userPtr->AbsoluteAddress[3] = SubQPtr[11];
                   5024:             userPtr->TrackRelativeAddress[0] = 0;
                   5025:             userPtr->TrackRelativeAddress[1] = SubQPtr[13];
                   5026:             userPtr->TrackRelativeAddress[2] = SubQPtr[14];
                   5027:             userPtr->TrackRelativeAddress[3] = SubQPtr[15];
                   5028:             Irp->IoStatus.Information = 16;
                   5029:         } else {
                   5030:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   5031:             CdDump(( 1,
                   5032:                          "CdAudio535DeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
                   5033:                          status
                   5034:                          ));
                   5035:         }
                   5036: 
                   5037:         ExFreePool( SubQPtr );
                   5038:         }
                   5039:         break;
                   5040: 
                   5041:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   5042: 
                   5043:         {
                   5044:             PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   5045: 
                   5046:             //
                   5047:             // Play Audio MSF
                   5048:             //
                   5049: 
                   5050:             DebugPrint((2,"ScsiCdRomDeviceControl: Play audio MSF\n"));
                   5051: 
                   5052:             if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
                   5053:                 sizeof(CDROM_PLAY_AUDIO_MSF)) {
                   5054: 
                   5055:                 //
                   5056:                 // Indicate unsuccessful status.
                   5057:                 //
                   5058: 
                   5059:                 status = STATUS_BUFFER_TOO_SMALL;
                   5060:                 break;
                   5061:             }
                   5062: 
                   5063:             if (inputBuffer->StartingM == inputBuffer->EndingM &&
                   5064:                 inputBuffer->StartingS == inputBuffer->EndingS &&
                   5065:                 inputBuffer->StartingF == inputBuffer->EndingF) {
                   5066:                 
                   5067:                 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
                   5068:                 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
                   5069: 
                   5070:             } else {
                   5071:                 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
                   5072:     
                   5073:                 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
                   5074:                 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
                   5075:                 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
                   5076:     
                   5077:                 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
                   5078:                 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
                   5079:                 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
                   5080:     
                   5081:             }
                   5082: 
                   5083:             srb.CdbLength = 10;
                   5084: 
                   5085:             //
                   5086:             // Set timeout value.
                   5087:             //
                   5088: 
                   5089:             srb.TimeOutValue             = AUDIO_TIMEOUT;
                   5090: 
                   5091:             status = ScsiClassSendSrbSynchronous(DeviceObject,
                   5092:                           &srb,
                   5093:                           NULL,
                   5094:                           0,
                   5095:                           FALSE);
                   5096: 
                   5097:             if (NT_SUCCESS(status) &&
                   5098:                 cdb->PLAY_AUDIO_MSF.OperationCode == SCSIOP_PLAY_AUDIO_MSF) {
                   5099:                 deviceExtension->PlayActive = TRUE;
                   5100:             }
                   5101:         }
                   5102: 
                   5103:         break;
                   5104: 
                   5105:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   5106:         {
                   5107: 
                   5108:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   5109: 
                   5110:         CdDump(( 3,
                   5111:             "CdAudio535DeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   5112:             ));
                   5113: 
                   5114:         //
                   5115:         // Use the data seek command to move the pickup
                   5116:         // BUGBUG: blithely assumes logical block size == 2048 bytes
                   5117:         //
                   5118: 
                   5119:         destblock = ((((ULONG)(inputBuffer->M) * 60)
                   5120:                     + (ULONG)(inputBuffer->S)) * 75)
                   5121:                     + (ULONG)(inputBuffer->F)
                   5122:                     - 150;
                   5123: 
                   5124:         srb.CdbLength                = 10;
                   5125:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   5126:         cdb->SEEK.OperationCode      = SCSIOP_SEEK;
                   5127:         cdb->SEEK.LogicalBlockAddress[0] = (destblock >> 24) & 0xFF;
                   5128:         cdb->SEEK.LogicalBlockAddress[1] = (destblock >> 16) & 0xFF;
                   5129:         cdb->SEEK.LogicalBlockAddress[2] = (destblock >>  8) & 0xFF;
                   5130:         cdb->SEEK.LogicalBlockAddress[3] = destblock & 0xFF;
                   5131:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5132:                                      &srb,
                   5133:                                      NULL,
                   5134:                                      0,
                   5135:                                      FALSE
                   5136:                                     );
                   5137: 
                   5138:         if (!NT_SUCCESS(status)) {
                   5139: 
                   5140:             CdDump(( 3,
                   5141:                 "CdAudio535DeviceControl: SEEK failed (0x%08lX)\n",
                   5142:                 status ));
                   5143: 
                   5144:         }
                   5145:         }
                   5146:         break;
                   5147: 
                   5148:     case IOCTL_CDROM_EJECT_MEDIA:
                   5149: 
                   5150:         //
                   5151:         // Build cdb to eject cartridge
                   5152:         //
                   5153: 
                   5154:         CdDump(( 3,
                   5155:                      "CdAudio535DeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   5156:                      ));
                   5157: 
                   5158:         deviceExtension->PlayActive = FALSE;
                   5159: 
                   5160:         srb.CdbLength                  = 10;
                   5161:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   5162:         cdb->CDB10.OperationCode = CDS535_EJECT_CODE;
                   5163:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5164:                                      &srb,
                   5165:                                      NULL,
                   5166:                                      0,
                   5167:                                      FALSE
                   5168:                                     );
                   5169:         break;
                   5170: 
                   5171:     case IOCTL_CDROM_GET_CONTROL:
                   5172:     case IOCTL_CDROM_GET_VOLUME:
                   5173:     case IOCTL_CDROM_SET_VOLUME:
                   5174:         CdDump(( 3, "CdAudio535DeviceControl: Not Supported yet.\n" ));
                   5175:         status = STATUS_INVALID_DEVICE_REQUEST;
                   5176:         break;
                   5177: 
                   5178:     case IOCTL_CDROM_CHECK_VERIFY:
                   5179: 
                   5180:         //
                   5181:         // Update the play active flag.
                   5182:         //
                   5183: 
                   5184:         CdAudioIsPlayActive(DeviceObject);
                   5185: 
                   5186:     default:
                   5187: 
                   5188:         CdDump((5,"ChCdAudio535DeviceControl: Unsupported device IOCTL\n"));
                   5189:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   5190:         break;
                   5191: 
                   5192:     } // end switch( IOCTL )
                   5193: 
                   5194: SetStatusAndReturn:
                   5195:     //
                   5196:     // set status code and return
                   5197:     //
                   5198: 
                   5199:     if (status == STATUS_VERIFY_REQUIRED) {
                   5200: 
                   5201:         IoSetHardErrorOrVerifyDevice( Irp,
                   5202:                                       deviceExtension->TargetDeviceObject
                   5203:                                      );
                   5204: 
                   5205:         Irp->IoStatus.Information = 0;
                   5206:     }
                   5207: 
                   5208:     Irp->IoStatus.Status = status;
                   5209:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   5210:     return status;
                   5211: 
                   5212: }
                   5213: 
                   5214: 
                   5215: NTSTATUS
                   5216: CdAudio435DeviceControl(
                   5217:     PDEVICE_OBJECT DeviceObject,
                   5218:     PIRP Irp
                   5219:     )
                   5220: 
                   5221: /*++
                   5222: 
                   5223: Routine Description:
                   5224: 
                   5225:     This routine is called by CdAudioDeviceControl to handle
                   5226:     audio IOCTLs sent to Chinon CDS-435 cdrom drive.
                   5227: 
                   5228: Arguments:
                   5229: 
                   5230:     DeviceObject
                   5231:     Irp
                   5232: 
                   5233: Return Value:
                   5234: 
                   5235:     NTSTATUS
                   5236: 
                   5237: --*/
                   5238: 
                   5239: {
                   5240:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
                   5241:     PCD_DEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
                   5242:     PCDROM_TOC         cdaudioDataOut  = Irp->AssociatedIrp.SystemBuffer;
                   5243:     SCSI_REQUEST_BLOCK srb;
                   5244:     PCDB               cdb = (PCDB)srb.Cdb;
                   5245:     NTSTATUS           status;
                   5246:     ULONG              i,bytesTransfered;
                   5247:     PUCHAR             Toc;
                   5248: 
                   5249:     //
                   5250:     // Clear out cdb
                   5251:     //
                   5252: 
                   5253:     RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   5254: 
                   5255:     //
                   5256:     // What IOCTL do we need to execute?
                   5257:     //
                   5258: 
                   5259:     switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
                   5260: 
                   5261:     case IOCTL_CDROM_READ_TOC:
                   5262:         CdDump(( 3,
                   5263:                      "CdAudio435DeviceControl: IOCTL_CDROM_READ_TOC received.\n"
                   5264:                      ));
                   5265: 
                   5266: 
                   5267:         //
                   5268:         // If the cd is playing music then reject this request.
                   5269:         //
                   5270: 
                   5271:         if (CdAudioIsPlayActive(DeviceObject)) {
                   5272:             status = STATUS_DEVICE_BUSY;
                   5273:             break;
                   5274:         }
                   5275: 
                   5276:         //
                   5277:         // Allocate storage to hold TOC from disc
                   5278:         //
                   5279: 
                   5280:         Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
                   5281:                                       CDROM_TOC_SIZE
                   5282:                                      );
                   5283: 
                   5284:         if (Toc==NULL) {
                   5285: 
                   5286:             status = STATUS_INSUFFICIENT_RESOURCES;
                   5287:             goto SetStatusAndReturn;
                   5288: 
                   5289:         }
                   5290: 
                   5291:         //
                   5292:         // Set up defaults
                   5293:         //
                   5294: 
                   5295:         RtlZeroMemory( Toc, CDROM_TOC_SIZE );
                   5296: 
                   5297:         //
                   5298:         // Fill in cdb for this operation
                   5299:         //
                   5300: 
                   5301:         cdb->READ_TOC.OperationCode = CDS435_READ_TOC_CODE;
                   5302:         cdb->READ_TOC.Msf = 1;
                   5303:         cdb->READ_TOC.AllocationLength[0] = (CDROM_TOC_SIZE >> 8);
                   5304:         cdb->READ_TOC.AllocationLength[1] = (CDROM_TOC_SIZE & 0xFF);
                   5305:         srb.TimeOutValue                  = AUDIO_TIMEOUT;
                   5306:         srb.CdbLength                     = 10;
                   5307:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5308:                                      &srb,
                   5309:                                      Toc,
                   5310:                                      CDROM_TOC_SIZE,
                   5311:                                      FALSE
                   5312:                                     );
                   5313: 
                   5314:         if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
                   5315: 
                   5316:             CdDump(( 1,
                   5317:                 "CdAudio435DeviceControl: READ_TOC error (0x%08lX)\n",
                   5318:                  status ));
                   5319: 
                   5320:             if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
                   5321: 
                   5322:                 CdDump(( 1, "CdAudio435DeviceControl: SRB ERROR (0x%lX)\n",
                   5323:                              srb.SrbStatus ));
                   5324:                 ExFreePool( Toc );
                   5325:                 goto SetStatusAndReturn;
                   5326:             }
                   5327: 
                   5328:         } else {
                   5329: 
                   5330:             status = STATUS_SUCCESS;
                   5331:         }
                   5332: 
                   5333:         //
                   5334:         // Translate data into SCSI-II format
                   5335:         //   (track numbers, except 0xAA, must be converted from BCD)
                   5336: 
                   5337:         bytesTransfered =
                   5338:             currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
                   5339:             sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
                   5340:         Irp->IoStatus.Information  = bytesTransfered;
                   5341: 
                   5342:         cdaudioDataOut->Length[0]  = Toc[0];
                   5343:         cdaudioDataOut->Length[1]  = Toc[1];
                   5344:         cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
                   5345:         cdaudioDataOut->LastTrack  = BCD_TO_DEC(Toc[3]);
                   5346: 
                   5347:         for( i=0;
                   5348:              i<=( (ULONG)cdaudioDataOut->LastTrack -
                   5349:                   (ULONG)cdaudioDataOut->FirstTrack   );
                   5350:              i++
                   5351:             ) {
                   5352: 
                   5353:             //
                   5354:             // Grab Information for each track
                   5355:             //
                   5356: 
                   5357:             cdaudioDataOut->TrackData[i].Reserved    = 0;
                   5358:             cdaudioDataOut->TrackData[i].Control     = Toc[(i*8)+4+1];
                   5359:             cdaudioDataOut->TrackData[i].TrackNumber = BCD_TO_DEC(Toc[(i*8)+4+2]);
                   5360:             cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   5361:             cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   5362:             cdaudioDataOut->TrackData[i].Address[1]  = Toc[(i*8)+4+5];
                   5363:             cdaudioDataOut->TrackData[i].Address[2]  = Toc[(i*8)+4+6];
                   5364:             cdaudioDataOut->TrackData[i].Address[3]  = Toc[(i*8)+4+7];
                   5365: 
                   5366:         }
                   5367: 
                   5368:         //
                   5369:         // Copy "lead out track" info
                   5370:         //
                   5371: 
                   5372:         cdaudioDataOut->TrackData[i].Reserved    = 0;
                   5373:         cdaudioDataOut->TrackData[i].Control     = Toc[(i*8)+4+1];
                   5374:         cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2];  /* leave as 0xAA */
                   5375:         cdaudioDataOut->TrackData[i].Reserved1   = 0;
                   5376:         cdaudioDataOut->TrackData[i].Address[0]  = 0;
                   5377:         cdaudioDataOut->TrackData[i].Address[1]  = Toc[(i*8)+4+5];
                   5378:         cdaudioDataOut->TrackData[i].Address[2]  = Toc[(i*8)+4+6];
                   5379:         cdaudioDataOut->TrackData[i].Address[3]  = Toc[(i*8)+4+7];
                   5380: 
                   5381:         //
                   5382:         // Clear out deviceExtension data
                   5383:         //
                   5384: 
                   5385:         deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   5386:         deviceExtension->PausedM = 0;
                   5387:         deviceExtension->PausedS = 0;
                   5388:         deviceExtension->PausedF = 0;
                   5389:         deviceExtension->LastEndM = 0;
                   5390:         deviceExtension->LastEndS = 0;
                   5391:         deviceExtension->LastEndF = 0;
                   5392: 
                   5393:         //
                   5394:         // Free storage now that we've stored it elsewhere
                   5395:         //
                   5396: 
                   5397:         ExFreePool( Toc );
                   5398:         break;
                   5399: 
                   5400:     case IOCTL_CDROM_PLAY_AUDIO_MSF:
                   5401:     case IOCTL_CDROM_STOP_AUDIO:
                   5402:         {
                   5403: 
                   5404:         PCDROM_PLAY_AUDIO_MSF inputBuffer =
                   5405:             Irp->AssociatedIrp.SystemBuffer;
                   5406: 
                   5407:         srb.CdbLength                  = 10;
                   5408:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   5409:         cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
                   5410:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5411:                                      &srb,
                   5412:                                      NULL,
                   5413:                                      0,
                   5414:                                      FALSE
                   5415:                                     );
                   5416: 
                   5417:         if (NT_SUCCESS(status)) {
                   5418: 
                   5419:             deviceExtension->PlayActive = FALSE;
                   5420: 
                   5421:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   5422:             deviceExtension->PausedM = 0;
                   5423:             deviceExtension->PausedS = 0;
                   5424:             deviceExtension->PausedF = 0;
                   5425:             deviceExtension->LastEndM = 0;
                   5426:             deviceExtension->LastEndS = 0;
                   5427:             deviceExtension->LastEndF = 0;
                   5428: 
                   5429:         } else {
                   5430: 
                   5431:             CdDump(( 3,
                   5432:                 "CdAudio435DeviceControl: STOP failed (0x%08lX)\n",
                   5433:                 status ));
                   5434: 
                   5435:         }
                   5436: 
                   5437: 
                   5438:         if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
                   5439:             IOCTL_CDROM_STOP_AUDIO
                   5440:            ) {
                   5441: 
                   5442:             CdDump(( 3,
                   5443:                          "CdAudio435DeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
                   5444:                          ));
                   5445: 
                   5446:             goto SetStatusAndReturn;
                   5447: 
                   5448:         }
                   5449: 
                   5450:         CdDump(( 3,
                   5451:             "CdAudio435DeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
                   5452:             ));
                   5453: 
                   5454:         //
                   5455:         // Fill in cdb for this operation
                   5456:         //
                   5457: 
                   5458:         srb.CdbLength                = 10;
                   5459:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   5460:         cdb->PLAY_AUDIO_MSF.OperationCode     = CDS435_PLAY_AUDIO_EXTENDED_CODE;
                   5461:         cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
                   5462:         cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
                   5463:         cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
                   5464:         cdb->PLAY_AUDIO_MSF.EndingM   = inputBuffer->EndingM;
                   5465:         cdb->PLAY_AUDIO_MSF.EndingS   = inputBuffer->EndingS;
                   5466:         cdb->PLAY_AUDIO_MSF.EndingF   = inputBuffer->EndingF;
                   5467:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5468:                                      &srb,
                   5469:                                      NULL,
                   5470:                                      0,
                   5471:                                      FALSE
                   5472:                                     );
                   5473: 
                   5474:         if (NT_SUCCESS(status)) {
                   5475: 
                   5476:             deviceExtension->PlayActive = TRUE;
                   5477: 
                   5478:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   5479: 
                   5480:             //
                   5481:             // Set last play ending address for next pause command
                   5482:             //
                   5483: 
                   5484:             deviceExtension->LastEndM = inputBuffer->EndingM;
                   5485:             deviceExtension->LastEndS = inputBuffer->EndingS;
                   5486:             deviceExtension->LastEndF = inputBuffer->EndingF;
                   5487:             CdDump(( 3,
                   5488:                 "CdAudio435DeviceControl: PLAY  ==> BcdLastEnd set to (%x %x %x)\n",
                   5489:                 deviceExtension->LastEndM,
                   5490:                 deviceExtension->LastEndS,
                   5491:                 deviceExtension->LastEndF ));
                   5492: 
                   5493:         } else {
                   5494: 
                   5495:             CdDump(( 3,
                   5496:                 "CdAudio435DeviceControl: PLAY failed (0x%08lX)\n",
                   5497:                 status ));
                   5498: 
                   5499:         }
                   5500:         }
                   5501:         break;
                   5502: 
                   5503:     case IOCTL_CDROM_SEEK_AUDIO_MSF:
                   5504:         {
                   5505: 
                   5506:         PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
                   5507: 
                   5508:         CdDump(( 3,
                   5509:             "CdAudio435DeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
                   5510:             ));
                   5511: 
                   5512:         //
                   5513:         // Fill in cdb for this operation
                   5514:         //
                   5515: 
                   5516:         srb.CdbLength                = 10;
                   5517:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   5518:         cdb->CDB10.OperationCode     = CDS435_PLAY_AUDIO_EXTENDED_CODE;
                   5519:         cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->M;
                   5520:         cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->S;
                   5521:         cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->F;
                   5522:         cdb->PLAY_AUDIO_MSF.EndingM   = inputBuffer->M;
                   5523:         cdb->PLAY_AUDIO_MSF.EndingS   = inputBuffer->S;
                   5524:         cdb->PLAY_AUDIO_MSF.EndingF   = inputBuffer->F;
                   5525:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5526:                                      &srb,
                   5527:                                      NULL,
                   5528:                                      0,
                   5529:                                      FALSE
                   5530:                                     );
                   5531: 
                   5532:         if (NT_SUCCESS(status)) {
                   5533: 
                   5534:             deviceExtension->Paused = CDAUDIO_PAUSED;
                   5535:             deviceExtension->PausedM = inputBuffer->M;
                   5536:             deviceExtension->PausedS = inputBuffer->S;
                   5537:             deviceExtension->PausedF = inputBuffer->F;
                   5538:             deviceExtension->LastEndM = inputBuffer->M;
                   5539:             deviceExtension->LastEndS = inputBuffer->S;
                   5540:             deviceExtension->LastEndF = inputBuffer->F;
                   5541:             CdDump(( 3,
                   5542:                 "CdAudio435DeviceControl: SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
                   5543:                 deviceExtension->PausedM,
                   5544:                 deviceExtension->PausedS,
                   5545:                 deviceExtension->PausedF,
                   5546:                 deviceExtension->LastEndM,
                   5547:                 deviceExtension->LastEndS,
                   5548:                 deviceExtension->LastEndF ));
                   5549: 
                   5550:         } else {
                   5551: 
                   5552:             CdDump(( 3,
                   5553:                 "CdAudio435DeviceControl: SEEK failed (0x%08lX)\n",
                   5554:                 status ));
                   5555: 
                   5556:             //
                   5557:             // The CDS-435 drive returns STATUS_INVALID_DEVICE_REQUEST
                   5558:             // when we ask to play an invalid address, so we need
                   5559:             // to map to STATUS_NONEXISTENT_SECTOR in order to be
                   5560:             // consistent with the other drives.
                   5561:             //
                   5562: 
                   5563:             if (status==STATUS_INVALID_DEVICE_REQUEST) {
                   5564: 
                   5565:                 status = STATUS_NONEXISTENT_SECTOR;
                   5566:             }
                   5567: 
                   5568:         }
                   5569:         }
                   5570:         break;
                   5571: 
                   5572:     case IOCTL_CDROM_PAUSE_AUDIO:
                   5573:         {
                   5574:         PUCHAR SubQPtr =
                   5575:             ExAllocatePool( NonPagedPoolCacheAligned,
                   5576:                             sizeof(SUB_Q_CHANNEL_DATA)
                   5577:                            );
                   5578: 
                   5579:         CdDump(( 3,
                   5580:                      "CdAudio435DeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
                   5581:                      ));
                   5582: 
                   5583:         if (SubQPtr==NULL) {
                   5584: 
                   5585:             status = STATUS_INSUFFICIENT_RESOURCES;
                   5586:             goto SetStatusAndReturn;
                   5587: 
                   5588:         }
                   5589: 
                   5590:         //
                   5591:         // Enter pause (still ) mode
                   5592:         //
                   5593: 
                   5594:         if (deviceExtension->Paused==CDAUDIO_PAUSED) {
                   5595: 
                   5596:             CdDump(( 3,
                   5597:                 "CdAudio435DeviceControl: PAUSE: Already Paused!\n"
                   5598:                 ));
                   5599: 
                   5600:             ExFreePool( SubQPtr );
                   5601:             status = STATUS_SUCCESS;
                   5602:             goto SetStatusAndReturn;
                   5603: 
                   5604:         }
                   5605: 
                   5606:         //
                   5607:         // Since the CDS-435 doesn't have a pause mode,
                   5608:         // we'll just record the current position and
                   5609:         // stop the drive.
                   5610:         //
                   5611: 
                   5612:         srb.CdbLength            = 10;
                   5613:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   5614:         cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
                   5615:         cdb->SUBCHANNEL.Msf = 1;
                   5616:         cdb->SUBCHANNEL.SubQ = 1;
                   5617:         cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
                   5618:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5619:                                      &srb,
                   5620:                                      SubQPtr,
                   5621:                                      sizeof(SUB_Q_CHANNEL_DATA),
                   5622:                                      FALSE
                   5623:                                     );
                   5624:         if (!NT_SUCCESS(status)) {
                   5625: 
                   5626:                 CdDump(( 1,
                   5627:                     "CdAudio435DeviceControl: Pause, Read Q Channel failed (0x%lx)\n",
                   5628:                     status ));
                   5629:                 ExFreePool( SubQPtr );
                   5630:                 goto SetStatusAndReturn;
                   5631:         }
                   5632: 
                   5633:         deviceExtension->PausedM = SubQPtr[9];
                   5634:         deviceExtension->PausedS = SubQPtr[10];
                   5635:         deviceExtension->PausedF = SubQPtr[11];
                   5636: 
                   5637:         //
                   5638:         // now stop audio
                   5639:         //
                   5640:         RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
                   5641:         srb.CdbLength                  = 10;
                   5642:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   5643:         cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
                   5644:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5645:                                      &srb,
                   5646:                                      NULL,
                   5647:                                      0,
                   5648:                                      FALSE
                   5649:                                     );
                   5650:         if (!NT_SUCCESS(status)) {
                   5651: 
                   5652:                 CdDump(( 1,
                   5653:                     "CdAudio435DeviceControl: PAUSE, StopAudio failed! (0x%08lX)\n",
                   5654:                     status ));
                   5655:                 ExFreePool( SubQPtr );
                   5656:                 goto SetStatusAndReturn;
                   5657:         }
                   5658: 
                   5659:         deviceExtension->PlayActive = FALSE;
                   5660: 
                   5661:         deviceExtension->Paused = CDAUDIO_PAUSED;
                   5662:         deviceExtension->PausedM = SubQPtr[9];
                   5663:         deviceExtension->PausedS = SubQPtr[10];
                   5664:         deviceExtension->PausedF = SubQPtr[11];
                   5665: 
                   5666:         CdDump((3,
                   5667:             "CdAudio435DeviceControl: PAUSE ==> Paused  set to (%x %x %x)\n",
                   5668:             deviceExtension->PausedM,
                   5669:             deviceExtension->PausedS,
                   5670:             deviceExtension->PausedF ));
                   5671: 
                   5672:         ExFreePool( SubQPtr );
                   5673:         }
                   5674:         break;
                   5675: 
                   5676:     case IOCTL_CDROM_RESUME_AUDIO:
                   5677: 
                   5678:         //
                   5679:         // Resume cdrom
                   5680:         //
                   5681: 
                   5682:         CdDump(( 3,
                   5683:                      "CdAudio435DeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
                   5684:                      ));
                   5685: 
                   5686: 
                   5687:         //
                   5688:         // Since the CDS-435 doesn't have a resume IOCTL,
                   5689:         // we'll just start playing (if paused) from the
                   5690:         // last recored paused position to the last recorded
                   5691:         // "end of play" position.
                   5692:         //
                   5693: 
                   5694:         if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
                   5695: 
                   5696:             status = STATUS_UNSUCCESSFUL;
                   5697:             goto SetStatusAndReturn;
                   5698: 
                   5699:         }
                   5700: 
                   5701:         //
                   5702:         // Fill in cdb for this operation
                   5703:         //
                   5704: 
                   5705:         srb.CdbLength                = 10;
                   5706:         srb.TimeOutValue             = AUDIO_TIMEOUT;
                   5707:         cdb->PLAY_AUDIO_MSF.OperationCode     = CDS435_PLAY_AUDIO_EXTENDED_CODE;
                   5708:         cdb->PLAY_AUDIO_MSF.StartingM = deviceExtension->PausedM;
                   5709:         cdb->PLAY_AUDIO_MSF.StartingS = deviceExtension->PausedS;
                   5710:         cdb->PLAY_AUDIO_MSF.StartingF = deviceExtension->PausedF;
                   5711:         cdb->PLAY_AUDIO_MSF.EndingM   = deviceExtension->LastEndM;
                   5712:         cdb->PLAY_AUDIO_MSF.EndingS   = deviceExtension->LastEndS;
                   5713:         cdb->PLAY_AUDIO_MSF.EndingF   = deviceExtension->LastEndF;
                   5714:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5715:                                      &srb,
                   5716:                                      NULL,
                   5717:                                      0,
                   5718:                                      FALSE
                   5719:                                     );
                   5720: 
                   5721:         if (NT_SUCCESS(status)) {
                   5722: 
                   5723:             deviceExtension->PlayActive = TRUE;
                   5724: 
                   5725:             deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   5726: 
                   5727:         } else {
                   5728: 
                   5729:             CdDump(( 1,
                   5730:                 "CdAudio435DeviceControl: RESUME (%x %x %x) - (%x %x %x) failed (0x%08lX)\n",
                   5731:                 deviceExtension->PausedM,
                   5732:                 deviceExtension->PausedS,
                   5733:                 deviceExtension->PausedF,
                   5734:                 deviceExtension->LastEndM,
                   5735:                 deviceExtension->LastEndS,
                   5736:                 deviceExtension->LastEndF,
                   5737:                 status ));
                   5738: 
                   5739:         }
                   5740:         break;
                   5741: 
                   5742:     case IOCTL_CDROM_READ_Q_CHANNEL:
                   5743:         {
                   5744:         PSUB_Q_CURRENT_POSITION userPtr =
                   5745:             Irp->AssociatedIrp.SystemBuffer;
                   5746:         PUCHAR SubQPtr =
                   5747:             ExAllocatePool( NonPagedPoolCacheAligned,
                   5748:                             sizeof(SUB_Q_CHANNEL_DATA)
                   5749:                            );
                   5750: 
                   5751:         CdDump(( 5,
                   5752:                      "CdAudio435DeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
                   5753:                      ));
                   5754: 
                   5755:         if (SubQPtr==NULL) {
                   5756: 
                   5757:             CdDump(( 1,
                   5758:                          "CdAudio435DeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
                   5759:                          ));
                   5760: 
                   5761:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   5762:             status = STATUS_INSUFFICIENT_RESOURCES;
                   5763:             goto SetStatusAndReturn;
                   5764: 
                   5765:         }
                   5766: 
                   5767:         if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
                   5768:              IOCTL_CDROM_CURRENT_POSITION) {
                   5769: 
                   5770:             CdDump(( 1,
                   5771:                          "CdAudio435DeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
                   5772:                          ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
                   5773:                          ));
                   5774: 
                   5775:             ExFreePool( SubQPtr );
                   5776:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   5777:             status = STATUS_UNSUCCESSFUL;
                   5778:             goto SetStatusAndReturn;
                   5779:         }
                   5780: 
                   5781:         //
                   5782:         // Read audio play status
                   5783:         //
                   5784: 
                   5785:         srb.CdbLength            = 10;
                   5786:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   5787:         cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
                   5788:         cdb->SUBCHANNEL.Msf = 1;
                   5789:         cdb->SUBCHANNEL.SubQ = 1;
                   5790:         cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
                   5791:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5792:                                      &srb,
                   5793:                                      SubQPtr,
                   5794:                                      sizeof(SUB_Q_CHANNEL_DATA),
                   5795:                                      FALSE
                   5796:                                     );
                   5797:         if (NT_SUCCESS(status)) {
                   5798: 
                   5799:             userPtr->Header.Reserved = 0;
                   5800: 
                   5801:             if (deviceExtension->Paused==CDAUDIO_PAUSED) {
                   5802: 
                   5803:                 deviceExtension->PlayActive = FALSE;
                   5804:                 userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
                   5805: 
                   5806:             } else {
                   5807: 
                   5808:                 if (SubQPtr[1] == 0x11) {
                   5809: 
                   5810:                     deviceExtension->PlayActive = TRUE;
                   5811:                     userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
                   5812: 
                   5813:                 } else {
                   5814: 
                   5815:                     deviceExtension->PlayActive = FALSE;
                   5816:                     userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
                   5817: 
                   5818:                 }
                   5819:             }
                   5820: 
                   5821:             userPtr->Header.DataLength[0] = 0;
                   5822:             userPtr->Header.DataLength[1] = 12;
                   5823: 
                   5824:             userPtr->FormatCode = 0x01;
                   5825:             userPtr->Control = SubQPtr[5];
                   5826:             userPtr->ADR     = 0;
                   5827:             userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
                   5828:             userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
                   5829:             userPtr->AbsoluteAddress[0] = 0;
                   5830:             userPtr->AbsoluteAddress[1] = SubQPtr[9];
                   5831:             userPtr->AbsoluteAddress[2] = SubQPtr[10];
                   5832:             userPtr->AbsoluteAddress[3] = SubQPtr[11];
                   5833:             userPtr->TrackRelativeAddress[0] = 0;
                   5834:             userPtr->TrackRelativeAddress[1] = SubQPtr[13];
                   5835:             userPtr->TrackRelativeAddress[2] = SubQPtr[14];
                   5836:             userPtr->TrackRelativeAddress[3] = SubQPtr[15];
                   5837:             Irp->IoStatus.Information = 16;
                   5838: 
                   5839:         } else {
                   5840: 
                   5841:             RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
                   5842:             CdDump(( 1,
                   5843:                          "CdAudio435DeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
                   5844:                          status
                   5845:                          ));
                   5846: 
                   5847: 
                   5848:         }
                   5849: 
                   5850:         ExFreePool( SubQPtr );
                   5851:         }
                   5852:         break;
                   5853: 
                   5854:     case IOCTL_CDROM_EJECT_MEDIA:
                   5855: 
                   5856:         //
                   5857:         // Build cdb to eject cartridge
                   5858:         //
                   5859: 
                   5860:         CdDump(( 3,
                   5861:                      "CdAudio435DeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
                   5862:                      ));
                   5863: 
                   5864:         srb.CdbLength                  = 10;
                   5865:         srb.TimeOutValue               = AUDIO_TIMEOUT;
                   5866:         cdb->CDB10.OperationCode = CDS435_EJECT_CODE;
                   5867:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5868:                                      &srb,
                   5869:                                      NULL,
                   5870:                                      0,
                   5871:                                      FALSE
                   5872:                                     );
                   5873: 
                   5874:         deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
                   5875:         deviceExtension->PausedM = 0;
                   5876:         deviceExtension->PausedS = 0;
                   5877:         deviceExtension->PausedF = 0;
                   5878:         deviceExtension->LastEndM = 0;
                   5879:         deviceExtension->LastEndS = 0;
                   5880:         deviceExtension->LastEndF = 0;
                   5881: 
                   5882:         break;
                   5883: 
                   5884:     case IOCTL_CDROM_GET_CONTROL:
                   5885:     case IOCTL_CDROM_GET_VOLUME:
                   5886:     case IOCTL_CDROM_SET_VOLUME:
                   5887:         CdDump(( 3, "CdAudio435DeviceControl: Not Supported yet.\n" ));
                   5888:         status = STATUS_INVALID_DEVICE_REQUEST;
                   5889:         break;
                   5890: 
                   5891:     case IOCTL_CDROM_CHECK_VERIFY:
                   5892:         //
                   5893:         // Update the play active flag.
                   5894:         //
                   5895: 
                   5896:         CdAudioIsPlayActive(DeviceObject);
                   5897: 
                   5898:         //
                   5899:         // This normally uses the Test_Unit_Ready (TUR) command.  The
                   5900:         // CDS-435/431 respond to the TUR command with a status byte
                   5901:         // of 0x08 to indicate that an audio play is in progress.  That
                   5902:         // looks like SCSISTAT_BUSY, so it ends up getting retried.
                   5903:         // There are a couple of solutions:
                   5904:         //  a) install a class error handler that watches for
                   5905:         //     Status == STATUS_DEVICE_NOT_READY
                   5906:         //     and/or Srb->ScsiStatus = SCSISTAT_BUSY
                   5907:         //     and converts it to Status = STATUS_SUCCESS,
                   5908:         //     Srb->ScsiStatus = SCSISTAT_GOOD
                   5909:         //     This is considerably more general than really necessary,
                   5910:         //     since only the TUR command behaves this way.
                   5911:         //  b) use another command, like ReadSubQ to get the drive's status
                   5912:         //     (we don't need to transfer any data, i.e. allocation length
                   5913:         //     = 0)
                   5914:         //
                   5915: 
                   5916:         CdDump(( 3, "CdAudio435DeviceControl: IOCTL_CDROM_CHECK_VERIFY received.\n"
                   5917:                      ));
                   5918: 
                   5919:         //
                   5920:         // Read audio play status
                   5921:         //
                   5922: 
                   5923:         srb.CdbLength            = 10;
                   5924:         srb.TimeOutValue         = AUDIO_TIMEOUT;
                   5925:         cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
                   5926:         cdb->SUBCHANNEL.Msf = 1;
                   5927:         cdb->SUBCHANNEL.SubQ = 1;
                   5928:         status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
                   5929:                                      &srb,
                   5930:                                      NULL,
                   5931:                                      0,
                   5932:                                      FALSE
                   5933:                                     );
                   5934:         break;
                   5935: 
                   5936:     default:
                   5937: 
                   5938:         CdDump((5,"CdAudio435DeviceControl: Unsupported device IOCTL\n"));
                   5939:         return CdAudioSendToNextDriver( DeviceObject, Irp );
                   5940:         break;
                   5941: 
                   5942:     } // end switch( IOCTL )
                   5943: 
                   5944: SetStatusAndReturn:
                   5945:     //
                   5946:     // set status code and return
                   5947:     //
                   5948: 
                   5949:     if (status == STATUS_VERIFY_REQUIRED) {
                   5950: 
                   5951:         IoSetHardErrorOrVerifyDevice( Irp,
                   5952:                                       deviceExtension->TargetDeviceObject
                   5953:                                      );
                   5954: 
                   5955:         Irp->IoStatus.Information = 0;
                   5956:     }
                   5957: 
                   5958:     Irp->IoStatus.Status = status;
                   5959:     IoCompleteRequest(Irp, IO_NO_INCREMENT);
                   5960:     return status;
                   5961: 
                   5962: }
                   5963: 
                   5964: #if DBG
                   5965: VOID
                   5966: CdAudioDebugPrint(
                   5967:     ULONG DebugPrintLevel,
                   5968:     PCCHAR DebugMessage,
                   5969:     ...
                   5970:     )
                   5971: 
                   5972: /*++
                   5973: 
                   5974: Routine Description:
                   5975: 
                   5976:     Debug print for CdAudio driver
                   5977: 
                   5978: Arguments:
                   5979: 
                   5980:     Debug print level between 0 and 3, with 3 being the most verbose.
                   5981: 
                   5982: Return Value:
                   5983: 
                   5984:     None
                   5985: 
                   5986: --*/
                   5987: 
                   5988: {
                   5989:     va_list ap;
                   5990: 
                   5991:     va_start( ap, DebugMessage );
                   5992: 
                   5993:     if (DebugPrintLevel <= CdAudioDebug) {
                   5994: 
                   5995:         char buffer[128];
                   5996: 
                   5997:         vsprintf(buffer, DebugMessage, ap);
                   5998:         DbgPrint(buffer);
                   5999:     }
                   6000: 
                   6001:     va_end(ap);
                   6002: 
                   6003: } // end CdAudioDebugPrint
                   6004: 
                   6005: #endif // DBG

unix.superglobalmegacorp.com

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