7dcc3614a1d0982e19baa4c629a14384f301d5dc
[reactos.git] / drivers / storage / class / cdrom_new / mmc.c
1 /*--
2
3 Copyright (C) Microsoft Corporation, 2000
4
5 Module Name:
6
7 mmc.c
8
9 Abstract:
10
11 This file is used to extend cdrom.sys to detect and use mmc-compatible
12 drives' capabilities more wisely.
13
14 Environment:
15
16 kernel mode only
17
18 Notes:
19
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
22
23 Revision History:
24
25 --*/
26
27 #include "cdrom.h"
28
29 NTSTATUS
30 NTAPI
31 CdRomGetConfiguration(
32 IN PDEVICE_OBJECT Fdo,
33 OUT PGET_CONFIGURATION_HEADER *Buffer,
34 OUT PULONG BytesReturned,
35 IN FEATURE_NUMBER StartingFeature,
36 IN ULONG RequestedType
37 );
38
39 VOID
40 NTAPI
41 CdRompPrintAllFeaturePages(
42 IN PGET_CONFIGURATION_HEADER Buffer,
43 IN ULONG Usable
44 );
45
46 NTSTATUS
47 NTAPI
48 CdRomUpdateMmcDriveCapabilitiesCompletion(
49 IN PDEVICE_OBJECT Unused,
50 IN PIRP Irp,
51 IN PDEVICE_OBJECT Fdo
52 );
53
54 VOID
55 NTAPI
56 CdRomPrepareUpdateCapabilitiesIrp(
57 PDEVICE_OBJECT Fdo
58 );
59
60 /*++
61
62 NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
63 if memory is non-paged
64 PRESUMES ALL DATA IS ACCESSIBLE based on FeatureBuffer
65
66 --*/
67 VOID
68 NTAPI
69 CdRomFindProfileInProfiles(
70 IN PFEATURE_DATA_PROFILE_LIST ProfileHeader,
71 IN FEATURE_PROFILE_TYPE ProfileToFind,
72 OUT PBOOLEAN Found
73 )
74 {
75 PFEATURE_DATA_PROFILE_LIST_EX profile;
76 ULONG numberOfProfiles;
77 ULONG i;
78
79 ASSERT((ProfileHeader->Header.AdditionalLength % 4) == 0);
80
81 *Found = FALSE;
82
83 numberOfProfiles = ProfileHeader->Header.AdditionalLength / 4;
84 profile = ProfileHeader->Profiles; // zero-sized array
85
86 for (i = 0; i < numberOfProfiles; i++) {
87
88 FEATURE_PROFILE_TYPE currentProfile;
89
90 currentProfile =
91 (profile->ProfileNumber[0] << 8) |
92 (profile->ProfileNumber[1] & 0xff);
93
94 if (currentProfile == ProfileToFind) {
95
96 *Found = TRUE;
97
98 }
99
100 profile++;
101 }
102 return;
103
104 }
105
106
107 /*++
108
109 NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
110 if memory is non-paged
111
112 --*/
113 PVOID
114 NTAPI
115 CdRomFindFeaturePage(
116 IN PGET_CONFIGURATION_HEADER FeatureBuffer,
117 IN ULONG Length,
118 IN FEATURE_NUMBER Feature
119 )
120 {
121 PUCHAR buffer;
122 PUCHAR limit;
123
124 if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) {
125 return NULL;
126 }
127
128 //
129 // set limit to point to first illegal address
130 //
131
132 limit = (PUCHAR)FeatureBuffer;
133 limit += Length;
134
135 //
136 // set buffer to point to first page
137 //
138
139 buffer = FeatureBuffer->Data;
140
141 //
142 // loop through each page until we find the requested one, or
143 // until it's not safe to access the entire feature header
144 // (if equal, have exactly enough for the feature header)
145 //
146 while (buffer + sizeof(FEATURE_HEADER) <= limit) {
147
148 PFEATURE_HEADER header = (PFEATURE_HEADER)buffer;
149 FEATURE_NUMBER thisFeature;
150
151 thisFeature =
152 (header->FeatureCode[0] << 8) |
153 (header->FeatureCode[1]);
154
155 if (thisFeature == Feature) {
156
157 PUCHAR temp;
158
159 //
160 // if don't have enough memory to safely access all the feature
161 // information, return NULL
162 //
163 temp = buffer;
164 temp += sizeof(FEATURE_HEADER);
165 temp += header->AdditionalLength;
166
167 if (temp > limit) {
168
169 //
170 // this means the transfer was cut-off, an insufficiently
171 // small buffer was given, or other arbitrary error. since
172 // it's not safe to view the amount of data (even though
173 // the header is safe) in this feature, pretend it wasn't
174 // transferred at all...
175 //
176
177 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
178 "Feature %x exists, but not safe to access all its "
179 "data. returning NULL\n", Feature));
180 return NULL;
181 } else {
182 return buffer;
183 }
184 }
185
186 if (header->AdditionalLength % 4) {
187 ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
188 return NULL;
189 }
190
191 buffer += sizeof(FEATURE_HEADER);
192 buffer += header->AdditionalLength;
193
194 }
195 return NULL;
196 }
197
198 /*++
199
200 Private so we can later expose to someone wanting to use a preallocated buffer
201
202 --*/
203 NTSTATUS
204 NTAPI
205 CdRompGetConfiguration(
206 IN PDEVICE_OBJECT Fdo,
207 IN PGET_CONFIGURATION_HEADER Buffer,
208 IN ULONG BufferSize,
209 OUT PULONG ValidBytes,
210 IN FEATURE_NUMBER StartingFeature,
211 IN ULONG RequestedType
212 )
213 {
214 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
215 PCDROM_DATA cdData;
216 SCSI_REQUEST_BLOCK srb;
217 PCDB cdb;
218 ULONG_PTR returned;
219 NTSTATUS status;
220
221 PAGED_CODE();
222 ASSERT(Buffer);
223 ASSERT(ValidBytes);
224
225 *ValidBytes = 0;
226 returned = 0;
227
228 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
229 RtlZeroMemory(Buffer, BufferSize);
230
231 fdoExtension = Fdo->DeviceExtension;
232 cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
233
234 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) {
235 return STATUS_INVALID_DEVICE_REQUEST;
236 }
237
238 srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
239 srb.CdbLength = 10;
240
241 cdb = (PCDB)srb.Cdb;
242 cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
243 cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType;
244 cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8);
245 cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff);
246 cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8);
247 cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff);
248
249 status = ClassSendSrbSynchronous(Fdo, &srb, Buffer,
250 BufferSize, FALSE);
251 returned = srb.DataTransferLength;
252
253 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
254 "CdromGetConfiguration: Status was %x\n", status));
255
256 if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
257
258 //
259 // if returned more than can be stored in a ULONG, return false
260 //
261
262 if (returned > (ULONG)(-1)) {
263 return STATUS_UNSUCCESSFUL;
264 }
265 ASSERT(returned <= BufferSize);
266 *ValidBytes = (ULONG)returned;
267 return STATUS_SUCCESS;
268
269 } else {
270
271 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
272 "CdromGetConfiguration: failed %x\n", status));
273 return status;
274
275 }
276 ASSERT(FALSE);
277 return STATUS_UNSUCCESSFUL;
278 }
279
280 /*++
281
282 Allocates buffer with configuration info, returns STATUS_SUCCESS
283 or an error if one occurred
284
285 NOTE: does not handle case where more than 65000 bytes are returned,
286 which requires multiple calls with different starting feature
287 numbers.
288
289 --*/
290 NTSTATUS
291 NTAPI
292 CdRomGetConfiguration(
293 IN PDEVICE_OBJECT Fdo,
294 OUT PGET_CONFIGURATION_HEADER *Buffer,
295 OUT PULONG BytesReturned,
296 IN FEATURE_NUMBER StartingFeature,
297 IN ULONG RequestedType
298 )
299 {
300 //PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
301 GET_CONFIGURATION_HEADER header; // eight bytes, not a lot
302 PGET_CONFIGURATION_HEADER buffer;
303 ULONG returned;
304 ULONG size;
305 ULONG i;
306 NTSTATUS status;
307
308 PAGED_CODE();
309
310
311 //fdoExtension = Fdo->DeviceExtension;
312 *Buffer = NULL;
313 *BytesReturned = 0;
314
315 buffer = NULL;
316 returned = 0;
317
318 //
319 // send the first request down to just get the header
320 //
321
322 status = CdRompGetConfiguration(Fdo, &header, sizeof(header),
323 &returned, StartingFeature, RequestedType);
324
325 if (!NT_SUCCESS(status)) {
326 return status;
327 }
328
329 //
330 // now try again, using information returned to allocate
331 // just enough memory
332 //
333
334 size = header.DataLength[0] << 24 |
335 header.DataLength[1] << 16 |
336 header.DataLength[2] << 8 |
337 header.DataLength[3] << 0 ;
338
339
340 for (i = 0; i < 4; i++) {
341
342 //
343 // the datalength field is the size *following*
344 // itself, so adjust accordingly
345 //
346
347 size += 4*sizeof(UCHAR);
348
349 //
350 // make sure the size is reasonable
351 //
352
353 if (size <= sizeof(FEATURE_HEADER)) {
354 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
355 "CdromGetConfiguration: drive reports only %x bytes?\n",
356 size));
357 return STATUS_UNSUCCESSFUL;
358 }
359
360 //
361 // allocate the memory
362 //
363
364 buffer = (PGET_CONFIGURATION_HEADER)
365 ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
366 size,
367 CDROM_TAG_FEATURE);
368
369 if (buffer == NULL) {
370 return STATUS_INSUFFICIENT_RESOURCES;
371 }
372
373 //
374 // send the first request down to just get the header
375 //
376
377 status = CdRompGetConfiguration(Fdo, buffer, size, &returned,
378 StartingFeature, RequestedType);
379
380 if (!NT_SUCCESS(status)) {
381 ExFreePool(buffer);
382 return status;
383 }
384
385 if (returned > size) {
386 ExFreePool(buffer);
387 return STATUS_INTERNAL_ERROR;
388 }
389
390 returned = buffer->DataLength[0] << 24 |
391 buffer->DataLength[1] << 16 |
392 buffer->DataLength[2] << 8 |
393 buffer->DataLength[3] << 0 ;
394 returned += 4*sizeof(UCHAR);
395
396 if (returned <= size) {
397 *Buffer = buffer;
398 *BytesReturned = size; // amount of 'safe' memory
399 return STATUS_SUCCESS;
400 }
401
402 //
403 // else retry using the new size....
404 //
405
406 size = returned;
407 ExFreePool(buffer);
408 buffer = NULL;
409
410 }
411
412 //
413 // it failed after a number of attempts, so just fail.
414 //
415
416 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
417 "CdRomGetConfiguration: Failed %d attempts to get all feature "
418 "information\n", i));
419 return STATUS_IO_DEVICE_ERROR;
420 }
421
422 VOID
423 NTAPI
424 CdRomIsDeviceMmcDevice(
425 IN PDEVICE_OBJECT Fdo,
426 OUT PBOOLEAN IsMmc
427 )
428 {
429 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
430 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
431 PCDROM_DATA cdData = commonExtension->DriverData;
432 GET_CONFIGURATION_HEADER localHeader;
433 NTSTATUS status;
434 ULONG usable;
435 ULONG size;
436 ULONG previouslyFailed;
437
438 PAGED_CODE();
439 ASSERT( commonExtension->IsFdo );
440
441 *IsMmc = FALSE;
442
443 //
444 // read the registry in case the drive failed previously,
445 // and a timeout is occurring.
446 //
447
448 previouslyFailed = FALSE;
449 ClassGetDeviceParameter(fdoExtension,
450 CDROM_SUBKEY_NAME,
451 CDROM_NON_MMC_DRIVE_NAME,
452 &previouslyFailed
453 );
454
455 if (previouslyFailed) {
456 SET_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
457 }
458
459 //
460 // check for the following profiles:
461 //
462 // ProfileList
463 //
464
465 status = CdRompGetConfiguration(Fdo,
466 &localHeader,
467 sizeof(localHeader),
468 &usable,
469 FeatureProfileList,
470 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
471
472 if (status == STATUS_INVALID_DEVICE_REQUEST ||
473 status == STATUS_NO_MEDIA_IN_DEVICE ||
474 status == STATUS_IO_DEVICE_ERROR ||
475 status == STATUS_IO_TIMEOUT) {
476
477 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
478 "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
479 status, Fdo
480 ));
481 previouslyFailed = TRUE;
482 ClassSetDeviceParameter(fdoExtension,
483 CDROM_SUBKEY_NAME,
484 CDROM_NON_MMC_DRIVE_NAME,
485 previouslyFailed
486 );
487 return;
488
489 } else if (!NT_SUCCESS(status)) {
490
491 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
492 "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
493 status));
494 return;
495
496 } else if (usable < sizeof(GET_CONFIGURATION_HEADER)) {
497
498 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
499 "GetConfiguration Failed, returned only %x bytes!\n", usable));
500 previouslyFailed = TRUE;
501 ClassSetDeviceParameter(fdoExtension,
502 CDROM_SUBKEY_NAME,
503 CDROM_NON_MMC_DRIVE_NAME,
504 previouslyFailed
505 );
506 return;
507
508 }
509
510 size = (localHeader.DataLength[0] << 24) |
511 (localHeader.DataLength[1] << 16) |
512 (localHeader.DataLength[2] << 8) |
513 (localHeader.DataLength[3] << 0);
514
515 if(size <= 4) {
516 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
517 "GetConfiguration Failed, claims MMC support but doesn't "
518 "correctly return config length!\n"));
519 return;
520 }
521
522 size += 4; // sizeof the datalength fields
523
524 #if DBG
525 {
526 PGET_CONFIGURATION_HEADER dbgBuffer;
527 NTSTATUS dbgStatus;
528
529 dbgBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
530 (SIZE_T)size,
531 CDROM_TAG_FEATURE);
532 if (dbgBuffer != NULL) {
533 RtlZeroMemory(dbgBuffer, size);
534
535 dbgStatus = CdRompGetConfiguration(Fdo, dbgBuffer, size,
536 &size, FeatureProfileList,
537 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
538
539 if (NT_SUCCESS(dbgStatus)) {
540 CdRompPrintAllFeaturePages(dbgBuffer, usable);
541 }
542 ExFreePool(dbgBuffer);
543 }
544 }
545 #endif // DBG
546
547 *IsMmc = TRUE;
548 return;
549 }
550
551 VOID
552 NTAPI
553 CdRompPrintAllFeaturePages(
554 IN PGET_CONFIGURATION_HEADER Buffer,
555 IN ULONG Usable
556 )
557 {
558 PFEATURE_HEADER header;
559
560 ////////////////////////////////////////////////////////////////////////////////
561 // items expected to ALWAYS be current
562 ////////////////////////////////////////////////////////////////////////////////
563 header = CdRomFindFeaturePage(Buffer, Usable, FeatureProfileList);
564 if (header != NULL) {
565 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
566 "CdromGetConfiguration: CurrentProfile %x "
567 "with %x bytes of data at %p\n",
568 Buffer->CurrentProfile[0] << 8 |
569 Buffer->CurrentProfile[1],
570 Usable, Buffer));
571 }
572
573 header = CdRomFindFeaturePage(Buffer, Usable, FeatureCore);
574 if (header) {
575 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
576 "CdromGetConfiguration: %s %s\n",
577 (header->Current ?
578 "Currently supports" : "Is able to support"),
579 "CORE Features"
580 ));
581 }
582
583 header = CdRomFindFeaturePage(Buffer, Usable, FeatureMorphing);
584 if (header) {
585 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
586 "CdromGetConfiguration: %s %s\n",
587 (header->Current ?
588 "Currently supports" : "Is able to support"),
589 "Morphing"
590 ));
591 }
592
593 header = CdRomFindFeaturePage(Buffer, Usable, FeatureMultiRead);
594 if (header) {
595 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
596 "CdromGetConfiguration: %s %s\n",
597 (header->Current ?
598 "Currently supports" : "Is able to support"),
599 "Multi-Read"
600 ));
601 }
602 header = CdRomFindFeaturePage(Buffer, Usable, FeatureRemovableMedium);
603 if (header) {
604 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
605 "CdromGetConfiguration: %s %s\n",
606 (header->Current ?
607 "Currently supports" : "Is able to support"),
608 "Removable Medium"
609 ));
610 }
611
612 header = CdRomFindFeaturePage(Buffer, Usable, FeatureTimeout);
613 if (header) {
614 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
615 "CdromGetConfiguration: %s %s\n",
616 (header->Current ?
617 "Currently supports" : "Is able to support"),
618 "Timeouts"
619 ));
620 }
621
622 header = CdRomFindFeaturePage(Buffer, Usable, FeaturePowerManagement);
623 if (header) {
624 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
625 "CdromGetConfiguration: %s %s\n",
626 (header->Current ?
627 "Currently supports" : "Is able to support"),
628 "Power Management"
629 ));
630 }
631
632 header = CdRomFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger);
633 if (header) {
634 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
635 "CdromGetConfiguration: %s %s\n",
636 (header->Current ?
637 "Currently supports" : "Is able to support"),
638 "Embedded Changer"
639 ));
640 }
641
642 header = CdRomFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber);
643 if (header) {
644 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
645 "CdromGetConfiguration: %s %s\n",
646 (header->Current ?
647 "Currently supports" : "Is able to support"),
648 "LUN Serial Number"
649 ));
650 }
651
652
653 header = CdRomFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade);
654 if (header) {
655 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
656 "CdromGetConfiguration: %s %s\n",
657 (header->Current ?
658 "Currently supports" : "Is able to support"),
659 "Microcode Update"
660 ));
661 }
662
663 ////////////////////////////////////////////////////////////////////////////////
664 // items expected not to always be current
665 ////////////////////////////////////////////////////////////////////////////////
666 header = CdRomFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay);
667 if (header) {
668 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
669 "CdromGetConfiguration: %s %s\n",
670 (header->Current ?
671 "Currently supports" : "Is able to support"),
672 "Analogue CD Audio Operations"
673 ));
674 }
675
676 header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdRead);
677 if (header) {
678 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
679 "CdromGetConfiguration: %s %s\n",
680 (header->Current ?
681 "Currently supports" : "Is able to support"),
682 "reading from CD-ROM/R/RW"
683 ));
684 }
685
686 header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdMastering);
687 if (header) {
688 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
689 "CdromGetConfiguration: %s %s\n",
690 (header->Current ?
691 "Currently supports" : "Is able to support"),
692 "CD Recording (Mastering)"
693 ));
694 }
695
696 header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce);
697 if (header) {
698 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
699 "CdromGetConfiguration: %s %s\n",
700 (header->Current ?
701 "Currently supports" : "Is able to support"),
702 "CD Recording (Track At Once)"
703 ));
704 }
705
706 header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCSS);
707 if (header) {
708 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
709 "CdromGetConfiguration: %s %s\n",
710 (header->Current ?
711 "Currently supports" : "Is able to support"),
712 "DVD CSS"
713 ));
714 }
715
716 header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRead);
717 if (header) {
718 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
719 "CdromGetConfiguration: %s %s\n",
720 (header->Current ?
721 "Currently supports" : "Is able to support"),
722 "DVD Structure Reads"
723 ));
724 }
725
726 header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite);
727 if (header) {
728 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
729 "CdromGetConfiguration: %s %s\n",
730 (header->Current ?
731 "Currently supports" : "Is able to support"),
732 "DVD Recording (Mastering)"
733 ));
734 }
735
736 header = CdRomFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks);
737 if (header) {
738 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
739 "CdromGetConfiguration: %s %s\n",
740 (header->Current ?
741 "Currently supports" : "Is able to support"),
742 "DVD Disc Control Blocks"
743 ));
744 }
745
746 header = CdRomFindFeaturePage(Buffer, Usable, FeatureFormattable);
747 if (header) {
748 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
749 "CdromGetConfiguration: %s %s\n",
750 (header->Current ?
751 "Currently supports" : "Is able to support"),
752 "Formatting"
753 ));
754 }
755
756 header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomReadable);
757 if (header) {
758 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
759 "CdromGetConfiguration: %s %s\n",
760 (header->Current ?
761 "Currently supports" : "Is able to support"),
762 "Random Reads"
763 ));
764 }
765
766 header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomWritable);
767 if (header) {
768 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
769 "CdromGetConfiguration: %s %s\n",
770 (header->Current ?
771 "Currently supports" : "Is able to support"),
772 "Random Writes"
773 ));
774 }
775
776 header = CdRomFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite);
777 if (header) {
778 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
779 "CdromGetConfiguration: %s %s\n",
780 (header->Current ?
781 "Currently supports" : "Is able to support"),
782 "Restricted Overwrites."
783 ));
784 }
785
786 header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteOnce);
787 if (header) {
788 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
789 "CdromGetConfiguration: %s %s\n",
790 (header->Current ?
791 "Currently supports" : "Is able to support"),
792 "Write Once Media"
793 ));
794 }
795
796 header = CdRomFindFeaturePage(Buffer, Usable, FeatureSectorErasable);
797 if (header) {
798 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
799 "CdromGetConfiguration: %s %s\n",
800 (header->Current ?
801 "Currently supports" : "Is able to support"),
802 "Sector Erasable Media"
803 ));
804 }
805
806 header = CdRomFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable);
807 if (header) {
808 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
809 "CdromGetConfiguration: %s %s\n",
810 (header->Current ?
811 "Currently supports" : "Is able to support"),
812 "Incremental Streaming Writing"
813 ));
814 }
815
816 header = CdRomFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming);
817 if (header) {
818 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
819 "CdromGetConfiguration: %s %s\n",
820 (header->Current ?
821 "Currently supports" : "Is able to support"),
822 "Real-time Streaming Reads"
823 ));
824 }
825
826 header = CdRomFindFeaturePage(Buffer, Usable, FeatureSMART);
827 if (header) {
828 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
829 "CdromGetConfiguration: %s %s\n",
830 (header->Current ?
831 "Currently supports" : "Is able to support"),
832 "S.M.A.R.T."
833 ));
834 }
835
836 header = CdRomFindFeaturePage(Buffer, Usable, FeatureDefectManagement);
837 if (header) {
838 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
839 "CdromGetConfiguration: %s %s\n",
840 (header->Current ?
841 "Currently supports" : "Is able to support"),
842 "defect management"
843 ));
844 }
845 return;
846 }
847
848 NTSTATUS
849 NTAPI
850 CdRomUpdateMmcDriveCapabilitiesCompletion(
851 IN PDEVICE_OBJECT Unused,
852 IN PIRP Irp,
853 IN PDEVICE_OBJECT Fdo
854 )
855 {
856 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
857 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
858 PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
859 PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
860 PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
861 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
862 NTSTATUS status = STATUS_UNSUCCESSFUL;
863 //PIRP delayedIrp;
864 ULONG retryCount;
865 LARGE_INTEGER delay;
866
867
868 // completion routine should retry as necessary.
869 // when success, clear the flag to allow startio to proceed.
870 // else fail original request when retries are exhausted.
871
872 ASSERT(mmcData->CapabilitiesIrp == Irp);
873
874 // for now, if succeeded, just print the new pages.
875
876 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
877
878 //
879 // ISSUE-2000/4/20-henrygab - should we try to reallocate if size
880 // available became larger than what we
881 // originally allocated? otherwise, it
882 // is possible (not probable) that we
883 // would miss the feature. can check
884 // that by finding out what the last
885 // feature is in the current group.
886 //
887
888 BOOLEAN retry;
889 ULONG retryInterval;
890
891 //
892 // Release the queue if it is frozen.
893 //
894
895 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
896 ClassReleaseQueue(Fdo);
897 }
898
899 retry = ClassInterpretSenseInfo(
900 Fdo,
901 srb,
902 irpStack->MajorFunction,
903 0,
904 MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
905 &status,
906 &retryInterval);
907
908 //
909 // DATA_OVERRUN is not an error in this case....
910 //
911
912 if (status == STATUS_DATA_OVERRUN) {
913 status = STATUS_SUCCESS;
914 }
915
916 //
917 // override verify_volume based on original irp's settings
918 //
919
920 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
921 status == STATUS_VERIFY_REQUIRED) {
922 status = STATUS_IO_DEVICE_ERROR;
923 retry = TRUE;
924 }
925
926 //
927 // get current retry count
928 //
929 retryCount = PtrToUlong(irpStack->Parameters.Others.Argument1);
930
931 if (retry && retryCount) {
932
933 //
934 // update retry count
935 //
936 irpStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
937
938
939 delay.QuadPart = retryInterval;
940 delay.QuadPart *= (LONGLONG)1000 * 1000 * 10;
941
942 //
943 // retry the request
944 //
945
946 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
947 "Not using ClassRetryRequest Yet\n"));
948 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
949 "Retry update capabilities %p\n", Irp));
950 CdRomPrepareUpdateCapabilitiesIrp(Fdo);
951
952 CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
953
954 //
955 // ClassRetryRequest(Fdo, Irp, delay);
956 //
957
958 return STATUS_MORE_PROCESSING_REQUIRED;
959
960 }
961
962 } else {
963
964 status = STATUS_SUCCESS;
965
966 }
967
968 Irp->IoStatus.Status = status;
969
970 KeSetEvent(&mmcData->CapabilitiesEvent, IO_CD_ROM_INCREMENT, FALSE);
971
972
973 return STATUS_MORE_PROCESSING_REQUIRED;
974 }
975
976 VOID
977 NTAPI
978 CdRomPrepareUpdateCapabilitiesIrp(
979 PDEVICE_OBJECT Fdo
980 )
981 {
982 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
983 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
984 PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
985 PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
986 PIO_STACK_LOCATION nextStack;
987 PSCSI_REQUEST_BLOCK srb;
988 PCDB cdb;
989 ULONG bufferSize;
990 PIRP irp;
991
992 ASSERT(mmcData->UpdateState);
993 ASSERT(ExQueryDepthSList(&(mmcData->DelayedIrps)) != 0);
994 ASSERT(mmcData->CapabilitiesIrp != NULL);
995 ASSERT(mmcData->CapabilitiesMdl != NULL);
996 ASSERT(mmcData->CapabilitiesBuffer);
997 ASSERT(mmcData->CapabilitiesBufferSize != 0);
998 ASSERT(fdoExtension->SenseData);
999
1000 //
1001 // do *NOT* call IoReuseIrp(), since it would zero out our
1002 // current irp stack location, which we really don't want
1003 // to happen. it would also set the current irp stack location
1004 // to one greater than currently exists (to give max irp usage),
1005 // but we don't want that either, since we use the top irp stack.
1006 //
1007 // IoReuseIrp(mmcData->CapabilitiesIrp, STATUS_UNSUCCESSFUL);
1008 //
1009
1010 irp = mmcData->CapabilitiesIrp;
1011 srb = &(mmcData->CapabilitiesSrb);
1012 cdb = (PCDB)(srb->Cdb);
1013 bufferSize = mmcData->CapabilitiesBufferSize;
1014
1015 //
1016 // zero stuff out
1017 //
1018
1019 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1020 RtlZeroMemory(fdoExtension->SenseData, sizeof(SENSE_DATA));
1021 RtlZeroMemory(mmcData->CapabilitiesBuffer, bufferSize);
1022
1023 //
1024 // setup the srb
1025 //
1026
1027 srb->TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
1028 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1029 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1030 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1031 srb->SenseInfoBuffer = fdoExtension->SenseData;
1032 srb->DataBuffer = mmcData->CapabilitiesBuffer;
1033 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1034 srb->DataTransferLength = mmcData->CapabilitiesBufferSize;
1035 srb->ScsiStatus = 0;
1036 srb->SrbStatus = 0;
1037 srb->NextSrb = NULL;
1038 srb->OriginalRequest = irp;
1039 srb->SrbFlags = fdoExtension->SrbFlags;
1040 srb->CdbLength = 10;
1041 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
1042 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
1043
1044 //
1045 // setup the cdb
1046 //
1047
1048 cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
1049 cdb->GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT;
1050 cdb->GET_CONFIGURATION.StartingFeature[0] = 0;
1051 cdb->GET_CONFIGURATION.StartingFeature[1] = 0;
1052 cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
1053 cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
1054
1055 //
1056 // setup the irp
1057 //
1058
1059 nextStack = IoGetNextIrpStackLocation(irp);
1060 nextStack->MajorFunction = IRP_MJ_SCSI;
1061 nextStack->Parameters.Scsi.Srb = srb;
1062 irp->MdlAddress = mmcData->CapabilitiesMdl;
1063 irp->AssociatedIrp.SystemBuffer = mmcData->CapabilitiesBuffer;
1064 IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE)CdRomUpdateMmcDriveCapabilitiesCompletion, Fdo,
1065 TRUE, TRUE, TRUE);
1066
1067 return;
1068
1069 }
1070
1071 VOID
1072 NTAPI
1073 CdRomUpdateMmcDriveCapabilities(
1074 IN PDEVICE_OBJECT Fdo,
1075 IN PVOID Context
1076 )
1077 {
1078 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1079 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1080 PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
1081 PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
1082 PIO_STACK_LOCATION thisStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
1083 PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
1084 NTSTATUS status;
1085
1086
1087 ASSERT(Context == NULL);
1088
1089 //
1090 // NOTE: a remove lock is unnecessary, since the delayed irp
1091 // will have said lock held for itself, preventing a remove.
1092 //
1093 CdRomPrepareUpdateCapabilitiesIrp(Fdo);
1094
1095 ASSERT(thisStack->Parameters.Others.Argument1 == Fdo);
1096 ASSERT(thisStack->Parameters.Others.Argument2 == mmcData->CapabilitiesBuffer);
1097 ASSERT(thisStack->Parameters.Others.Argument3 == &(mmcData->CapabilitiesSrb));
1098
1099 mmcData->WriteAllowed = FALSE; // default to read-only
1100
1101 //
1102 // set max retries, and also allow volume verify override based on
1103 // original (delayed) irp
1104 //
1105
1106 thisStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
1107
1108 //
1109 // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
1110 // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL
1111 //
1112
1113 IoCallDriver(commonExtension->LowerDeviceObject, mmcData->CapabilitiesIrp);
1114
1115 KeWaitForSingleObject(&mmcData->CapabilitiesEvent,
1116 Executive, KernelMode, FALSE, NULL);
1117
1118 status = mmcData->CapabilitiesIrp->IoStatus.Status;
1119
1120 if (!NT_SUCCESS(status)) {
1121
1122 goto FinishDriveUpdate;
1123
1124 }
1125
1126 //
1127 // we've updated the feature set, so update whether or not reads and writes
1128 // are allowed or not.
1129 //
1130
1131 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1132 "CdRomUpdateMmc => Succeeded "
1133 "--------------------"
1134 "--------------------\n"));
1135
1136 /*++
1137
1138 NOTE: It is important to only use srb->DataTransferLength worth
1139 of data at this point, since the bufferSize is what is
1140 *available* to use, not what was *actually* used.
1141
1142 --*/
1143
1144 #if DBG
1145 CdRompPrintAllFeaturePages(mmcData->CapabilitiesBuffer,
1146 srb->DataTransferLength);
1147 #endif // DBG
1148
1149 //
1150 // update whether or not writes are allowed. this is currently defined
1151 // as requiring TargetDefectManagement and RandomWritable features
1152 //
1153 {
1154 PFEATURE_HEADER defectHeader;
1155 PFEATURE_HEADER writableHeader;
1156
1157 defectHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
1158 srb->DataTransferLength,
1159 FeatureDefectManagement);
1160 writableHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
1161 srb->DataTransferLength,
1162 FeatureRandomWritable);
1163
1164 if ((defectHeader != NULL) && (writableHeader != NULL) &&
1165 (defectHeader->Current) && (writableHeader->Current)) {
1166
1167 //
1168 // this should be the *ONLY* place writes are set to allowed
1169 //
1170
1171 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1172 "CdRomUpdateMmc => Writes *allowed*\n"));
1173 mmcData->WriteAllowed = TRUE;
1174
1175 } else {
1176
1177 if (defectHeader == NULL) {
1178 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1179 "CdRomUpdateMmc => No writes - %s = %s\n",
1180 "defect management", "DNE"));
1181 } else {
1182 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1183 "CdRomUpdateMmc => No writes - %s = %s\n",
1184 "defect management", "Not Current"));
1185 }
1186 if (writableHeader == NULL) {
1187 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1188 "CdRomUpdateMmc => No writes - %s = %s\n",
1189 "sector writable", "DNE"));
1190 } else {
1191 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1192 "CdRomUpdateMmc => No writes - %s = %s\n",
1193 "sector writable", "Not Current"));
1194 }
1195 } // end of feature checking
1196 } // end of check for writability
1197
1198 //
1199 // update the cached partition table information
1200 //
1201 // NOTE: THIS WILL CURRENTLY CAUSE A DEADLOCK!
1202 //
1203 // ISSUE-2000/06/20-henrygab - partition support not implemented
1204 // IoReadPartitionTable must be done
1205 // at PASSIVE level, requiring a thread
1206 // or worker item or other such method.
1207 //
1208 #if 0
1209 status = IoReadPartitionTable(Fdo, 1 << fdoExtension->SectorShift,
1210 TRUE, &mmcData->PartitionList);
1211 if (!NT_SUCCESS(status)) {
1212
1213 goto FinishDriveUpdate;
1214
1215 }
1216 #endif
1217
1218 status = STATUS_SUCCESS;
1219
1220 FinishDriveUpdate:
1221
1222 CdRompFlushDelayedList(Fdo, mmcData, status, TRUE);
1223
1224 return;
1225 }
1226
1227 VOID
1228 NTAPI
1229 CdRompFlushDelayedList(
1230 IN PDEVICE_OBJECT Fdo,
1231 IN PCDROM_MMC_EXTENSION MmcData,
1232 IN NTSTATUS Status,
1233 IN BOOLEAN CalledFromWorkItem
1234 )
1235 {
1236 PSINGLE_LIST_ENTRY list;
1237 PIRP irp;
1238
1239 // NOTE - REF #0002
1240 //
1241 // need to set the new state first to prevent deadlocks.
1242 // this is only done from the workitem, to prevent any
1243 // edge cases where we'd "lose" the UpdateRequired
1244 //
1245 // then, must ignore the state, since it's not guaranteed to
1246 // be the same any longer. the only thing left is to handle
1247 // all the delayed irps by flushing the queue and sending them
1248 // back onto the StartIo queue for the device.
1249 //
1250
1251 if (CalledFromWorkItem) {
1252
1253 LONG oldState;
1254 LONG newState;
1255
1256 if (NT_SUCCESS(Status)) {
1257 newState = CdromMmcUpdateComplete;
1258 } else {
1259 newState = CdromMmcUpdateRequired;
1260 }
1261
1262 oldState = InterlockedCompareExchange(&MmcData->UpdateState,
1263 newState,
1264 CdromMmcUpdateStarted);
1265 ASSERT(oldState == CdromMmcUpdateStarted);
1266
1267 } else {
1268
1269 //
1270 // just flushing the queue if not called from the workitem,
1271 // and we don't want to ever fail the queue in those cases.
1272 //
1273
1274 ASSERT(NT_SUCCESS(Status));
1275
1276 }
1277
1278 list = ExInterlockedFlushSList(&MmcData->DelayedIrps);
1279
1280 // if this assert fires, it means that we have started
1281 // a workitem when the previous workitem took the delayed
1282 // irp. if this happens, then the logic in HACKHACK #0002
1283 // is either flawed or the rules set within are not being
1284 // followed. this would require investigation.
1285
1286 ASSERT(list != NULL);
1287
1288 //
1289 // now either succeed or fail all the delayed irps, according
1290 // to the update status.
1291 //
1292
1293 while (list != NULL) {
1294
1295 irp = (PIRP)( ((PUCHAR)list) -
1296 FIELD_OFFSET(IRP, Tail.Overlay.DriverContext[0])
1297 );
1298 list = list->Next;
1299 irp->Tail.Overlay.DriverContext[0] = 0;
1300 irp->Tail.Overlay.DriverContext[1] = 0;
1301 irp->Tail.Overlay.DriverContext[2] = 0;
1302 irp->Tail.Overlay.DriverContext[3] = 0;
1303
1304 if (NT_SUCCESS(Status)) {
1305
1306 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1307 "CdRomUpdateMmc => Re-sending delayed irp %p\n",
1308 irp));
1309 IoStartPacket(Fdo, irp, NULL, NULL);
1310
1311 } else {
1312
1313 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1314 "CdRomUpdateMmc => Failing delayed irp %p with "
1315 " status %x\n", irp, Status));
1316 irp->IoStatus.Information = 0;
1317 irp->IoStatus.Status = Status;
1318 ClassReleaseRemoveLock(Fdo, irp);
1319 IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);
1320
1321 }
1322
1323 } // while (list)
1324
1325 return;
1326
1327 }
1328
1329 VOID
1330 NTAPI
1331 CdRomDeAllocateMmcResources(
1332 IN PDEVICE_OBJECT Fdo
1333 )
1334 {
1335 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1336 PCDROM_DATA cddata = commonExtension->DriverData;
1337 PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
1338 //NTSTATUS status;
1339
1340 if (mmcData->CapabilitiesWorkItem) {
1341 IoFreeWorkItem(mmcData->CapabilitiesWorkItem);
1342 mmcData->CapabilitiesWorkItem = NULL;
1343 }
1344 if (mmcData->CapabilitiesIrp) {
1345 IoFreeIrp(mmcData->CapabilitiesIrp);
1346 mmcData->CapabilitiesIrp = NULL;
1347 }
1348 if (mmcData->CapabilitiesMdl) {
1349 IoFreeMdl(mmcData->CapabilitiesMdl);
1350 mmcData->CapabilitiesMdl = NULL;
1351 }
1352 if (mmcData->CapabilitiesBuffer) {
1353 ExFreePool(mmcData->CapabilitiesBuffer);
1354 mmcData->CapabilitiesBuffer = NULL;
1355 }
1356 mmcData->CapabilitiesBuffer = 0;
1357 mmcData->IsMmc = FALSE;
1358 mmcData->WriteAllowed = FALSE;
1359
1360 return;
1361 }
1362
1363 NTSTATUS
1364 NTAPI
1365 CdRomAllocateMmcResources(
1366 IN PDEVICE_OBJECT Fdo
1367 )
1368 {
1369 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1370 PCDROM_DATA cddata = commonExtension->DriverData;
1371 PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
1372 PIO_STACK_LOCATION irpStack;
1373 NTSTATUS status;
1374
1375 ASSERT(mmcData->CapabilitiesWorkItem == NULL);
1376 ASSERT(mmcData->CapabilitiesIrp == NULL);
1377 ASSERT(mmcData->CapabilitiesMdl == NULL);
1378 ASSERT(mmcData->CapabilitiesBuffer == NULL);
1379 ASSERT(mmcData->CapabilitiesBufferSize == 0);
1380
1381 status = CdRomGetConfiguration(Fdo,
1382 &mmcData->CapabilitiesBuffer,
1383 &mmcData->CapabilitiesBufferSize,
1384 FeatureProfileList,
1385 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
1386 if (!NT_SUCCESS(status)) {
1387 ASSERT(mmcData->CapabilitiesBuffer == NULL);
1388 ASSERT(mmcData->CapabilitiesBufferSize == 0);
1389 return status;
1390 }
1391 ASSERT(mmcData->CapabilitiesBuffer != NULL);
1392 ASSERT(mmcData->CapabilitiesBufferSize != 0);
1393
1394 mmcData->CapabilitiesMdl = IoAllocateMdl(mmcData->CapabilitiesBuffer,
1395 mmcData->CapabilitiesBufferSize,
1396 FALSE, FALSE, NULL);
1397 if (mmcData->CapabilitiesMdl == NULL) {
1398 ExFreePool(mmcData->CapabilitiesBuffer);
1399 mmcData->CapabilitiesBufferSize = 0;
1400 return STATUS_INSUFFICIENT_RESOURCES;
1401 }
1402
1403
1404 mmcData->CapabilitiesIrp = IoAllocateIrp(Fdo->StackSize + 2, FALSE);
1405 if (mmcData->CapabilitiesIrp == NULL) {
1406 IoFreeMdl(mmcData->CapabilitiesMdl);
1407 ExFreePool(mmcData->CapabilitiesBuffer);
1408 mmcData->CapabilitiesBufferSize = 0;
1409 return STATUS_INSUFFICIENT_RESOURCES;
1410 }
1411
1412 mmcData->CapabilitiesWorkItem = IoAllocateWorkItem(Fdo);
1413 if (mmcData->CapabilitiesWorkItem == NULL) {
1414 IoFreeIrp(mmcData->CapabilitiesIrp);
1415 IoFreeMdl(mmcData->CapabilitiesMdl);
1416 ExFreePool(mmcData->CapabilitiesBuffer);
1417 mmcData->CapabilitiesBufferSize = 0;
1418 return STATUS_INSUFFICIENT_RESOURCES;
1419 }
1420
1421 //
1422 // everything has been allocated, so now prepare it all....
1423 //
1424
1425 MmBuildMdlForNonPagedPool(mmcData->CapabilitiesMdl);
1426 ExInitializeSListHead(&mmcData->DelayedIrps);
1427 KeInitializeSpinLock(&mmcData->DelayedLock);
1428
1429 //
1430 // use the extra stack for internal bookkeeping
1431 //
1432 IoSetNextIrpStackLocation(mmcData->CapabilitiesIrp);
1433 irpStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
1434 irpStack->Parameters.Others.Argument1 = Fdo;
1435 irpStack->Parameters.Others.Argument2 = mmcData->CapabilitiesBuffer;
1436 irpStack->Parameters.Others.Argument3 = &(mmcData->CapabilitiesSrb);
1437 // arg 4 is the retry count
1438
1439 //
1440 // set the completion event to FALSE for now
1441 //
1442
1443 KeInitializeEvent(&mmcData->CapabilitiesEvent,
1444 SynchronizationEvent, FALSE);
1445 return STATUS_SUCCESS;
1446
1447 }
1448