Don't create the media change event as named object.
[reactos.git] / reactos / drivers / storage / cdrom / cdrom.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/cdrom/cdrom.c
24 * PURPOSE: cdrom class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /*
29 * TODO:
30 * - Add io timer routine for autorun support.
31 * - Add cdaudio support (cd player).
32 */
33
34 /* INCLUDES *****************************************************************/
35
36 #include <ddk/ntddk.h>
37 #include <ddk/scsi.h>
38 #include <ddk/class2.h>
39 #include <ddk/ntddscsi.h>
40 #include <ntos/minmax.h>
41
42 #define NDEBUG
43 #include <debug.h>
44
45 #define VERSION "0.0.1"
46
47
48 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
49
50
51 typedef struct _ERROR_RECOVERY_DATA6
52 {
53 MODE_PARAMETER_HEADER Header;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
55 } ERROR_RECOVERY_DATA6, *PERROR_RECOVERY_DATA6;
56
57
58 typedef struct _ERROR_RECOVERY_DATA10
59 {
60 MODE_PARAMETER_HEADER10 Header;
61 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
62 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
63
64 typedef struct _MODE_CAPABILITIES_DATA6
65 {
66 MODE_PARAMETER_HEADER Header;
67 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
68 } MODE_CAPABILITIES_DATA6, *PMODE_CAPABILITIES_DATA6;
69
70 typedef struct _MODE_CAPABILITIES_DATA10
71 {
72 MODE_PARAMETER_HEADER10 Header;
73 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
74 } MODE_CAPABILITIES_DATA10, *PMODE_CAPABILITIES_DATA10;
75
76 typedef struct _CDROM_DATA
77 {
78 BOOLEAN PlayActive;
79 BOOLEAN RawAccess;
80 USHORT XaFlags;
81
82 } CDROM_DATA, *PCDROM_DATA;
83
84 /* CDROM_DATA.XaFlags */
85 #define XA_USE_6_BYTE 0x0001
86 #define XA_USE_10_BYTE 0x0002
87 #define XA_USE_READ_CD 0x0004
88 #define XA_NOT_SUPPORTED 0x0008
89
90
91 BOOLEAN STDCALL
92 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
93 IN PUNICODE_STRING RegistryPath,
94 IN PCLASS_INIT_DATA InitializationData,
95 IN PDEVICE_OBJECT PortDeviceObject,
96 IN ULONG PortNumber);
97
98 BOOLEAN STDCALL
99 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
100
101 NTSTATUS STDCALL
102 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
103 IN PIRP Irp);
104
105 static VOID
106 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
107 IN ULONG DeviceNumber);
108
109 static NTSTATUS
110 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
111 IN PUNICODE_STRING RegistryPath,
112 IN PDEVICE_OBJECT PortDeviceObject,
113 IN ULONG PortNumber,
114 IN ULONG DeviceNumber,
115 IN PIO_SCSI_CAPABILITIES Capabilities,
116 IN PSCSI_INQUIRY_DATA InquiryData,
117 IN PCLASS_INIT_DATA InitializationData);
118
119
120 NTSTATUS STDCALL
121 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
122 IN PIRP Irp);
123
124 VOID STDCALL
125 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
126 IN PIRP Irp);
127
128 NTSTATUS STDCALL
129 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
130 IN PIRP Irp,
131 IN PVOID Context);
132
133 VOID STDCALL
134 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
135 IN PVOID Context);
136
137 VOID
138 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
139 IN PVOID Context);
140
141
142 /* FUNCTIONS ****************************************************************/
143
144 /**********************************************************************
145 * NAME EXPORTED
146 * DriverEntry
147 *
148 * DESCRIPTION:
149 * This function initializes the driver, locates and claims
150 * hardware resources, and creates various NT objects needed
151 * to process I/O requests.
152 *
153 * RUN LEVEL:
154 * PASSIVE_LEVEL
155 *
156 * ARGUMENTS:
157 * DriverObject
158 * System allocated Driver Object for this driver
159 * RegistryPath
160 * Name of registry driver service key
161 *
162 * RETURNS:
163 * Status.
164 */
165
166 NTSTATUS STDCALL
167 DriverEntry(IN PDRIVER_OBJECT DriverObject,
168 IN PUNICODE_STRING RegistryPath)
169 {
170 CLASS_INIT_DATA InitData;
171
172 DPRINT("CD-ROM Class Driver %s\n",
173 VERSION);
174 DPRINT("RegistryPath '%wZ'\n",
175 RegistryPath);
176
177 InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
178 InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA);
179 InitData.DeviceType = FILE_DEVICE_CD_ROM;
180 InitData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
181
182 InitData.ClassError = NULL;
183 InitData.ClassReadWriteVerification = CdromClassCheckReadWrite;
184 InitData.ClassFindDeviceCallBack = CdromClassCheckDevice;
185 InitData.ClassFindDevices = CdromClassFindDevices;
186 InitData.ClassDeviceControl = CdromClassDeviceControl;
187 InitData.ClassShutdownFlush = NULL;
188 InitData.ClassCreateClose = NULL;
189 InitData.ClassStartIo = CdromClassStartIo;
190
191 return(ScsiClassInitialize(DriverObject,
192 RegistryPath,
193 &InitData));
194 }
195
196
197 /**********************************************************************
198 * NAME EXPORTED
199 * CdromClassFindDevices
200 *
201 * DESCRIPTION:
202 * This function searches for device that are attached to the
203 * given scsi port.
204 *
205 * RUN LEVEL:
206 * PASSIVE_LEVEL
207 *
208 * ARGUMENTS:
209 * DriverObject
210 * System allocated Driver Object for this driver
211 * RegistryPath
212 * Name of registry driver service key.
213 * InitializationData
214 * Pointer to the main initialization data
215 * PortDeviceObject
216 * Scsi port device object
217 * PortNumber
218 * Port number
219 *
220 * RETURNS:
221 * TRUE: At least one disk drive was found
222 * FALSE: No disk drive found
223 */
224
225 BOOLEAN STDCALL
226 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
227 IN PUNICODE_STRING RegistryPath,
228 IN PCLASS_INIT_DATA InitializationData,
229 IN PDEVICE_OBJECT PortDeviceObject,
230 IN ULONG PortNumber)
231 {
232 PCONFIGURATION_INFORMATION ConfigInfo;
233 PIO_SCSI_CAPABILITIES PortCapabilities;
234 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
235 PSCSI_INQUIRY_DATA UnitInfo;
236 PINQUIRYDATA InquiryData;
237 PCHAR Buffer;
238 ULONG Bus;
239 ULONG DeviceCount;
240 BOOLEAN FoundDevice = FALSE;
241 NTSTATUS Status;
242
243 DPRINT("CdromClassFindDevices() called.\n");
244
245 /* Get port capabilities */
246 Status = ScsiClassGetCapabilities(PortDeviceObject,
247 &PortCapabilities);
248 if (!NT_SUCCESS(Status))
249 {
250 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
251 return(FALSE);
252 }
253
254 DPRINT("PortCapabilities: %p\n", PortCapabilities);
255 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
256 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
257
258 /* Get inquiry data */
259 Status = ScsiClassGetInquiryData(PortDeviceObject,
260 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
264 return(FALSE);
265 }
266
267 /* Check whether there are unclaimed devices */
268 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
269 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
270 AdapterBusInfo);
271 if (DeviceCount == 0)
272 {
273 DPRINT("No unclaimed devices!\n");
274 return(FALSE);
275 }
276
277 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
278
279 ConfigInfo = IoGetConfigurationInformation();
280 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
281
282 /* Search each bus of this adapter */
283 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
284 {
285 DPRINT("Searching bus %lu\n", Bus);
286
287 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
288
289 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
290 {
291 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
292
293 if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
294 (InquiryData->DeviceTypeQualifier == 0) &&
295 (UnitInfo->DeviceClaimed == FALSE))
296 {
297 DPRINT("Vendor: '%.24s'\n",
298 InquiryData->VendorId);
299
300 /* Create device objects for disk */
301 Status = CdromClassCreateDeviceObject(DriverObject,
302 RegistryPath,
303 PortDeviceObject,
304 PortNumber,
305 ConfigInfo->CdRomCount,
306 PortCapabilities,
307 UnitInfo,
308 InitializationData);
309 if (NT_SUCCESS(Status))
310 {
311 ConfigInfo->CdRomCount++;
312 FoundDevice = TRUE;
313 }
314 }
315
316 if (UnitInfo->NextInquiryDataOffset == 0)
317 break;
318
319 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
320 }
321 }
322
323 ExFreePool(Buffer);
324
325 DPRINT("CdromClassFindDevices() done\n");
326
327 return(FoundDevice);
328 }
329
330
331 /**********************************************************************
332 * NAME EXPORTED
333 * CdromClassCheckDevice
334 *
335 * DESCRIPTION
336 * This function checks the InquiryData for the correct device
337 * type and qualifier.
338 *
339 * RUN LEVEL
340 * PASSIVE_LEVEL
341 *
342 * ARGUMENTS
343 * InquiryData
344 * Pointer to the inquiry data for the device in question.
345 *
346 * RETURN VALUE
347 * TRUE: A disk device was found.
348 * FALSE: Otherwise.
349 */
350
351 BOOLEAN STDCALL
352 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
353 {
354 return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
355 (InquiryData->DeviceTypeQualifier == 0));
356 }
357
358
359 /**********************************************************************
360 * NAME EXPORTED
361 * CdromClassCheckReadWrite
362 *
363 * DESCRIPTION
364 * This function checks the given IRP for correct data.
365 *
366 * RUN LEVEL
367 * PASSIVE_LEVEL
368 *
369 * ARGUMENTS
370 * DeviceObject
371 * Pointer to the device.
372 * Irp
373 * Irp to check.
374 *
375 * RETURN VALUE
376 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
377 * Others: Failure.
378 */
379
380 NTSTATUS STDCALL
381 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
382 IN PIRP Irp)
383 {
384 DPRINT("CdromClassCheckReadWrite() called\n");
385
386 return(STATUS_SUCCESS);
387 }
388
389
390 static VOID
391 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
392 IN ULONG DeviceNumber)
393 {
394
395
396 DeviceExtension->MediaChangeEvent =
397 IoCreateSynchronizationEvent (NULL,
398 &DeviceExtension->MediaChangeEventHandle);
399
400 KeClearEvent (DeviceExtension->MediaChangeEvent);
401 }
402
403
404 /**********************************************************************
405 * NAME EXPORTED
406 * CdromClassCreateDeviceObject
407 *
408 * DESCRIPTION:
409 * Create the raw device and any partition devices on this drive
410 *
411 * RUN LEVEL:
412 * PASSIVE_LEVEL
413 *
414 * ARGUMENTS:
415 * DriverObject
416 * System allocated Driver Object for this driver.
417 * RegistryPath
418 * Name of registry driver service key.
419 * PortDeviceObject
420 * PortNumber
421 * DeviceNumber
422 * Capabilities
423 * InquiryData
424 * InitializationData
425 *
426 * RETURNS:
427 * Status.
428 */
429
430 static NTSTATUS
431 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
432 IN PUNICODE_STRING RegistryPath,
433 IN PDEVICE_OBJECT PortDeviceObject,
434 IN ULONG PortNumber,
435 IN ULONG DeviceNumber,
436 IN PIO_SCSI_CAPABILITIES Capabilities,
437 IN PSCSI_INQUIRY_DATA InquiryData,
438 IN PCLASS_INIT_DATA InitializationData)
439 {
440 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
441 PDEVICE_OBJECT DiskDeviceObject;
442 PCDROM_DATA CdromData;
443 CHAR NameBuffer[80];
444 SCSI_REQUEST_BLOCK Srb;
445 PUCHAR Buffer;
446 ULONG Length;
447 PCDB Cdb;
448 NTSTATUS Status;
449
450 DPRINT("CdromClassCreateDeviceObject() called\n");
451
452 /* Claim the cdrom device */
453 Status = ScsiClassClaimDevice(PortDeviceObject,
454 InquiryData,
455 FALSE,
456 &PortDeviceObject);
457 if (!NT_SUCCESS(Status))
458 {
459 DbgPrint("Could not claim cdrom device\n");
460 return(Status);
461 }
462
463 /* Create cdrom device */
464 sprintf(NameBuffer,
465 "\\Device\\CdRom%lu",
466 DeviceNumber);
467
468 Status = ScsiClassCreateDeviceObject(DriverObject,
469 NameBuffer,
470 NULL,
471 &DiskDeviceObject,
472 InitializationData);
473 if (!NT_SUCCESS(Status))
474 {
475 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
476
477 /* Release (unclaim) the disk */
478 ScsiClassClaimDevice(PortDeviceObject,
479 InquiryData,
480 TRUE,
481 NULL);
482
483 return(Status);
484 }
485
486 DiskDeviceObject->Flags |= DO_DIRECT_IO;
487 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
488 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
489
490 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
491 {
492 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
493 }
494
495 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
496 DiskDeviceExtension->LockCount = 0;
497 DiskDeviceExtension->DeviceNumber = DeviceNumber;
498 DiskDeviceExtension->DeviceObject = DiskDeviceObject;
499 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
500 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
501 DiskDeviceExtension->PortCapabilities = Capabilities;
502 DiskDeviceExtension->StartingOffset.QuadPart = 0;
503 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
504 DiskDeviceExtension->PathId = InquiryData->PathId;
505 DiskDeviceExtension->TargetId = InquiryData->TargetId;
506 DiskDeviceExtension->Lun = InquiryData->Lun;
507
508 /* zero-out disk data */
509 CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
510 RtlZeroMemory(CdromData,
511 sizeof(CDROM_DATA));
512
513 DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
514 sizeof(SENSE_DATA));
515 if (DiskDeviceExtension->SenseData == NULL)
516 {
517 DPRINT1("Failed to allocate sense data buffer!\n");
518
519 IoDeleteDevice(DiskDeviceObject);
520
521 /* Release (unclaim) the disk */
522 ScsiClassClaimDevice(PortDeviceObject,
523 InquiryData,
524 TRUE,
525 NULL);
526
527 return(STATUS_INSUFFICIENT_RESOURCES);
528 }
529
530 /* Get timeout value */
531 DiskDeviceExtension->TimeOutValue =
532 ScsiClassQueryTimeOutRegistryValue(RegistryPath);
533 if (DiskDeviceExtension->TimeOutValue == 0)
534 DiskDeviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
535
536 /* Initialize lookaside list for SRBs */
537 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
538 4);
539
540 /* Get disk geometry */
541 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
542 sizeof(DISK_GEOMETRY));
543 if (DiskDeviceExtension->DiskGeometry == NULL)
544 {
545 DPRINT1("Failed to allocate geometry buffer!\n");
546
547 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
548
549 IoDeleteDevice(DiskDeviceObject);
550
551 /* Release (unclaim) the disk */
552 ScsiClassClaimDevice(PortDeviceObject,
553 InquiryData,
554 TRUE,
555 NULL);
556
557 return(STATUS_INSUFFICIENT_RESOURCES);
558 }
559
560 /* Read the drive's capacity */
561 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
562 if (!NT_SUCCESS(Status) ||
563 DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
564 {
565 /* Set ISO9660 defaults */
566 DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
567 DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
568 DiskDeviceExtension->SectorShift = 11;
569 DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
570 }
571 else
572 {
573 /* Make sure the BytesPerSector value is a power of 2 */
574 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
575 }
576
577 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
578
579 /* Initialize media change support */
580 CdromClassCreateMediaChangeEvent (DiskDeviceExtension,
581 DeviceNumber);
582 if (DiskDeviceExtension->MediaChangeEvent != NULL)
583 {
584 DPRINT("Allocated media change event!\n");
585
586 /* FIXME: Allocate media change IRP and SRB */
587 }
588
589 /* Use 6 byte xa commands by default */
590 CdromData->XaFlags |= XA_USE_6_BYTE;
591
592 /* Read 'error recovery page' to get additional drive capabilities */
593 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
594
595 RtlZeroMemory (&Srb,
596 sizeof(SCSI_REQUEST_BLOCK));
597 Srb.CdbLength = 6;
598 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
599
600 Cdb = (PCDB)Srb.Cdb;
601 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
602 Cdb->MODE_SENSE.PageCode = 0x01;
603 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
604
605 Buffer = ExAllocatePool (NonPagedPool,
606 max(sizeof(ERROR_RECOVERY_DATA6),
607 max(sizeof(ERROR_RECOVERY_DATA10),
608 max(sizeof(MODE_CAPABILITIES_DATA6),
609 sizeof(MODE_CAPABILITIES_DATA10)))));
610 if (Buffer == NULL)
611 {
612 DPRINT1("Allocating recovery page buffer failed!\n");
613 return STATUS_INSUFFICIENT_RESOURCES;
614 }
615
616 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
617 &Srb,
618 Buffer,
619 Length,
620 FALSE);
621
622 if (!NT_SUCCESS (Status))
623 {
624 DPRINT("MODE_SENSE(6) failed\n");
625
626 /* Try the 10 byte version */
627 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH10;
628
629 RtlZeroMemory (&Srb,
630 sizeof(SCSI_REQUEST_BLOCK));
631 Srb.CdbLength = 10;
632 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
633
634 Cdb = (PCDB)Srb.Cdb;
635 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
636 Cdb->MODE_SENSE10.PageCode = 0x01;
637 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
638 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
639
640 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
641 &Srb,
642 Buffer,
643 Length,
644 FALSE);
645
646 if (Status == STATUS_DATA_OVERRUN)
647 {
648 DPRINT1("Data overrun\n");
649
650 /* FIXME */
651 }
652 else if (NT_SUCCESS (Status))
653 {
654 DPRINT("Use 10 byte commands\n");
655 CdromData->XaFlags &= XA_USE_6_BYTE;
656 CdromData->XaFlags |= XA_USE_10_BYTE;
657 }
658 else
659 {
660 DPRINT("XA not supported\n");
661 CdromData->XaFlags |= XA_NOT_SUPPORTED;
662 }
663 }
664 else
665 {
666 DPRINT("Use 6 byte commands\n");
667 }
668
669 /* Read 'capabilities & mechanical status page' to get additional drive capabilities */
670 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
671
672 if (!(CdromData->XaFlags & XA_NOT_SUPPORTED))
673 {
674 RtlZeroMemory (&Srb, sizeof(SCSI_REQUEST_BLOCK));
675 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
676 Cdb = (PCDB)Srb.Cdb;
677
678 if (CdromData->XaFlags & XA_USE_10_BYTE)
679 {
680 /* Try the 10 byte version */
681 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH10;
682
683 Srb.CdbLength = 10;
684 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
685 Cdb->MODE_SENSE10.PageCode = 0x2a;
686 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
687 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
688 }
689 else
690 {
691 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH;
692
693 Srb.CdbLength = 6;
694 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
695 Cdb->MODE_SENSE.PageCode = 0x2a;
696 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
697 }
698 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
699 &Srb,
700 Buffer,
701 Length,
702 FALSE);
703 if (NT_SUCCESS (Status))
704 {
705 #if 0
706 PMODE_CAPABILITIES_PAGE2 CapabilitiesData;
707 if (CdromData->XaFlags & XA_USE_10_BYTE)
708 {
709 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER10));
710 }
711 else
712 {
713 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER));
714 }
715
716 DbgPrint("Capabilities for '%s':\n", NameBuffer);
717 if (CapabilitiesData->Reserved2[0] & 0x20)
718 {
719 DbgPrint(" Drive supports reading of DVD-RAM discs\n");
720 }
721 if (CapabilitiesData->Reserved2[0] & 0x10)
722 {
723 DbgPrint(" Drive supports reading of DVD-R discs\n");
724 }
725 if (CapabilitiesData->Reserved2[0] & 0x08)
726 {
727 DbgPrint(" Drive supports reading of DVD-ROM discs\n");
728 }
729 if (CapabilitiesData->Reserved2[0] & 0x04)
730 {
731 DbgPrint(" Drive supports reading CD-R discs with addressing method 2\n");
732 }
733 if (CapabilitiesData->Reserved2[0] & 0x02)
734 {
735 DbgPrint(" Drive can read from CD-R/W (CD-E) discs (orange book, part III)\n");
736 }
737 if (CapabilitiesData->Reserved2[0] & 0x01)
738 {
739 DbgPrint(" Drive supports read from CD-R discs (orange book, part II)\n");
740 }
741 DPRINT("CapabilitiesData.Reserved2[1] %x\n", CapabilitiesData->Reserved2[1]);
742 if (CapabilitiesData->Reserved2[1] & 0x01)
743 {
744 DbgPrint(" Drive can write to CD-R discs (orange book, part II)\n");
745 }
746 if (CapabilitiesData->Reserved2[1] & 0x02)
747 {
748 DbgPrint(" Drive can write to CD-R/W (CD-E) discs (orange book, part III)\n");
749 }
750 if (CapabilitiesData->Reserved2[1] & 0x04)
751 {
752 DbgPrint(" Drive can fake writes\n");
753 }
754 if (CapabilitiesData->Reserved2[1] & 0x10)
755 {
756 DbgPrint(" Drive can write DVD-R discs\n");
757 }
758 if (CapabilitiesData->Reserved2[1] & 0x20)
759 {
760 DbgPrint(" Drive can write DVD-RAM discs\n");
761 }
762 DPRINT("CapabilitiesData.Capabilities[0] %x\n", CapabilitiesData->Capabilities[0]);
763 if (CapabilitiesData->Capabilities[0] & 0x01)
764 {
765 DbgPrint(" Drive supports audio play operations\n");
766 }
767 if (CapabilitiesData->Capabilities[0] & 0x02)
768 {
769 DbgPrint(" Drive can deliver a composite audio/video data stream\n");
770 }
771 if (CapabilitiesData->Capabilities[0] & 0x04)
772 {
773 DbgPrint(" Drive supports digital output on port 1\n");
774 }
775 if (CapabilitiesData->Capabilities[0] & 0x08)
776 {
777 DbgPrint(" Drive supports digital output on port 2\n");
778 }
779 if (CapabilitiesData->Capabilities[0] & 0x10)
780 {
781 DbgPrint(" Drive can read mode 2, form 1 (XA) data\n");
782 }
783 if (CapabilitiesData->Capabilities[0] & 0x20)
784 {
785 DbgPrint(" Drive can read mode 2, form 2 data\n");
786 }
787 if (CapabilitiesData->Capabilities[0] & 0x40)
788 {
789 DbgPrint(" Drive can read multisession discs\n");
790 }
791 DPRINT("CapabilitiesData.Capabilities[1] %x\n", CapabilitiesData->Capabilities[1]);
792 if (CapabilitiesData->Capabilities[1] & 0x01)
793 {
794 DbgPrint(" Drive can read Red Book audio data\n");
795 }
796 if (CapabilitiesData->Capabilities[1] & 0x02)
797 {
798 DbgPrint(" Drive can continue a read cdda operation from a loss of streaming\n");
799 }
800 if (CapabilitiesData->Capabilities[1] & 0x04)
801 {
802 DbgPrint(" Subchannel reads can return combined R-W information\n");
803 }
804 if (CapabilitiesData->Capabilities[1] & 0x08)
805 {
806 DbgPrint(" R-W data will be returned deinterleaved and error corrected\n");
807 }
808 if (CapabilitiesData->Capabilities[1] & 0x10)
809 {
810 DbgPrint(" Drive supports C2 error pointers\n");
811 }
812 if (CapabilitiesData->Capabilities[1] & 0x20)
813 {
814 DbgPrint(" Drive can return International Standard Recording Code info\n");
815 }
816 if (CapabilitiesData->Capabilities[1] & 0x40)
817 {
818 DbgPrint(" Drive can return Media Catalog Number (UPC) info\n");
819 }
820 DPRINT("CapabilitiesData.Capabilities[2] %x\n", CapabilitiesData->Capabilities[2]);
821 if (CapabilitiesData->Capabilities[2] & 0x01)
822 {
823 DbgPrint(" Drive can lock the door\n");
824 }
825 if (CapabilitiesData->Capabilities[2] & 0x02)
826 {
827 DbgPrint(" The door is locked\n");
828 }
829 if (CapabilitiesData->Capabilities[2] & 0x04)
830 {
831 }
832 if (CapabilitiesData->Capabilities[2] & 0x08)
833 {
834 DbgPrint(" Drive can eject a disc or changer cartridge\n");
835 }
836 if (CapabilitiesData->Capabilities[2] & 0x10)
837 {
838 DbgPrint(" Drive supports C2 error pointers\n");
839 }
840 switch (CapabilitiesData->Capabilities[2] >> 5)
841 {
842 case 0:
843 DbgPrint(" Drive use a caddy type loading mechanism\n");
844 break;
845 case 1:
846 DbgPrint(" Drive use a tray type loading mechanism\n");
847 break;
848 case 2:
849 DbgPrint(" Drive use a pop-up type loading mechanism\n");
850 break;
851 case 4:
852 DbgPrint(" Drive is a changer with individually changeable discs\n");
853 break;
854 case 5:
855 DbgPrint(" Drive is a changer with cartridge mechanism\n");
856 break;
857 }
858 DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData->Capabilities[3]);
859 if (CapabilitiesData->Capabilities[3] & 0x01)
860 {
861 DbgPrint(" Audio level for each channel can be controlled independently\n");
862 }
863 if (CapabilitiesData->Capabilities[3] & 0x02)
864 {
865 DbgPrint(" Audio for each channel can be muted independently\n");
866 }
867 if (CapabilitiesData->Capabilities[3] & 0x04)
868 {
869 DbgPrint(" Changer can report exact contents of slots\n");
870 }
871 if (CapabilitiesData->Capabilities[3] & 0x08)
872 {
873 DbgPrint(" Drive supports software slot selection\n");
874 }
875 DbgPrint(" Maximum speed is %d kB/s\n",
876 (CapabilitiesData->MaximumSpeedSupported[0] << 8)
877 | CapabilitiesData->MaximumSpeedSupported[1]);
878 DbgPrint(" Current speed is %d kB/s\n",
879 (CapabilitiesData->CurrentSpeed[0] << 8)
880 | CapabilitiesData->CurrentSpeed[1]);
881 DbgPrint(" Number of discrete volume levels is %d\n",
882 (CapabilitiesData->Reserved3 << 8)
883 | CapabilitiesData->NumberVolumeLevels);
884 DbgPrint(" Buffer size is %d kB\n",
885 (CapabilitiesData->BufferSize[0] << 8)
886 | CapabilitiesData->BufferSize[1]);
887 #endif
888 }
889 else
890 {
891 DPRINT("XA not supported\n");
892 CdromData->XaFlags |= XA_NOT_SUPPORTED;
893 }
894
895 }
896
897
898 ExFreePool (Buffer);
899
900 /* Initialize device timer */
901 IoInitializeTimer(DiskDeviceObject,
902 CdromTimerRoutine,
903 NULL);
904 IoStartTimer(DiskDeviceObject);
905
906 DPRINT("CdromClassCreateDeviceObjects() done\n");
907
908 return(STATUS_SUCCESS);
909 }
910
911
912 /**********************************************************************
913 * NAME
914 * CdromClassReadTocEntry
915 *
916 * ARGUMENTS:
917 * DeviceObject
918 * TrackNo
919 * Buffer
920 * Length
921 *
922 * RETURNS:
923 * Status.
924 */
925 static NTSTATUS
926 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
927 UINT TrackNo,
928 PVOID Buffer,
929 UINT Length)
930 {
931 PDEVICE_EXTENSION DeviceExtension;
932 SCSI_REQUEST_BLOCK Srb;
933 PCDB Cdb;
934
935 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
936
937 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
938 Srb.CdbLength = 10;
939 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
940
941 Cdb = (PCDB)Srb.Cdb;
942 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
943 Cdb->READ_TOC.StartingTrack = TrackNo;
944 Cdb->READ_TOC.Format = 0;
945 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
946 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
947 Cdb->READ_TOC.Msf = 1;
948
949 return(ScsiClassSendSrbSynchronous(DeviceObject,
950 &Srb,
951 Buffer,
952 Length,
953 FALSE));
954 }
955
956
957 static NTSTATUS
958 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
959 UINT TrackNo,
960 PVOID Buffer,
961 UINT Length)
962 {
963 PDEVICE_EXTENSION DeviceExtension;
964 SCSI_REQUEST_BLOCK Srb;
965 PCDB Cdb;
966
967 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
968
969 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
970 Srb.CdbLength = 10;
971 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
972
973 Cdb = (PCDB)Srb.Cdb;
974 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
975 Cdb->READ_TOC.StartingTrack = TrackNo;
976 Cdb->READ_TOC.Format = 1;
977 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
978 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
979 Cdb->READ_TOC.Msf = 0;
980
981 return(ScsiClassSendSrbSynchronous(DeviceObject,
982 &Srb,
983 Buffer,
984 Length,
985 FALSE));
986 }
987
988
989 /**********************************************************************
990 * NAME EXPORTED
991 * CdromClassDeviceControl
992 *
993 * DESCRIPTION:
994 * Answer requests for device control calls
995 *
996 * RUN LEVEL:
997 * PASSIVE_LEVEL
998 *
999 * ARGUMENTS:
1000 * DeviceObject
1001 * Irp
1002 * Standard dispatch arguments
1003 *
1004 * RETURNS:
1005 * Status.
1006 */
1007
1008 NTSTATUS STDCALL
1009 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1010 IN PIRP Irp)
1011 {
1012 PDEVICE_EXTENSION DeviceExtension;
1013 PIO_STACK_LOCATION IrpStack;
1014 ULONG ControlCode, InputLength, OutputLength;
1015 PCDROM_DATA CdromData;
1016 ULONG Information;
1017 NTSTATUS Status;
1018
1019 DPRINT("CdromClassDeviceControl() called!\n");
1020
1021 Status = STATUS_INVALID_DEVICE_REQUEST;
1022 Information = 0;
1023 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1024 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1025 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1026 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1027 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1028 CdromData = (PCDROM_DATA)(DeviceExtension + 1);
1029
1030 switch (ControlCode)
1031 {
1032 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1033 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1034 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1035 {
1036 Status = STATUS_INFO_LENGTH_MISMATCH;
1037 break;
1038 }
1039 IoMarkIrpPending (Irp);
1040 IoStartPacket (DeviceObject,
1041 Irp,
1042 NULL,
1043 NULL);
1044 return STATUS_PENDING;
1045
1046 case IOCTL_CDROM_CHECK_VERIFY:
1047 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
1048 if (OutputLength != 0 && OutputLength < sizeof (ULONG))
1049 {
1050 DPRINT1("Buffer too small\n");
1051 Status = STATUS_BUFFER_TOO_SMALL;
1052 break;
1053 }
1054 IoMarkIrpPending (Irp);
1055 IoStartPacket (DeviceObject,
1056 Irp,
1057 NULL,
1058 NULL);
1059 return STATUS_PENDING;
1060
1061 case IOCTL_CDROM_READ_TOC:
1062 DPRINT("IOCTL_CDROM_READ_TOC\n");
1063 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
1064 {
1065 Status = STATUS_INFO_LENGTH_MISMATCH;
1066 }
1067 else
1068 {
1069 PCDROM_TOC TocBuffer;
1070 USHORT Length;
1071
1072 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1073
1074 /* First read the lead out */
1075 Length = 4 + sizeof(TRACK_DATA);
1076 Status = CdromClassReadTocEntry(DeviceObject,
1077 0xAA,
1078 TocBuffer,
1079 Length);
1080 if (NT_SUCCESS(Status))
1081 {
1082 if (TocBuffer->FirstTrack == 0xaa)
1083 {
1084 /* there is an empty cd */
1085 Information = Length;
1086 }
1087 else
1088 {
1089 /* read the toc */
1090 Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
1091 Status = CdromClassReadTocEntry(DeviceObject,
1092 TocBuffer->FirstTrack,
1093 TocBuffer, Length);
1094 if (NT_SUCCESS(Status))
1095 {
1096 Information = Length;
1097 }
1098 }
1099 }
1100 }
1101 break;
1102
1103 case IOCTL_CDROM_GET_LAST_SESSION:
1104 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
1105 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
1106 {
1107 Status = STATUS_INFO_LENGTH_MISMATCH;
1108 }
1109 else
1110 {
1111 PCDROM_TOC TocBuffer;
1112 USHORT Length;
1113
1114 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1115 Length = 4 + sizeof(TRACK_DATA);
1116 Status = CdromClassReadLastSession(DeviceObject,
1117 0,
1118 TocBuffer,
1119 Length);
1120 if (NT_SUCCESS(Status))
1121 {
1122 Information = Length;
1123 }
1124 }
1125 break;
1126
1127 default:
1128 /* Call the common device control function */
1129 return(ScsiClassDeviceControl(DeviceObject, Irp));
1130 }
1131
1132 /* Verify the device if the user caused the error */
1133 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
1134 {
1135 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1136 }
1137
1138 Irp->IoStatus.Status = Status;
1139 Irp->IoStatus.Information = Information;
1140 IoCompleteRequest(Irp,
1141 IO_DISK_INCREMENT);
1142
1143 return Status;
1144 }
1145
1146
1147 /**********************************************************************
1148 * NAME
1149 * CdromClassStartIo
1150 *
1151 * DESCRIPTION:
1152 * Starts IRP processing.
1153 *
1154 * RUN LEVEL:
1155 * PASSIVE_LEVEL
1156 *
1157 * ARGUMENTS:
1158 * DeviceObject
1159 * Irp
1160 * Standard dispatch arguments
1161 *
1162 * RETURNS:
1163 * None.
1164 */
1165 VOID STDCALL
1166 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
1167 IN PIRP Irp)
1168 {
1169 PDEVICE_EXTENSION DeviceExtension;
1170 PIO_STACK_LOCATION IrpStack;
1171 PIO_STACK_LOCATION SubIrpStack;
1172 ULONG MaximumTransferLength;
1173 ULONG TransferPages;
1174 PSCSI_REQUEST_BLOCK Srb;
1175 PIRP SubIrp;
1176 PUCHAR SenseBuffer;
1177 PVOID DataBuffer;
1178 PCDB Cdb;
1179
1180 DPRINT("CdromClassStartIo() called!\n");
1181
1182 IoMarkIrpPending (Irp);
1183
1184 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1185 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1186
1187 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1188
1189 if (DeviceObject->Flags & DO_VERIFY_VOLUME)
1190 {
1191 if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1192 {
1193 DPRINT1 ("Verify required\n");
1194
1195 if (Irp->Tail.Overlay.Thread)
1196 {
1197 IoSetHardErrorOrVerifyDevice (Irp,
1198 DeviceObject);
1199 }
1200 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1201
1202 /* FIXME: Update drive capacity */
1203 IoCompleteRequest (Irp,
1204 IO_DISK_INCREMENT);
1205 IoStartNextPacket (DeviceObject,
1206 FALSE);
1207 return;
1208 }
1209 }
1210
1211 if (IrpStack->MajorFunction == IRP_MJ_READ)
1212 {
1213 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
1214
1215 TransferPages =
1216 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
1217 IrpStack->Parameters.Read.Length);
1218
1219 /* Check transfer size */
1220 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
1221 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
1222 {
1223 /* Transfer size is too large - split it */
1224 TransferPages =
1225 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1226
1227 /* Adjust transfer size */
1228 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
1229 MaximumTransferLength = TransferPages * PAGE_SIZE;
1230
1231 if (MaximumTransferLength == 0)
1232 MaximumTransferLength = PAGE_SIZE;
1233
1234 /* Split the transfer */
1235 ScsiClassSplitRequest (DeviceObject,
1236 Irp,
1237 MaximumTransferLength);
1238 return;
1239 }
1240 else
1241 {
1242 /* Build SRB */
1243 ScsiClassBuildRequest (DeviceObject,
1244 Irp);
1245 }
1246 }
1247 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1248 {
1249 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1250
1251 /* Allocate an IRP for sending requests to the port driver */
1252 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1253 FALSE);
1254 if (SubIrp == NULL)
1255 {
1256 Irp->IoStatus.Information = 0;
1257 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1258 IoCompleteRequest (Irp,
1259 IO_DISK_INCREMENT);
1260 IoStartNextPacket (DeviceObject,
1261 FALSE);
1262 return;
1263 }
1264
1265 /* Allocate an SRB */
1266 Srb = ExAllocatePool (NonPagedPool,
1267 sizeof (SCSI_REQUEST_BLOCK));
1268 if (Srb == NULL)
1269 {
1270 IoFreeIrp (SubIrp);
1271 Irp->IoStatus.Information = 0;
1272 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1273 IoCompleteRequest (Irp,
1274 IO_DISK_INCREMENT);
1275 IoStartNextPacket (DeviceObject,
1276 FALSE);
1277 return;
1278 }
1279
1280 /* Allocte a sense buffer */
1281 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1282 SENSE_BUFFER_SIZE);
1283 if (SenseBuffer == NULL)
1284 {
1285 ExFreePool (Srb);
1286 IoFreeIrp (SubIrp);
1287 Irp->IoStatus.Information = 0;
1288 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1289 IoCompleteRequest (Irp,
1290 IO_DISK_INCREMENT);
1291 IoStartNextPacket (DeviceObject,
1292 FALSE);
1293 return;
1294 }
1295
1296 /* Initialize the IRP */
1297 IoSetNextIrpStackLocation (SubIrp);
1298 SubIrp->IoStatus.Information = 0;
1299 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1300 SubIrp->Flags = 0;
1301 SubIrp->UserBuffer = NULL;
1302
1303 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1304 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1305 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1306
1307 /* Initialize next stack location */
1308 SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
1309 SubIrpStack->MajorFunction = IRP_MJ_SCSI;
1310 SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1311 SubIrpStack->Parameters.Scsi.Srb = Srb;
1312
1313 /* Initialize the SRB */
1314 RtlZeroMemory(Srb,
1315 sizeof (SCSI_REQUEST_BLOCK));
1316 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1317 Srb->PathId = DeviceExtension->PathId;
1318 Srb->TargetId = DeviceExtension->TargetId;
1319 Srb->Lun = DeviceExtension->Lun;
1320 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1321 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1322 Srb->ScsiStatus = 0;
1323 Srb->NextSrb = 0;
1324 Srb->OriginalRequest = SubIrp;
1325 Srb->SenseInfoBuffer = SenseBuffer;
1326 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1327
1328 /* Initialize the CDB */
1329 Cdb = (PCDB)Srb->Cdb;
1330
1331 /* Set the completion routine */
1332 IoSetCompletionRoutine (SubIrp,
1333 CdromDeviceControlCompletion,
1334 Srb,
1335 TRUE,
1336 TRUE,
1337 TRUE);
1338
1339 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1340 {
1341 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1342 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1343 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
1344 Srb->CdbLength = 10;
1345 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
1346 Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
1347 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1348
1349 /* Allocate data buffer */
1350 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1351 sizeof(READ_CAPACITY_DATA));
1352 if (DataBuffer == NULL)
1353 {
1354 Irp->IoStatus.Information = 0;
1355 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1356 IoCompleteRequest (Irp,
1357 IO_DISK_INCREMENT);
1358 ExFreePool (SenseBuffer);
1359 ExFreePool (Srb);
1360 IoFreeIrp (SubIrp);
1361 IoStartNextPacket (DeviceObject,
1362 FALSE);
1363 return;
1364 }
1365
1366 /* Allocate an MDL for the data buffer */
1367 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1368 sizeof(READ_CAPACITY_DATA),
1369 FALSE,
1370 FALSE,
1371 NULL);
1372 if (SubIrp->MdlAddress == NULL)
1373 {
1374 Irp->IoStatus.Information = 0;
1375 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1376 IoCompleteRequest (Irp,
1377 IO_DISK_INCREMENT);
1378 ExFreePool (DataBuffer);
1379 ExFreePool (SenseBuffer);
1380 ExFreePool (Srb);
1381 IoFreeIrp (SubIrp);
1382 IoStartNextPacket (DeviceObject,
1383 FALSE);
1384 return;
1385 }
1386
1387 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1388 Srb->DataBuffer = DataBuffer;
1389
1390 IoCallDriver (DeviceExtension->PortDeviceObject,
1391 SubIrp);
1392 return;
1393
1394 case IOCTL_CDROM_CHECK_VERIFY:
1395 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1396 Srb->CdbLength = 6;
1397 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1398 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1399 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1400
1401 IoCallDriver (DeviceExtension->PortDeviceObject,
1402 SubIrp);
1403 return;
1404
1405 default:
1406 IoCompleteRequest (Irp,
1407 IO_NO_INCREMENT);
1408 return;
1409 }
1410 }
1411
1412 /* Call the SCSI port driver */
1413 IoCallDriver (DeviceExtension->PortDeviceObject,
1414 Irp);
1415 }
1416
1417
1418 NTSTATUS STDCALL
1419 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1420 IN PIRP Irp,
1421 IN PVOID Context)
1422 {
1423 PDEVICE_EXTENSION DeviceExtension;
1424 PDEVICE_EXTENSION PhysicalExtension;
1425 PIO_STACK_LOCATION IrpStack;
1426 PIO_STACK_LOCATION OrigCurrentIrpStack;
1427 PIO_STACK_LOCATION OrigNextIrpStack;
1428 PSCSI_REQUEST_BLOCK Srb;
1429 PIRP OrigIrp;
1430 BOOLEAN Retry;
1431 NTSTATUS Status;
1432
1433 DPRINT ("CdromDeviceControlCompletion() called\n");
1434
1435 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1436 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1437 Srb = (PSCSI_REQUEST_BLOCK) Context;
1438
1439 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1440
1441 /* Get the original IRP */
1442 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1443 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1444 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1445
1446 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1447 {
1448 Status = STATUS_SUCCESS;
1449 }
1450 else
1451 {
1452 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1453
1454 /* Interpret sense info */
1455 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1456 Srb,
1457 IrpStack->MajorFunction,
1458 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1459 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1460 &Status);
1461 DPRINT ("Retry %u\n", Retry);
1462
1463 if (Retry == TRUE &&
1464 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
1465 {
1466 DPRINT1 ("Try again (Retry count %lu)\n",
1467 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
1468
1469 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1--;
1470
1471 /* Release 'old' buffers */
1472 ExFreePool (Srb->SenseInfoBuffer);
1473 if (Srb->DataBuffer)
1474 ExFreePool(Srb->DataBuffer);
1475 ExFreePool(Srb);
1476
1477 if (Irp->MdlAddress != NULL)
1478 IoFreeMdl(Irp->MdlAddress);
1479
1480 IoFreeIrp(Irp);
1481
1482 /* Call the StartIo routine again */
1483 CdromClassStartIo (DeviceObject,
1484 OrigIrp);
1485
1486 return STATUS_MORE_PROCESSING_REQUIRED;
1487 }
1488
1489 DPRINT ("Status %lx\n", Status);
1490 }
1491
1492 if (NT_SUCCESS (Status))
1493 {
1494 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1495 {
1496 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1497 {
1498 PREAD_CAPACITY_DATA CapacityBuffer;
1499 ULONG LastSector;
1500 ULONG SectorSize;
1501
1502 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1503
1504 CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1505 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1506 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1507 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1508 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1509
1510 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1511 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1512 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1513 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1514
1515 if (SectorSize == 0)
1516 SectorSize = 2048;
1517 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1518
1519 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1520 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1521 DeviceExtension->SectorShift);
1522 DeviceExtension->PartitionLength.QuadPart =
1523 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1524
1525 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1526 {
1527 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1528 }
1529 else
1530 {
1531 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1532 }
1533 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1534 (LONGLONG)((LastSector + 1)/(32 * 64));
1535 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1536 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1537
1538 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1539 DeviceExtension->DiskGeometry,
1540 sizeof(DISK_GEOMETRY));
1541 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1542 }
1543 break;
1544
1545 case IOCTL_CDROM_CHECK_VERIFY:
1546 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1547 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1548 {
1549 /* Return the media change counter */
1550 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1551 PhysicalExtension->MediaChangeCount;
1552 OrigIrp->IoStatus.Information = sizeof(ULONG);
1553 }
1554 else
1555 {
1556 OrigIrp->IoStatus.Information = 0;
1557 }
1558 break;
1559
1560 default:
1561 OrigIrp->IoStatus.Information = 0;
1562 Status = STATUS_INVALID_DEVICE_REQUEST;
1563 break;
1564 }
1565 }
1566
1567 /* Release the SRB and associated buffers */
1568 if (Srb != NULL)
1569 {
1570 DPRINT("Srb %p\n", Srb);
1571
1572 if (Srb->DataBuffer != NULL)
1573 ExFreePool (Srb->DataBuffer);
1574
1575 if (Srb->SenseInfoBuffer != NULL)
1576 ExFreePool (Srb->SenseInfoBuffer);
1577
1578 ExFreePool (Srb);
1579 }
1580
1581 if (OrigIrp->PendingReturned)
1582 {
1583 IoMarkIrpPending (OrigIrp);
1584 }
1585
1586 /* Release the MDL */
1587 if (Irp->MdlAddress != NULL)
1588 {
1589 IoFreeMdl (Irp->MdlAddress);
1590 }
1591
1592 /* Release the sub irp */
1593 IoFreeIrp (Irp);
1594
1595 /* Set io status information */
1596 OrigIrp->IoStatus.Status = Status;
1597 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1598 {
1599 IoSetHardErrorOrVerifyDevice (OrigIrp,
1600 DeviceObject);
1601 OrigIrp->IoStatus.Information = 0;
1602 }
1603
1604 /* Complete the original IRP */
1605 IoCompleteRequest (OrigIrp,
1606 IO_DISK_INCREMENT);
1607 IoStartNextPacket (DeviceObject,
1608 FALSE);
1609
1610 DPRINT ("CdromDeviceControlCompletion() done\n");
1611
1612 return STATUS_MORE_PROCESSING_REQUIRED;
1613 }
1614
1615
1616 VOID STDCALL
1617 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
1618 IN PVOID Context)
1619 {
1620 PIO_WORKITEM WorkItem;
1621
1622 DPRINT ("CdromTimerRoutine() called\n");
1623 WorkItem = IoAllocateWorkItem(DeviceObject);
1624 if (!WorkItem)
1625 {
1626 return;
1627 }
1628
1629 IoQueueWorkItem(WorkItem,
1630 CdromWorkItem,
1631 DelayedWorkQueue,
1632 WorkItem);
1633 }
1634
1635
1636 VOID
1637 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
1638 IN PVOID Context)
1639 {
1640 PIRP Irp;
1641 KEVENT Event;
1642 IO_STATUS_BLOCK IoStatus;
1643 NTSTATUS Status;
1644
1645 DPRINT("CdromWorkItem() called\n");
1646
1647 IoFreeWorkItem((PIO_WORKITEM) Context);
1648
1649 KeInitializeEvent(&Event,
1650 NotificationEvent,
1651 FALSE);
1652
1653 Irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
1654 DeviceObject,
1655 NULL,
1656 0,
1657 NULL,
1658 0,
1659 FALSE,
1660 &Event,
1661 &IoStatus);
1662 if (Irp == NULL)
1663 {
1664 DPRINT("IoBuildDeviceIoControlRequest failed\n");
1665 return;
1666 }
1667
1668 Status = IoCallDriver(DeviceObject, Irp);
1669 DPRINT("Status: %x\n", Status);
1670
1671 if (Status == STATUS_PENDING)
1672 {
1673 KeWaitForSingleObject(&Event,
1674 Suspended,
1675 KernelMode,
1676 FALSE,
1677 NULL);
1678 }
1679 }
1680
1681 /* EOF */