Patch by tinus.Fix media change support for CDROMs. This fixes bug #471. Patch by...
[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 WCHAR NameBuffer[MAX_PATH];
395 UNICODE_STRING Name;
396
397 swprintf (NameBuffer,
398 L"\\Device\\MediaChangeEvent%lu",
399 DeviceNumber);
400 RtlInitUnicodeString (&Name,
401 NameBuffer);
402
403 DeviceExtension->MediaChangeEvent =
404 IoCreateSynchronizationEvent (&Name,
405 &DeviceExtension->MediaChangeEventHandle);
406
407 KeClearEvent (DeviceExtension->MediaChangeEvent);
408 }
409
410
411 /**********************************************************************
412 * NAME EXPORTED
413 * CdromClassCreateDeviceObject
414 *
415 * DESCRIPTION:
416 * Create the raw device and any partition devices on this drive
417 *
418 * RUN LEVEL:
419 * PASSIVE_LEVEL
420 *
421 * ARGUMENTS:
422 * DriverObject
423 * System allocated Driver Object for this driver.
424 * RegistryPath
425 * Name of registry driver service key.
426 * PortDeviceObject
427 * PortNumber
428 * DeviceNumber
429 * Capabilities
430 * InquiryData
431 * InitializationData
432 *
433 * RETURNS:
434 * Status.
435 */
436
437 static NTSTATUS
438 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
439 IN PUNICODE_STRING RegistryPath,
440 IN PDEVICE_OBJECT PortDeviceObject,
441 IN ULONG PortNumber,
442 IN ULONG DeviceNumber,
443 IN PIO_SCSI_CAPABILITIES Capabilities,
444 IN PSCSI_INQUIRY_DATA InquiryData,
445 IN PCLASS_INIT_DATA InitializationData)
446 {
447 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
448 PDEVICE_OBJECT DiskDeviceObject;
449 PCDROM_DATA CdromData;
450 CHAR NameBuffer[80];
451 SCSI_REQUEST_BLOCK Srb;
452 PUCHAR Buffer;
453 ULONG Length;
454 PCDB Cdb;
455 NTSTATUS Status;
456
457 DPRINT("CdromClassCreateDeviceObject() called\n");
458
459 /* Claim the cdrom device */
460 Status = ScsiClassClaimDevice(PortDeviceObject,
461 InquiryData,
462 FALSE,
463 &PortDeviceObject);
464 if (!NT_SUCCESS(Status))
465 {
466 DbgPrint("Could not claim cdrom device\n");
467 return(Status);
468 }
469
470 /* Create cdrom device */
471 sprintf(NameBuffer,
472 "\\Device\\CdRom%lu",
473 DeviceNumber);
474
475 Status = ScsiClassCreateDeviceObject(DriverObject,
476 NameBuffer,
477 NULL,
478 &DiskDeviceObject,
479 InitializationData);
480 if (!NT_SUCCESS(Status))
481 {
482 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
483
484 /* Release (unclaim) the disk */
485 ScsiClassClaimDevice(PortDeviceObject,
486 InquiryData,
487 TRUE,
488 NULL);
489
490 return(Status);
491 }
492
493 DiskDeviceObject->Flags |= DO_DIRECT_IO;
494 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
495 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
496
497 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
498 {
499 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
500 }
501
502 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
503 DiskDeviceExtension->LockCount = 0;
504 DiskDeviceExtension->DeviceNumber = DeviceNumber;
505 DiskDeviceExtension->DeviceObject = DiskDeviceObject;
506 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
507 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
508 DiskDeviceExtension->PortCapabilities = Capabilities;
509 DiskDeviceExtension->StartingOffset.QuadPart = 0;
510 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
511 DiskDeviceExtension->PathId = InquiryData->PathId;
512 DiskDeviceExtension->TargetId = InquiryData->TargetId;
513 DiskDeviceExtension->Lun = InquiryData->Lun;
514
515 /* zero-out disk data */
516 CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
517 RtlZeroMemory(CdromData,
518 sizeof(CDROM_DATA));
519
520 DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
521 sizeof(SENSE_DATA));
522 if (DiskDeviceExtension->SenseData == NULL)
523 {
524 DPRINT1("Failed to allocate sense data buffer!\n");
525
526 IoDeleteDevice(DiskDeviceObject);
527
528 /* Release (unclaim) the disk */
529 ScsiClassClaimDevice(PortDeviceObject,
530 InquiryData,
531 TRUE,
532 NULL);
533
534 return(STATUS_INSUFFICIENT_RESOURCES);
535 }
536
537 /* Get timeout value */
538 DiskDeviceExtension->TimeOutValue =
539 ScsiClassQueryTimeOutRegistryValue(RegistryPath);
540 if (DiskDeviceExtension->TimeOutValue == 0)
541 DiskDeviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
542
543 /* Initialize lookaside list for SRBs */
544 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
545 4);
546
547 /* Get disk geometry */
548 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
549 sizeof(DISK_GEOMETRY));
550 if (DiskDeviceExtension->DiskGeometry == NULL)
551 {
552 DPRINT1("Failed to allocate geometry buffer!\n");
553
554 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
555
556 IoDeleteDevice(DiskDeviceObject);
557
558 /* Release (unclaim) the disk */
559 ScsiClassClaimDevice(PortDeviceObject,
560 InquiryData,
561 TRUE,
562 NULL);
563
564 return(STATUS_INSUFFICIENT_RESOURCES);
565 }
566
567 /* Read the drive's capacity */
568 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
569 if (!NT_SUCCESS(Status) ||
570 DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
571 {
572 /* Set ISO9660 defaults */
573 DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
574 DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
575 DiskDeviceExtension->SectorShift = 11;
576 DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
577 }
578 else
579 {
580 /* Make sure the BytesPerSector value is a power of 2 */
581 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
582 }
583
584 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
585
586 /* Initialize media change support */
587 CdromClassCreateMediaChangeEvent (DiskDeviceExtension,
588 DeviceNumber);
589 if (DiskDeviceExtension->MediaChangeEvent != NULL)
590 {
591 DPRINT("Allocated media change event!\n");
592
593 /* FIXME: Allocate media change IRP and SRB */
594 }
595
596 /* Use 6 byte xa commands by default */
597 CdromData->XaFlags |= XA_USE_6_BYTE;
598
599 /* Read 'error recovery page' to get additional drive capabilities */
600 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
601
602 RtlZeroMemory (&Srb,
603 sizeof(SCSI_REQUEST_BLOCK));
604 Srb.CdbLength = 6;
605 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
606
607 Cdb = (PCDB)Srb.Cdb;
608 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
609 Cdb->MODE_SENSE.PageCode = 0x01;
610 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
611
612 Buffer = ExAllocatePool (NonPagedPool,
613 max(sizeof(ERROR_RECOVERY_DATA6),
614 max(sizeof(ERROR_RECOVERY_DATA10),
615 max(sizeof(MODE_CAPABILITIES_DATA6),
616 sizeof(MODE_CAPABILITIES_DATA10)))));
617 if (Buffer == NULL)
618 {
619 DPRINT1("Allocating recovery page buffer failed!\n");
620 return STATUS_INSUFFICIENT_RESOURCES;
621 }
622
623 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
624 &Srb,
625 Buffer,
626 Length,
627 FALSE);
628
629 if (!NT_SUCCESS (Status))
630 {
631 DPRINT("MODE_SENSE(6) failed\n");
632
633 /* Try the 10 byte version */
634 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH10;
635
636 RtlZeroMemory (&Srb,
637 sizeof(SCSI_REQUEST_BLOCK));
638 Srb.CdbLength = 10;
639 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
640
641 Cdb = (PCDB)Srb.Cdb;
642 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
643 Cdb->MODE_SENSE10.PageCode = 0x01;
644 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
645 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
646
647 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
648 &Srb,
649 Buffer,
650 Length,
651 FALSE);
652
653 if (Status == STATUS_DATA_OVERRUN)
654 {
655 DPRINT1("Data overrun\n");
656
657 /* FIXME */
658 }
659 else if (NT_SUCCESS (Status))
660 {
661 DPRINT("Use 10 byte commands\n");
662 CdromData->XaFlags &= XA_USE_6_BYTE;
663 CdromData->XaFlags |= XA_USE_10_BYTE;
664 }
665 else
666 {
667 DPRINT("XA not supported\n");
668 CdromData->XaFlags |= XA_NOT_SUPPORTED;
669 }
670 }
671 else
672 {
673 DPRINT("Use 6 byte commands\n");
674 }
675
676 /* Read 'capabilities & mechanical status page' to get additional drive capabilities */
677 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
678
679 if (!(CdromData->XaFlags & XA_NOT_SUPPORTED))
680 {
681 RtlZeroMemory (&Srb, sizeof(SCSI_REQUEST_BLOCK));
682 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
683 Cdb = (PCDB)Srb.Cdb;
684
685 if (CdromData->XaFlags & XA_USE_10_BYTE)
686 {
687 /* Try the 10 byte version */
688 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH10;
689
690 Srb.CdbLength = 10;
691 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
692 Cdb->MODE_SENSE10.PageCode = 0x2a;
693 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
694 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
695 }
696 else
697 {
698 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH;
699
700 Srb.CdbLength = 6;
701 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
702 Cdb->MODE_SENSE.PageCode = 0x2a;
703 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
704 }
705 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
706 &Srb,
707 Buffer,
708 Length,
709 FALSE);
710 if (NT_SUCCESS (Status))
711 {
712 #if 0
713 PMODE_CAPABILITIES_PAGE2 CapabilitiesData;
714 if (CdromData->XaFlags & XA_USE_10_BYTE)
715 {
716 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER10));
717 }
718 else
719 {
720 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER));
721 }
722
723 DbgPrint("Capabilities for '%s':\n", NameBuffer);
724 if (CapabilitiesData->Reserved2[0] & 0x20)
725 {
726 DbgPrint(" Drive supports reading of DVD-RAM discs\n");
727 }
728 if (CapabilitiesData->Reserved2[0] & 0x10)
729 {
730 DbgPrint(" Drive supports reading of DVD-R discs\n");
731 }
732 if (CapabilitiesData->Reserved2[0] & 0x08)
733 {
734 DbgPrint(" Drive supports reading of DVD-ROM discs\n");
735 }
736 if (CapabilitiesData->Reserved2[0] & 0x04)
737 {
738 DbgPrint(" Drive supports reading CD-R discs with addressing method 2\n");
739 }
740 if (CapabilitiesData->Reserved2[0] & 0x02)
741 {
742 DbgPrint(" Drive can read from CD-R/W (CD-E) discs (orange book, part III)\n");
743 }
744 if (CapabilitiesData->Reserved2[0] & 0x01)
745 {
746 DbgPrint(" Drive supports read from CD-R discs (orange book, part II)\n");
747 }
748 DPRINT("CapabilitiesData.Reserved2[1] %x\n", CapabilitiesData->Reserved2[1]);
749 if (CapabilitiesData->Reserved2[1] & 0x01)
750 {
751 DbgPrint(" Drive can write to CD-R discs (orange book, part II)\n");
752 }
753 if (CapabilitiesData->Reserved2[1] & 0x02)
754 {
755 DbgPrint(" Drive can write to CD-R/W (CD-E) discs (orange book, part III)\n");
756 }
757 if (CapabilitiesData->Reserved2[1] & 0x04)
758 {
759 DbgPrint(" Drive can fake writes\n");
760 }
761 if (CapabilitiesData->Reserved2[1] & 0x10)
762 {
763 DbgPrint(" Drive can write DVD-R discs\n");
764 }
765 if (CapabilitiesData->Reserved2[1] & 0x20)
766 {
767 DbgPrint(" Drive can write DVD-RAM discs\n");
768 }
769 DPRINT("CapabilitiesData.Capabilities[0] %x\n", CapabilitiesData->Capabilities[0]);
770 if (CapabilitiesData->Capabilities[0] & 0x01)
771 {
772 DbgPrint(" Drive supports audio play operations\n");
773 }
774 if (CapabilitiesData->Capabilities[0] & 0x02)
775 {
776 DbgPrint(" Drive can deliver a composite audio/video data stream\n");
777 }
778 if (CapabilitiesData->Capabilities[0] & 0x04)
779 {
780 DbgPrint(" Drive supports digital output on port 1\n");
781 }
782 if (CapabilitiesData->Capabilities[0] & 0x08)
783 {
784 DbgPrint(" Drive supports digital output on port 2\n");
785 }
786 if (CapabilitiesData->Capabilities[0] & 0x10)
787 {
788 DbgPrint(" Drive can read mode 2, form 1 (XA) data\n");
789 }
790 if (CapabilitiesData->Capabilities[0] & 0x20)
791 {
792 DbgPrint(" Drive can read mode 2, form 2 data\n");
793 }
794 if (CapabilitiesData->Capabilities[0] & 0x40)
795 {
796 DbgPrint(" Drive can read multisession discs\n");
797 }
798 DPRINT("CapabilitiesData.Capabilities[1] %x\n", CapabilitiesData->Capabilities[1]);
799 if (CapabilitiesData->Capabilities[1] & 0x01)
800 {
801 DbgPrint(" Drive can read Red Book audio data\n");
802 }
803 if (CapabilitiesData->Capabilities[1] & 0x02)
804 {
805 DbgPrint(" Drive can continue a read cdda operation from a loss of streaming\n");
806 }
807 if (CapabilitiesData->Capabilities[1] & 0x04)
808 {
809 DbgPrint(" Subchannel reads can return combined R-W information\n");
810 }
811 if (CapabilitiesData->Capabilities[1] & 0x08)
812 {
813 DbgPrint(" R-W data will be returned deinterleaved and error corrected\n");
814 }
815 if (CapabilitiesData->Capabilities[1] & 0x10)
816 {
817 DbgPrint(" Drive supports C2 error pointers\n");
818 }
819 if (CapabilitiesData->Capabilities[1] & 0x20)
820 {
821 DbgPrint(" Drive can return International Standard Recording Code info\n");
822 }
823 if (CapabilitiesData->Capabilities[1] & 0x40)
824 {
825 DbgPrint(" Drive can return Media Catalog Number (UPC) info\n");
826 }
827 DPRINT("CapabilitiesData.Capabilities[2] %x\n", CapabilitiesData->Capabilities[2]);
828 if (CapabilitiesData->Capabilities[2] & 0x01)
829 {
830 DbgPrint(" Drive can lock the door\n");
831 }
832 if (CapabilitiesData->Capabilities[2] & 0x02)
833 {
834 DbgPrint(" The door is locked\n");
835 }
836 if (CapabilitiesData->Capabilities[2] & 0x04)
837 {
838 }
839 if (CapabilitiesData->Capabilities[2] & 0x08)
840 {
841 DbgPrint(" Drive can eject a disc or changer cartridge\n");
842 }
843 if (CapabilitiesData->Capabilities[2] & 0x10)
844 {
845 DbgPrint(" Drive supports C2 error pointers\n");
846 }
847 switch (CapabilitiesData->Capabilities[2] >> 5)
848 {
849 case 0:
850 DbgPrint(" Drive use a caddy type loading mechanism\n");
851 break;
852 case 1:
853 DbgPrint(" Drive use a tray type loading mechanism\n");
854 break;
855 case 2:
856 DbgPrint(" Drive use a pop-up type loading mechanism\n");
857 break;
858 case 4:
859 DbgPrint(" Drive is a changer with individually changeable discs\n");
860 break;
861 case 5:
862 DbgPrint(" Drive is a changer with cartridge mechanism\n");
863 break;
864 }
865 DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData->Capabilities[3]);
866 if (CapabilitiesData->Capabilities[3] & 0x01)
867 {
868 DbgPrint(" Audio level for each channel can be controlled independently\n");
869 }
870 if (CapabilitiesData->Capabilities[3] & 0x02)
871 {
872 DbgPrint(" Audio for each channel can be muted independently\n");
873 }
874 if (CapabilitiesData->Capabilities[3] & 0x04)
875 {
876 DbgPrint(" Changer can report exact contents of slots\n");
877 }
878 if (CapabilitiesData->Capabilities[3] & 0x08)
879 {
880 DbgPrint(" Drive supports software slot selection\n");
881 }
882 DbgPrint(" Maximum speed is %d kB/s\n",
883 (CapabilitiesData->MaximumSpeedSupported[0] << 8)
884 | CapabilitiesData->MaximumSpeedSupported[1]);
885 DbgPrint(" Current speed is %d kB/s\n",
886 (CapabilitiesData->CurrentSpeed[0] << 8)
887 | CapabilitiesData->CurrentSpeed[1]);
888 DbgPrint(" Number of discrete volume levels is %d\n",
889 (CapabilitiesData->Reserved3 << 8)
890 | CapabilitiesData->NumberVolumeLevels);
891 DbgPrint(" Buffer size is %d kB\n",
892 (CapabilitiesData->BufferSize[0] << 8)
893 | CapabilitiesData->BufferSize[1]);
894 #endif
895 }
896 else
897 {
898 DPRINT("XA not supported\n");
899 CdromData->XaFlags |= XA_NOT_SUPPORTED;
900 }
901
902 }
903
904
905 ExFreePool (Buffer);
906
907 /* Initialize device timer */
908 IoInitializeTimer(DiskDeviceObject,
909 CdromTimerRoutine,
910 NULL);
911 IoStartTimer(DiskDeviceObject);
912
913 DPRINT("CdromClassCreateDeviceObjects() done\n");
914
915 return(STATUS_SUCCESS);
916 }
917
918
919 /**********************************************************************
920 * NAME
921 * CdromClassReadTocEntry
922 *
923 * ARGUMENTS:
924 * DeviceObject
925 * TrackNo
926 * Buffer
927 * Length
928 *
929 * RETURNS:
930 * Status.
931 */
932 static NTSTATUS
933 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
934 UINT TrackNo,
935 PVOID Buffer,
936 UINT Length)
937 {
938 PDEVICE_EXTENSION DeviceExtension;
939 SCSI_REQUEST_BLOCK Srb;
940 PCDB Cdb;
941
942 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
943
944 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
945 Srb.CdbLength = 10;
946 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
947
948 Cdb = (PCDB)Srb.Cdb;
949 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
950 Cdb->READ_TOC.StartingTrack = TrackNo;
951 Cdb->READ_TOC.Format = 0;
952 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
953 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
954 Cdb->READ_TOC.Msf = 1;
955
956 return(ScsiClassSendSrbSynchronous(DeviceObject,
957 &Srb,
958 Buffer,
959 Length,
960 FALSE));
961 }
962
963
964 static NTSTATUS
965 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
966 UINT TrackNo,
967 PVOID Buffer,
968 UINT Length)
969 {
970 PDEVICE_EXTENSION DeviceExtension;
971 SCSI_REQUEST_BLOCK Srb;
972 PCDB Cdb;
973
974 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
975
976 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
977 Srb.CdbLength = 10;
978 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
979
980 Cdb = (PCDB)Srb.Cdb;
981 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
982 Cdb->READ_TOC.StartingTrack = TrackNo;
983 Cdb->READ_TOC.Format = 1;
984 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
985 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
986 Cdb->READ_TOC.Msf = 0;
987
988 return(ScsiClassSendSrbSynchronous(DeviceObject,
989 &Srb,
990 Buffer,
991 Length,
992 FALSE));
993 }
994
995
996 /**********************************************************************
997 * NAME EXPORTED
998 * CdromClassDeviceControl
999 *
1000 * DESCRIPTION:
1001 * Answer requests for device control calls
1002 *
1003 * RUN LEVEL:
1004 * PASSIVE_LEVEL
1005 *
1006 * ARGUMENTS:
1007 * DeviceObject
1008 * Irp
1009 * Standard dispatch arguments
1010 *
1011 * RETURNS:
1012 * Status.
1013 */
1014
1015 NTSTATUS STDCALL
1016 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1017 IN PIRP Irp)
1018 {
1019 PDEVICE_EXTENSION DeviceExtension;
1020 PIO_STACK_LOCATION IrpStack;
1021 ULONG ControlCode, InputLength, OutputLength;
1022 PCDROM_DATA CdromData;
1023 ULONG Information;
1024 NTSTATUS Status;
1025
1026 DPRINT("CdromClassDeviceControl() called!\n");
1027
1028 Status = STATUS_INVALID_DEVICE_REQUEST;
1029 Information = 0;
1030 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1031 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1032 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1033 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1034 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1035 CdromData = (PCDROM_DATA)(DeviceExtension + 1);
1036
1037 switch (ControlCode)
1038 {
1039 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1040 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1041 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1042 {
1043 Status = STATUS_INFO_LENGTH_MISMATCH;
1044 break;
1045 }
1046 IoMarkIrpPending (Irp);
1047 IoStartPacket (DeviceObject,
1048 Irp,
1049 NULL,
1050 NULL);
1051 return STATUS_PENDING;
1052
1053 case IOCTL_CDROM_CHECK_VERIFY:
1054 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
1055 if (OutputLength != 0 && OutputLength < sizeof (ULONG))
1056 {
1057 DPRINT1("Buffer too small\n");
1058 Status = STATUS_BUFFER_TOO_SMALL;
1059 break;
1060 }
1061 IoMarkIrpPending (Irp);
1062 IoStartPacket (DeviceObject,
1063 Irp,
1064 NULL,
1065 NULL);
1066 return STATUS_PENDING;
1067
1068 case IOCTL_CDROM_READ_TOC:
1069 DPRINT("IOCTL_CDROM_READ_TOC\n");
1070 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
1071 {
1072 Status = STATUS_INFO_LENGTH_MISMATCH;
1073 }
1074 else
1075 {
1076 PCDROM_TOC TocBuffer;
1077 USHORT Length;
1078
1079 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1080
1081 /* First read the lead out */
1082 Length = 4 + sizeof(TRACK_DATA);
1083 Status = CdromClassReadTocEntry(DeviceObject,
1084 0xAA,
1085 TocBuffer,
1086 Length);
1087 if (NT_SUCCESS(Status))
1088 {
1089 if (TocBuffer->FirstTrack == 0xaa)
1090 {
1091 /* there is an empty cd */
1092 Information = Length;
1093 }
1094 else
1095 {
1096 /* read the toc */
1097 Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
1098 Status = CdromClassReadTocEntry(DeviceObject,
1099 TocBuffer->FirstTrack,
1100 TocBuffer, Length);
1101 if (NT_SUCCESS(Status))
1102 {
1103 Information = Length;
1104 }
1105 }
1106 }
1107 }
1108 break;
1109
1110 case IOCTL_CDROM_GET_LAST_SESSION:
1111 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
1112 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
1113 {
1114 Status = STATUS_INFO_LENGTH_MISMATCH;
1115 }
1116 else
1117 {
1118 PCDROM_TOC TocBuffer;
1119 USHORT Length;
1120
1121 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1122 Length = 4 + sizeof(TRACK_DATA);
1123 Status = CdromClassReadLastSession(DeviceObject,
1124 0,
1125 TocBuffer,
1126 Length);
1127 if (NT_SUCCESS(Status))
1128 {
1129 Information = Length;
1130 }
1131 }
1132 break;
1133
1134 default:
1135 /* Call the common device control function */
1136 return(ScsiClassDeviceControl(DeviceObject, Irp));
1137 }
1138
1139 /* Verify the device if the user caused the error */
1140 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
1141 {
1142 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1143 }
1144
1145 Irp->IoStatus.Status = Status;
1146 Irp->IoStatus.Information = Information;
1147 IoCompleteRequest(Irp,
1148 IO_DISK_INCREMENT);
1149
1150 return Status;
1151 }
1152
1153
1154 /**********************************************************************
1155 * NAME
1156 * CdromClassStartIo
1157 *
1158 * DESCRIPTION:
1159 * Starts IRP processing.
1160 *
1161 * RUN LEVEL:
1162 * PASSIVE_LEVEL
1163 *
1164 * ARGUMENTS:
1165 * DeviceObject
1166 * Irp
1167 * Standard dispatch arguments
1168 *
1169 * RETURNS:
1170 * None.
1171 */
1172 VOID STDCALL
1173 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
1174 IN PIRP Irp)
1175 {
1176 PDEVICE_EXTENSION DeviceExtension;
1177 PIO_STACK_LOCATION IrpStack;
1178 PIO_STACK_LOCATION SubIrpStack;
1179 ULONG MaximumTransferLength;
1180 ULONG TransferPages;
1181 PSCSI_REQUEST_BLOCK Srb;
1182 PIRP SubIrp;
1183 PUCHAR SenseBuffer;
1184 PVOID DataBuffer;
1185 PCDB Cdb;
1186
1187 DPRINT("CdromClassStartIo() called!\n");
1188
1189 IoMarkIrpPending (Irp);
1190
1191 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1192 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1193
1194 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1195
1196 if (DeviceObject->Flags & DO_VERIFY_VOLUME)
1197 {
1198 if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1199 {
1200 DPRINT1 ("Verify required\n");
1201
1202 if (Irp->Tail.Overlay.Thread)
1203 {
1204 IoSetHardErrorOrVerifyDevice (Irp,
1205 DeviceObject);
1206 }
1207 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1208
1209 /* FIXME: Update drive capacity */
1210 IoCompleteRequest (Irp,
1211 IO_DISK_INCREMENT);
1212 IoStartNextPacket (DeviceObject,
1213 FALSE);
1214 return;
1215 }
1216 }
1217
1218 if (IrpStack->MajorFunction == IRP_MJ_READ)
1219 {
1220 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
1221
1222 TransferPages =
1223 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
1224 IrpStack->Parameters.Read.Length);
1225
1226 /* Check transfer size */
1227 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
1228 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
1229 {
1230 /* Transfer size is too large - split it */
1231 TransferPages =
1232 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1233
1234 /* Adjust transfer size */
1235 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
1236 MaximumTransferLength = TransferPages * PAGE_SIZE;
1237
1238 if (MaximumTransferLength == 0)
1239 MaximumTransferLength = PAGE_SIZE;
1240
1241 /* Split the transfer */
1242 ScsiClassSplitRequest (DeviceObject,
1243 Irp,
1244 MaximumTransferLength);
1245 return;
1246 }
1247 else
1248 {
1249 /* Build SRB */
1250 ScsiClassBuildRequest (DeviceObject,
1251 Irp);
1252 }
1253 }
1254 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1255 {
1256 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1257
1258 /* Allocate an IRP for sending requests to the port driver */
1259 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1260 FALSE);
1261 if (SubIrp == NULL)
1262 {
1263 Irp->IoStatus.Information = 0;
1264 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1265 IoCompleteRequest (Irp,
1266 IO_DISK_INCREMENT);
1267 IoStartNextPacket (DeviceObject,
1268 FALSE);
1269 return;
1270 }
1271
1272 /* Allocate an SRB */
1273 Srb = ExAllocatePool (NonPagedPool,
1274 sizeof (SCSI_REQUEST_BLOCK));
1275 if (Srb == NULL)
1276 {
1277 IoFreeIrp (SubIrp);
1278 Irp->IoStatus.Information = 0;
1279 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1280 IoCompleteRequest (Irp,
1281 IO_DISK_INCREMENT);
1282 IoStartNextPacket (DeviceObject,
1283 FALSE);
1284 return;
1285 }
1286
1287 /* Allocte a sense buffer */
1288 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1289 SENSE_BUFFER_SIZE);
1290 if (SenseBuffer == NULL)
1291 {
1292 ExFreePool (Srb);
1293 IoFreeIrp (SubIrp);
1294 Irp->IoStatus.Information = 0;
1295 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1296 IoCompleteRequest (Irp,
1297 IO_DISK_INCREMENT);
1298 IoStartNextPacket (DeviceObject,
1299 FALSE);
1300 return;
1301 }
1302
1303 /* Initialize the IRP */
1304 IoSetNextIrpStackLocation (SubIrp);
1305 SubIrp->IoStatus.Information = 0;
1306 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1307 SubIrp->Flags = 0;
1308 SubIrp->UserBuffer = NULL;
1309
1310 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1311 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1312 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1313
1314 /* Initialize next stack location */
1315 SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
1316 SubIrpStack->MajorFunction = IRP_MJ_SCSI;
1317 SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1318 SubIrpStack->Parameters.Scsi.Srb = Srb;
1319
1320 /* Initialize the SRB */
1321 RtlZeroMemory(Srb,
1322 sizeof (SCSI_REQUEST_BLOCK));
1323 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1324 Srb->PathId = DeviceExtension->PathId;
1325 Srb->TargetId = DeviceExtension->TargetId;
1326 Srb->Lun = DeviceExtension->Lun;
1327 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1328 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1329 Srb->ScsiStatus = 0;
1330 Srb->NextSrb = 0;
1331 Srb->OriginalRequest = SubIrp;
1332 Srb->SenseInfoBuffer = SenseBuffer;
1333 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1334
1335 /* Initialize the CDB */
1336 Cdb = (PCDB)Srb->Cdb;
1337
1338 /* Set the completion routine */
1339 IoSetCompletionRoutine (SubIrp,
1340 CdromDeviceControlCompletion,
1341 Srb,
1342 TRUE,
1343 TRUE,
1344 TRUE);
1345
1346 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1347 {
1348 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1349 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1350 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
1351 Srb->CdbLength = 10;
1352 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
1353 Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
1354 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1355
1356 /* Allocate data buffer */
1357 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1358 sizeof(READ_CAPACITY_DATA));
1359 if (DataBuffer == NULL)
1360 {
1361 Irp->IoStatus.Information = 0;
1362 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1363 IoCompleteRequest (Irp,
1364 IO_DISK_INCREMENT);
1365 ExFreePool (SenseBuffer);
1366 ExFreePool (Srb);
1367 IoFreeIrp (SubIrp);
1368 IoStartNextPacket (DeviceObject,
1369 FALSE);
1370 return;
1371 }
1372
1373 /* Allocate an MDL for the data buffer */
1374 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1375 sizeof(READ_CAPACITY_DATA),
1376 FALSE,
1377 FALSE,
1378 NULL);
1379 if (SubIrp->MdlAddress == NULL)
1380 {
1381 Irp->IoStatus.Information = 0;
1382 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1383 IoCompleteRequest (Irp,
1384 IO_DISK_INCREMENT);
1385 ExFreePool (DataBuffer);
1386 ExFreePool (SenseBuffer);
1387 ExFreePool (Srb);
1388 IoFreeIrp (SubIrp);
1389 IoStartNextPacket (DeviceObject,
1390 FALSE);
1391 return;
1392 }
1393
1394 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1395 Srb->DataBuffer = DataBuffer;
1396
1397 IoCallDriver (DeviceExtension->PortDeviceObject,
1398 SubIrp);
1399 return;
1400
1401 case IOCTL_CDROM_CHECK_VERIFY:
1402 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1403 Srb->CdbLength = 6;
1404 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1405 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1406 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1407
1408 IoCallDriver (DeviceExtension->PortDeviceObject,
1409 SubIrp);
1410 return;
1411
1412 default:
1413 IoCompleteRequest (Irp,
1414 IO_NO_INCREMENT);
1415 return;
1416 }
1417 }
1418
1419 /* Call the SCSI port driver */
1420 IoCallDriver (DeviceExtension->PortDeviceObject,
1421 Irp);
1422 }
1423
1424
1425 NTSTATUS STDCALL
1426 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1427 IN PIRP Irp,
1428 IN PVOID Context)
1429 {
1430 PDEVICE_EXTENSION DeviceExtension;
1431 PDEVICE_EXTENSION PhysicalExtension;
1432 PIO_STACK_LOCATION IrpStack;
1433 PIO_STACK_LOCATION OrigCurrentIrpStack;
1434 PIO_STACK_LOCATION OrigNextIrpStack;
1435 PSCSI_REQUEST_BLOCK Srb;
1436 PIRP OrigIrp;
1437 BOOLEAN Retry;
1438 NTSTATUS Status;
1439
1440 DPRINT ("CdromDeviceControlCompletion() called\n");
1441
1442 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1443 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1444 Srb = (PSCSI_REQUEST_BLOCK) Context;
1445
1446 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1447
1448 /* Get the original IRP */
1449 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1450 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1451 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1452
1453 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1454 {
1455 Status = STATUS_SUCCESS;
1456 }
1457 else
1458 {
1459 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1460
1461 /* Interpret sense info */
1462 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1463 Srb,
1464 IrpStack->MajorFunction,
1465 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1466 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1467 &Status);
1468 DPRINT ("Retry %u\n", Retry);
1469
1470 if (Retry == TRUE &&
1471 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
1472 {
1473 DPRINT1 ("Try again (Retry count %lu)\n",
1474 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
1475
1476 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1--;
1477
1478 /* Release 'old' buffers */
1479 ExFreePool (Srb->SenseInfoBuffer);
1480 if (Srb->DataBuffer)
1481 ExFreePool(Srb->DataBuffer);
1482 ExFreePool(Srb);
1483
1484 if (Irp->MdlAddress != NULL)
1485 IoFreeMdl(Irp->MdlAddress);
1486
1487 IoFreeIrp(Irp);
1488
1489 /* Call the StartIo routine again */
1490 CdromClassStartIo (DeviceObject,
1491 OrigIrp);
1492
1493 return STATUS_MORE_PROCESSING_REQUIRED;
1494 }
1495
1496 DPRINT ("Status %lx\n", Status);
1497 }
1498
1499 if (NT_SUCCESS (Status))
1500 {
1501 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1502 {
1503 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1504 {
1505 PREAD_CAPACITY_DATA CapacityBuffer;
1506 ULONG LastSector;
1507 ULONG SectorSize;
1508
1509 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1510
1511 CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1512 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1513 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1514 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1515 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1516
1517 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1518 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1519 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1520 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1521
1522 if (SectorSize == 0)
1523 SectorSize = 2048;
1524 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1525
1526 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1527 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1528 DeviceExtension->SectorShift);
1529 DeviceExtension->PartitionLength.QuadPart =
1530 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1531
1532 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1533 {
1534 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1535 }
1536 else
1537 {
1538 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1539 }
1540 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1541 (LONGLONG)((LastSector + 1)/(32 * 64));
1542 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1543 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1544
1545 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1546 DeviceExtension->DiskGeometry,
1547 sizeof(DISK_GEOMETRY));
1548 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1549 }
1550 break;
1551
1552 case IOCTL_CDROM_CHECK_VERIFY:
1553 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1554 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1555 {
1556 /* Return the media change counter */
1557 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1558 PhysicalExtension->MediaChangeCount;
1559 OrigIrp->IoStatus.Information = sizeof(ULONG);
1560 }
1561 else
1562 {
1563 OrigIrp->IoStatus.Information = 0;
1564 }
1565 break;
1566
1567 default:
1568 OrigIrp->IoStatus.Information = 0;
1569 Status = STATUS_INVALID_DEVICE_REQUEST;
1570 break;
1571 }
1572 }
1573
1574 /* Release the SRB and associated buffers */
1575 if (Srb != NULL)
1576 {
1577 DPRINT("Srb %p\n", Srb);
1578
1579 if (Srb->DataBuffer != NULL)
1580 ExFreePool (Srb->DataBuffer);
1581
1582 if (Srb->SenseInfoBuffer != NULL)
1583 ExFreePool (Srb->SenseInfoBuffer);
1584
1585 ExFreePool (Srb);
1586 }
1587
1588 if (OrigIrp->PendingReturned)
1589 {
1590 IoMarkIrpPending (OrigIrp);
1591 }
1592
1593 /* Release the MDL */
1594 if (Irp->MdlAddress != NULL)
1595 {
1596 IoFreeMdl (Irp->MdlAddress);
1597 }
1598
1599 /* Release the sub irp */
1600 IoFreeIrp (Irp);
1601
1602 /* Set io status information */
1603 OrigIrp->IoStatus.Status = Status;
1604 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1605 {
1606 IoSetHardErrorOrVerifyDevice (OrigIrp,
1607 DeviceObject);
1608 OrigIrp->IoStatus.Information = 0;
1609 }
1610
1611 /* Complete the original IRP */
1612 IoCompleteRequest (OrigIrp,
1613 IO_DISK_INCREMENT);
1614 IoStartNextPacket (DeviceObject,
1615 FALSE);
1616
1617 DPRINT ("CdromDeviceControlCompletion() done\n");
1618
1619 return STATUS_MORE_PROCESSING_REQUIRED;
1620 }
1621
1622
1623 VOID STDCALL
1624 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
1625 IN PVOID Context)
1626 {
1627 PIO_WORKITEM WorkItem;
1628
1629 DPRINT ("CdromTimerRoutine() called\n");
1630 WorkItem = IoAllocateWorkItem(DeviceObject);
1631 if (!WorkItem)
1632 {
1633 return;
1634 }
1635
1636 IoQueueWorkItem(WorkItem,
1637 CdromWorkItem,
1638 DelayedWorkQueue,
1639 WorkItem);
1640 }
1641
1642
1643 VOID
1644 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
1645 IN PVOID Context)
1646 {
1647 PIRP Irp;
1648 KEVENT Event;
1649 IO_STATUS_BLOCK IoStatus;
1650 NTSTATUS Status;
1651
1652 DPRINT("CdromWorkItem() called\n");
1653
1654 IoFreeWorkItem((PIO_WORKITEM) Context);
1655
1656 KeInitializeEvent(&Event,
1657 NotificationEvent,
1658 FALSE);
1659
1660 Irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
1661 DeviceObject,
1662 NULL,
1663 0,
1664 NULL,
1665 0,
1666 FALSE,
1667 &Event,
1668 &IoStatus);
1669 if (Irp == NULL)
1670 {
1671 DPRINT("IoBuildDeviceIoControlRequest failed\n");
1672 return;
1673 }
1674
1675 Status = IoCallDriver(DeviceObject, Irp);
1676 DPRINT("Status: %x\n", Status);
1677
1678 if (Status == STATUS_PENDING)
1679 {
1680 KeWaitForSingleObject(&Event,
1681 Suspended,
1682 KernelMode,
1683 FALSE,
1684 NULL);
1685 }
1686 }
1687
1688 /* EOF */