1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
7 Module Name: Phys_eject.cpp
9 Execution: Kernel mode only
13 Contains code that implement read/write operations for physical device
17 // define the file specific bug-check id
18 #define UDF_BUG_CHECK_ID UDF_FILE_PHYS_EJECT
26 This routine checks for User Eject request & initiates Dismount
33 PUDFEjectWaitContext WC
= (PUDFEjectWaitContext
)Context
;
35 OSSTATUS RC
= STATUS_SUCCESS
;
39 BOOLEAN UseEvent
= TRUE
;
41 BOOLEAN FlushWCache
= FALSE
;
42 IO_STATUS_BLOCK IoStatus
;
45 PDEVICE_OBJECT TargetDevObj
;
47 uint32 Tree_FlushPriod
;
49 uint32 SkipEjectCount
= 0;
51 uint32 flush_stat
= 0;
52 BOOLEAN UseEject
= TRUE
;
53 BOOLEAN MediaLoss
= FALSE
;
55 BOOLEAN SkipEject
= FALSE
;
56 BOOLEAN SkipFlush
= FALSE
;
58 // BOOLEAN FlushAndEject = FALSE;
60 UDFPrint((" UDFEjectReqWaiter: start\n"));
61 uint8 supported_evt_classes
= 0;
64 BOOLEAN OldLowFreeSpace
= FALSE
;
65 uint32 space_check_counter
= 0x7fffffff;
66 PGET_LAST_ERROR_USER_OUT Error
= NULL
;
68 // Drain out Event Queue
70 TargetDevObj
= Vcb
->TargetDeviceObject
;
71 UseEvent
= Vcb
->UseEvent
;
73 supported_evt_classes
= EventStat_Class_Media
;
75 UDFPrint((" Eject Button ignored\n"));
78 UDFPrint((" Reading events... (0)\n"));
79 if(supported_evt_classes
) {
80 for(i
=1; i
<=EventRetStat_Class_Mask
;i
++) {
81 evt_type
= (((UCHAR
)1) << i
);
82 if( !(supported_evt_classes
& evt_type
) )
84 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->Immed
= TRUE
;
85 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->EventClass
= evt_type
;
87 RC
= UDFPhSendIOCTL( IOCTL_CDRW_GET_EVENT
,
89 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_IN
),
90 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_OUT
),
93 if(RC
== STATUS_INVALID_DEVICE_REQUEST
) {
97 if(RC
== STATUS_NO_SUCH_DEVICE
)
100 supported_evt_classes
= WC
->EjectReqBuffer
.MediaChange
.Header
.SupportedClasses
;
106 if(RC
== STATUS_NO_SUCH_DEVICE
)
109 supported_evt_classes
= 0;
116 delay
.QuadPart
= -10000000; // 1.0 sec
117 WRC
= KeWaitForSingleObject(&(Vcb
->EjectWaiter
->StopReq
), Executive
, KernelMode
, FALSE
, &delay
);
118 if(WRC
== STATUS_SUCCESS
) {
121 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);//) {
122 /* delay.QuadPart = -1000000; // 0.1 sec
123 KeDelayExecutionThread(KernelMode, FALSE, &delay);
126 Vcb
->EjectWaiter
= NULL
;
127 UDFReleaseResource(&(Vcb
->VCBResource
));
129 KeSetEvent(WC
->WaiterStopped
, 0, FALSE
);
132 UDFPrint((" UDFEjectReqWaiter: exit 3\n"));
135 BM_FlushPriod
= Vcb
->BM_FlushPriod
;
136 Tree_FlushPriod
= Vcb
->Tree_FlushPriod
;
138 // check if we approaching end of disk
139 if(space_check_counter
> 2) {
140 // update FreeAllocUnits if it is necessary
141 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) && Vcb
->Modified
) {
142 Vcb
->FreeAllocUnits
= UDFGetFreeSpace(Vcb
);
144 // update LowFreeSpace flag
145 Vcb
->LowFreeSpace
= (Vcb
->FreeAllocUnits
< max(Vcb
->FECharge
,UDF_DEFAULT_FE_CHARGE
)*128);
146 if(Vcb
->LowFreeSpace
&& !OldLowFreeSpace
) {
147 // initiate Flush process if we crossed LowFreeSpace boundary
148 Vcb
->Tree_FlushTime
= Tree_FlushPriod
+1;
149 Vcb
->VCBFlags
&= ~UDF_VCB_SKIP_EJECT_CHECK
;
151 OldLowFreeSpace
= Vcb
->LowFreeSpace
;
152 space_check_counter
= 0;
154 space_check_counter
++;
156 if(Vcb
->VCBFlags
& UDF_VCB_SKIP_EJECT_CHECK
) {
159 SkipEject
= (SkipEjectCount
<= Vcb
->SkipEjectCountLimit
);
160 SkipFlush
= (SkipEjectCount
<= Vcb
->SkipCountLimit
);
161 if(SkipEject
|| SkipFlush
) {
162 Vcb
->VCBFlags
&= ~UDF_VCB_SKIP_EJECT_CHECK
;
169 if(WC
->SoftEjectReq
) {
176 Vcb
->Tree_FlushTime
= 0;
184 if(SkipEject
&& SkipFlush
) {
186 delay
.QuadPart
= -10000000; // 1.0 sec
187 WRC
= KeWaitForSingleObject(&(Vcb
->EjectWaiter
->StopReq
), Executive
, KernelMode
, FALSE
, &delay
);
188 if(WRC
== STATUS_SUCCESS
) {
194 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_LOCKED
) {
198 // check if the door is still locked
200 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
) &&
201 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
)) {
203 UDFAcquireResourceExclusive(&(Vcb
->IoResource
), TRUE
);
204 RC
= UDFPhSendIOCTL( IOCTL_CDRW_GET_CAPABILITIES
,
207 &(WC
->DevCap
),sizeof(GET_CAPABILITIES_USER_OUT
),
210 Error
= &(WC
->Error
);
211 UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR
, Vcb
->TargetDeviceObject
,
213 Error
,sizeof(GET_LAST_ERROR_USER_OUT
),
215 UDFReleaseResource(&(Vcb
->IoResource
));
216 UDFPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n",
217 Error
->SenseKey
, Error
->AdditionalSenseCode
, Error
->AdditionalSenseCodeQualifier
, Error
->LastError
));
218 // check for Long Write In Progress
219 if( ((Error
->SenseKey
== SCSI_SENSE_NOT_READY
) &&
220 (Error
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
221 (Error
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS
||
222 Error
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_FORMAT_IN_PROGRESS
)) ) {
223 if((!Vcb
->Modified
&&
224 !(Vcb
->VCBFlags
& UDF_VCB_LAST_WRITE
))
226 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_UNSAFE_IOCTL
)) {
227 // we should forget about this disk...
228 UDFPrint((" LAST_WRITE %x\n", !!(Vcb
->VCBFlags
& UDF_VCB_LAST_WRITE
)));
229 UDFPrint((" UDF_VCB_FLAGS_UNSAFE_IOCTL %x\n", !!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_UNSAFE_IOCTL
)));
230 UDFPrint((" UDFEjectReqWaiter: Unexpected write-in-progress on !Modified volume\n"));
232 Vcb
->ForgetVolume
= TRUE
;
233 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_READ_ONLY
| UDF_VCB_FLAGS_MEDIA_READ_ONLY
;
238 if( OS_SUCCESS(RC
) &&
239 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
) &&
240 !(WC
->DevCap
.Capabilities2
& DevCap_lock_state
)) {
241 // probably bus reset or power failure occured
243 UDFPrint((" UDFEjectReqWaiter: Unexpected tray unlock encountered. Try to re-lock\n"));
245 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
248 /* UDFResetDeviceDriver(Vcb, TargetDevObj, FALSE);
249 delay.QuadPart = -1000000; // 0.1 sec
250 KeDelayExecutionThread(KernelMode, FALSE, &delay);*/
252 ((PPREVENT_MEDIA_REMOVAL_USER_IN
)(&(WC
->DevCap
)))->PreventMediaRemoval
= TRUE
;
253 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL
,
255 &(WC
->DevCap
),sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
),
258 delay
.QuadPart
= -1000000; // 0.1 sec
259 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
260 // force write mode re-initialization
261 Vcb
->LastModifiedTrack
= 0;
266 UDFVVerify(Vcb
, 0 /* partial verify */);
269 !(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
270 (BM_FlushPriod
|| Tree_FlushPriod
)) {
271 KeQuerySystemTime(&delay
);
272 d
= (uint32
)((delay
.QuadPart
- time
.QuadPart
) / 10000000);
274 Vcb
->BM_FlushTime
+= d
;
275 Vcb
->Tree_FlushTime
+= d
;
281 UDFPrint((" SkipCount=%x, SkipCountLimit=%x\n",
283 Vcb
->SkipCountLimit
));
285 if( Tree_FlushPriod
&&
286 (Tree_FlushPriod
< Vcb
->Tree_FlushTime
)) {
288 UDFPrint((" Tree_FlushPriod %I64x, Vcb->Tree_FlushTime %I64x\n",
290 Vcb
->Tree_FlushTime
));
292 // do not touch unchanged volume
293 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) ||
297 // Acquire Vcb resource
299 if(!UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), FALSE
)) {
300 delay
.QuadPart
= -10000000; // 1.0 sec
301 WRC
= KeWaitForSingleObject(&(Vcb
->EjectWaiter
->StopReq
), Executive
, KernelMode
, FALSE
, &delay
);
302 if(WRC
== STATUS_SUCCESS
) {
310 UDFPrint(("UDF: Flushing Directory Tree....\n"));
312 (BM_FlushPriod
< Vcb
->BM_FlushTime
)) {
313 UDFPrint((" full flush\n"));
314 flush_stat
= UDFFlushADirectory(Vcb
, Vcb
->RootDirFCB
->FileInfo
, &IoStatus
, UDF_FLUSH_FLAGS_BREAKABLE
);
316 UDFPrint((" light flush\n"));
317 flush_stat
= UDFFlushADirectory(Vcb
, Vcb
->RootDirFCB
->FileInfo
, &IoStatus
, UDF_FLUSH_FLAGS_BREAKABLE
| UDF_FLUSH_FLAGS_LITE
);
319 if(flush_stat
& UDF_FLUSH_FLAGS_INTERRUPTED
)
322 UDFVVerify(Vcb
, UFD_VERIFY_FLAG_BG
/* partial verify */);
325 Vcb
->Tree_FlushTime
= 0;
328 (BM_FlushPriod
< Vcb
->BM_FlushTime
)) {
330 UDFPrint((" BM_FlushPriod %I64x, Vcb->BM_FlushTime %I64x\n",
335 // do not touch unchanged volume
336 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
)
342 if(!UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), FlushWCache
/*|| FALSE*/)) {
343 delay
.QuadPart
= -10000000; // 1.0 sec
344 WRC
= KeWaitForSingleObject(&(Vcb
->EjectWaiter
->StopReq
), Executive
, KernelMode
, FALSE
, &delay
);
345 if(WRC
== STATUS_SUCCESS
) {
353 UDFAcquireResourceExclusive(&(Vcb
->BitMapResource1
),TRUE
);
354 // UDF_CHECK_BITMAP_RESOURCE(Vcb);
356 if(Vcb
->FSBM_ByteCount
!= RtlCompareMemory(Vcb
->FSBM_Bitmap
, Vcb
->FSBM_OldBitmap
, Vcb
->FSBM_ByteCount
)) {
364 #ifndef UDF_READ_ONLY_BUILD
365 UDFFlushAllCachedAllocations(Vcb
, UDF_PREALLOC_CLASS_FE
);
366 UDFFlushAllCachedAllocations(Vcb
, UDF_PREALLOC_CLASS_DIR
);
368 UDFUpdateVolIdent(Vcb
, Vcb
->PVolDescAddr
, &(Vcb
->VolIdent
));
369 UDFUpdateVolIdent(Vcb
, Vcb
->PVolDescAddr2
, &(Vcb
->VolIdent
));
371 if(Vcb
->VerifyOnWrite
) {
372 UDFPrint(("UDF: Flushing cache for verify\n"));
373 //WCacheFlushAll__(&(Vcb->FastCache), Vcb);
374 WCacheFlushBlocks__(&(Vcb
->FastCache
), Vcb
, 0, Vcb
->LastLBA
);
378 UDFPrint(("UDF: Flushing Free Space Bitmap....\n"));
380 // if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent))))
381 // UDFPrint(("Error updating VolIdent\n"));
382 if(!OS_SUCCESS(UDFUpdateVDS(Vcb
, Vcb
->VDS1
, Vcb
->VDS1
+ Vcb
->VDS1_Len
, flags
)))
383 UDFPrint(("Error updating Main VDS\n"));
384 if(!OS_SUCCESS(UDFUpdateVDS(Vcb
, Vcb
->VDS2
, Vcb
->VDS2
+ Vcb
->VDS2_Len
, flags
)))
385 UDFPrint(("Error updating Reserve VDS\n"));
387 UDFUpdateVDS(Vcb
, Vcb
->VDS1
, Vcb
->VDS1
+ Vcb
->VDS1_Len
, flags
);
388 UDFUpdateVDS(Vcb
, Vcb
->VDS2
, Vcb
->VDS2
+ Vcb
->VDS2_Len
, flags
);
390 // Update Integrity Desc if any
391 if(Vcb
->LVid
&& Vcb
->origIntegrityType
== INTEGRITY_TYPE_CLOSE
) {
392 UDFUpdateLogicalVolInt(Vcb
, TRUE
);
395 RtlCopyMemory(Vcb
->FSBM_OldBitmap
, Vcb
->FSBM_Bitmap
, Vcb
->FSBM_ByteCount
);
397 #endif //UDF_READ_ONLY_BUILD
398 UDFPreClrModified(Vcb
);
399 UDFReleaseResource(&(Vcb
->BitMapResource1
));
401 Vcb
->BM_FlushTime
= 0;
405 WCacheFlushAll__(&(Vcb
->FastCache
), Vcb
);
409 //Vcb->Modified = FALSE;
415 UDFReleaseResource(&(Vcb
->VCBResource
));
417 if(!Vcb
->Tree_FlushTime
&&
425 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
))
428 UDFPrint((" UDFEjectReqWaiter: check removable media\n"));
429 if(!WC
->SoftEjectReq
&& SkipEject
) {
433 if(!WC
->SoftEjectReq
) {
436 UDFPrint((" Eject Button ignored\n"));
440 /* if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) &&
441 !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) ){
442 // delay.QuadPart = -100000; // 0.01 sec
443 // KeDelayExecutionThread(KernelMode, FALSE, &delay);
446 UDFPrint((" Sync cache before GET_EVENT\n"));
447 RC = UDFSyncCache(Vcb);
448 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
449 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_SYNC_CACHE;
452 // delay.QuadPart = -300000; // 0.03 sec
453 // KeDelayExecutionThread(KernelMode, FALSE, &delay);
454 Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
457 ASSERT(sizeof(TEST_UNIT_READY_USER_OUT
) <= sizeof(GET_EVENT_USER_OUT
));
459 RC
= UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY
,
462 &(WC
->EjectReqBuffer
),sizeof(TEST_UNIT_READY_USER_OUT
),
465 if(RC
!= STATUS_SUCCESS
&&
466 RC
!= STATUS_DATA_OVERRUN
) {
467 if(RC
== STATUS_NO_SUCH_DEVICE
) {
468 UDFPrint((" Device loss\n"));
471 if(RC
== STATUS_NO_MEDIA_IN_DEVICE
) {
472 UDFPrint((" Media loss\n"));
476 UDFPrint((" Reading events...\n"));
477 if(supported_evt_classes
) {
478 for(i
=1; i
<=EventRetStat_Class_Mask
;i
++) {
479 evt_type
= (((UCHAR
)1) << i
);
480 if( !(supported_evt_classes
& evt_type
) )
483 if( evt_type == EventStat_Class_Media )
485 if( evt_type == EventStat_Class_ExternalReq )
488 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->Immed
= TRUE
;
489 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->EventClass
= evt_type
;
491 RC
= UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT
,
493 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_IN
),
494 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_OUT
),
497 if(RC
== STATUS_INVALID_DEVICE_REQUEST
) {
498 supported_evt_classes
&= ~evt_type
;
501 if(RC
== STATUS_NO_SUCH_DEVICE
) {
502 UDFPrint((" Device loss (2)\n"));
505 if(!OS_SUCCESS(RC
)) {
509 if(WC
->EjectReqBuffer
.MediaChange
.Header
.Flags
.Flags
& EventRetStat_NEA
) {
512 if( evt_type
== EventStat_Class_Media
) {
513 UDFPrint((" EventStat_Class_Media:\n"));
514 if((WC
->EjectReqBuffer
.MediaChange
.Header
.Flags
.Flags
& EventRetStat_Class_Mask
) !=
515 EventRetStat_Class_Media
) {
518 retry_media_presence_check
:
519 if(!(WC
->EjectReqBuffer
.MediaChange
.Byte1
.Flags
& EventStat_MediaStat_Present
) ||
520 (WC
->EjectReqBuffer
.MediaChange
.Byte1
.Flags
& EventStat_MediaStat_DoorOpen
)) {
521 // something wrong....
522 RC
= UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY
,
525 &(WC
->EjectReqBuffer
),sizeof(TEST_UNIT_READY_USER_OUT
),
528 if(RC
== STATUS_SUCCESS
||
529 RC
== STATUS_DATA_OVERRUN
) {
530 UDFPrint((" Buggy GET_EVENT media presence flag %x\n",
531 WC
->EjectReqBuffer
.MediaChange
.Byte1
));
532 WC
->EjectReqBuffer
.MediaChange
.Byte1
.Flags
|= EventStat_MediaStat_Present
;
533 WC
->EjectReqBuffer
.MediaChange
.Byte1
.Flags
&= ~EventStat_MediaStat_DoorOpen
;
534 goto retry_media_presence_check
;
537 UDFPrint((" Unexpected media loss. Check device status\n"));
541 // check if eject request occured
542 if( (WC
->EjectReqBuffer
.MediaChange
.Byte0
.Flags
& EventStat_MediaEvent_Mask
) !=
543 EventStat_MediaEvent_EjectReq
) {
546 UDFPrint((" eject requested\n"));
547 WC
->SoftEjectReq
= TRUE
;
550 if( evt_type
== EventStat_Class_ExternalReq
) {
551 UDFPrint((" EventStat_Class_ExternalReq:\n"));
552 if((WC
->EjectReqBuffer
.ExternalReq
.Header
.Flags
.Flags
& EventRetStat_Class_Mask
) !=
553 EventRetStat_Class_ExternReq
)
555 switch(WC
->EjectReqBuffer
.ExternalReq
.Byte0
.Flags
& EventStat_ExtrnReqEvent_Mask
) {
556 case EventStat_ExtrnReqEvent_KeyDown
:
557 case EventStat_ExtrnReqEvent_KeyUp
:
558 case EventStat_ExtrnReqEvent_ExtrnReq
:
559 UDFPrint((" eject requested (%x)\n", WC
->EjectReqBuffer
.ExternalReq
.Byte0
.Flags
));
560 WC
->SoftEjectReq
= TRUE
;
566 if(!supported_evt_classes
) {
569 if(!WC
->SoftEjectReq
) {
574 UDFPrint((" Reading Media Event...\n"));
575 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->Immed
= TRUE
;
576 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->EventClass
= EventStat_Class_Media
;
578 RC
= UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT
,
580 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_IN
),
581 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_OUT
),
584 if(!OS_SUCCESS(RC
)) {
585 if(RC
== STATUS_NO_SUCH_DEVICE
)
587 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->Immed
= TRUE
;
588 ((PGET_EVENT_USER_IN
)(&(WC
->EjectReqBuffer
)))->EventClass
= EventStat_Class_ExternalReq
;
590 RC
= UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT
,
592 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_IN
),
593 &(WC
->EjectReqBuffer
),sizeof(GET_EVENT_USER_OUT
),
596 if(RC
== STATUS_NO_SUCH_DEVICE
)
598 if(RC
== STATUS_INVALID_DEVICE_REQUEST
) {
603 supported_evt_classes
= WC
->EjectReqBuffer
.MediaChange
.Header
.SupportedClasses
;
607 // FlushAndEject = TRUE;
609 // Ok. Lets flush all we have in memory, dismount volume & eject disc
610 // Acquire Vcb resource
611 Vcb
->SoftEjectReq
= TRUE
;
613 UDFPrint((" UDFEjectReqWaiter: ejecting...\n"));
614 #ifdef UDF_DELAYED_CLOSE
615 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
616 UDFPrint((" UDFEjectReqWaiter: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
617 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
618 UDFReleaseResource(&(Vcb
->VCBResource
));
619 #endif //UDF_DELAYED_CLOSE
621 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllSystemDelayedInDir\n"));
622 RC
= UDFCloseAllSystemDelayedInDir(Vcb
, Vcb
->RootDirFCB
->FileInfo
);
623 ASSERT(OS_SUCCESS(RC
));
624 #ifdef UDF_DELAYED_CLOSE
625 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllDelayed\n"));
626 UDFCloseAllDelayed(Vcb
);
627 //ASSERT(OS_SUCCESS(RC));
628 #endif //UDF_DELAYED_CLOSE
630 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
632 UDFPrint((" UDFEjectReqWaiter: UDFDoDismountSequence\n"));
633 UDFDoDismountSequence(Vcb
, (PPREVENT_MEDIA_REMOVAL_USER_IN
)&(WC
->EjectReqBuffer
), UseEject
);
635 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_MOUNTED
;
636 Vcb
->WriteSecurity
= FALSE
;
638 Vcb
->EjectWaiter
= NULL
;
639 Vcb
->SoftEjectReq
= FALSE
;
640 UDFReleaseResource(&(Vcb
->VCBResource
));
642 UDFPrint((" UDFEjectReqWaiter: set WaiterStopped\n"));
643 KeSetEvent(WC
->WaiterStopped
, 0, FALSE
);
647 UDFPrint((" UDFEjectReqWaiter: exit 1\n"));
655 UDFReleaseResource(&(Vcb
->VCBResource
));
659 delay.QuadPart = -10000000; // 1.0 sec
660 WRC = KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, &delay);
661 if(WRC == STATUS_SUCCESS) {
667 // Simply make compiler happy
669 } // end UDFEjectReqWaiter()
672 UDFStopEjectWaiter(PVCB Vcb
) {
674 UDFPrint((" UDFStopEjectWaiter: try\n"));
675 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
677 if(Vcb
->EjectWaiter
) {
678 UDFPrint((" UDFStopEjectWaiter: set flag\n"));
679 KeSetEvent( &(Vcb
->EjectWaiter
->StopReq
), 0, FALSE
);
683 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
686 UDFReleaseResource(&(Vcb
->VCBResource
));
689 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_STOP_WAITER_EVENT
) {
690 UDFPrint((" UDFStopEjectWaiter: wait\n"));
691 KeWaitForSingleObject(&(Vcb
->WaiterStopped
), Executive
, KernelMode
, FALSE
, NULL
);
693 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT
;
694 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
697 ASSERT(!Vcb
->EjectWaiter
);
698 UDFPrint((" UDFStopEjectWaiter: exit\n"));
700 } // end UDFStopEjectWaiter()
703 UDFDoDismountSequence(
705 IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf
,
713 // flush system cache
714 UDFFlushLogicalVolume(NULL
, NULL
, Vcb
, 0);
715 UDFPrint(("UDFDoDismountSequence:\n"));
717 delay
.QuadPart
= -1000000; // 0.1 sec
718 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
719 // wait for completion of all backgroung writes
720 while(Vcb
->BGWriters
) {
721 delay
.QuadPart
= -5000000; // 0.5 sec
722 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
725 WCacheRelease__(&(Vcb
->FastCache
));
727 UDFAcquireResourceExclusive(&(Vcb
->IoResource
), TRUE
);
729 // unlock media, drop our own Locks
730 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
) {
731 UDFPrint((" cleanup tray-lock (%d+2):\n", Vcb
->MediaLockCount
));
732 for(i
=0; i
<Vcb
->MediaLockCount
+2; i
++) {
733 Buf
->PreventMediaRemoval
= FALSE
;
734 UDFPhSendIOCTL(IOCTL_STORAGE_MEDIA_REMOVAL
,
735 Vcb
->TargetDeviceObject
,
736 Buf
,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
),
739 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
741 delay
.QuadPart
= -2000000; // 0.2 sec
744 if(!Vcb
->ForgetVolume
) {
746 if(!UDFIsDvdMedia(Vcb
)) {
747 // send speed limits to drive
748 UDFPrint((" Restore drive speed on dismount\n"));
749 Vcb
->SpeedBuf
.ReadSpeed
= Vcb
->MaxReadSpeed
;
750 Vcb
->SpeedBuf
.WriteSpeed
= Vcb
->MaxWriteSpeed
;
751 UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED
,
752 Vcb
->TargetDeviceObject
,
753 &(Vcb
->SpeedBuf
),sizeof(SET_CD_SPEED_USER_IN
),
757 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_OUR_DEVICE_DRIVER
) {
758 CLOSE_TRK_SES_USER_IN CBuff
;
761 UDFResetDeviceDriver(Vcb
, Vcb
->TargetDeviceObject
, TRUE
);
762 delay
.QuadPart
= -2000000; // 0.2 sec
763 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
765 memset(&CBuff
,0,sizeof(CLOSE_TRK_SES_USER_IN
));
768 UDFPrint((" Stop background formatting\n"));
770 CBuff
.Byte1
.Flags
= 0;//CloseTrkSes_Immed;
771 CBuff
.Byte2
.Flags
= CloseTrkSes_Ses
;
774 UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES
,
775 Vcb
->TargetDeviceObject
,
776 &CBuff
,sizeof(CLOSE_TRK_SES_USER_IN
),
777 &CBuff
,sizeof(CLOSE_TRK_SES_USER_IN
),
780 if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
781 UDFPrint((" Close BG-formatted track\n"));
783 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed;
784 CBuff.Byte2.Flags = CloseTrkSes_Trk;
787 RC = UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES,
788 Vcb->TargetDeviceObject,
789 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
790 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN),
795 UDFResetDeviceDriver(Vcb
, Vcb
->TargetDeviceObject
, TRUE
);
796 delay
.QuadPart
= -1000000; // 0.1 sec
797 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
801 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
)) {
803 UDFPhSendIOCTL(IOCTL_STORAGE_EJECT_MEDIA
,
804 Vcb
->TargetDeviceObject
,
809 // notify media change
810 /* if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) {
811 ((PNOTIFY_MEDIA_CHANGE_USER_IN)Buf)->Autorun = FALSE;
812 RC = UDFPhSendIOCTL(IOCTL_CDRW_NOTIFY_MEDIA_CHANGE,
813 Vcb->TargetDeviceObject,
814 Buf,sizeof(NOTIFY_MEDIA_CHANGE_USER_IN),
819 UDFReleaseResource(&(Vcb
->IoResource
));
820 // unregister shutdown notification
821 if(Vcb
->ShutdownRegistered
) {
822 IoUnregisterShutdownNotification(Vcb
->VCBDeviceObject
);
823 Vcb
->ShutdownRegistered
= FALSE
;
825 // allow media change checks (this will lead to dismount)
826 // ... and make it Read-Only... :-\~
827 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_MEDIA_LOCKED
;
829 // Return back XP CD Burner Volume
831 if (Vcb->CDBurnerVolumeValid) {
832 RtlWriteRegistryValue(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL,
833 REG_CD_BURNER_KEY_NAME,REG_CD_BURNER_VOLUME_NAME,
834 REG_SZ,(PVOID)&(Vcb->CDBurnerVolume),sizeof(Vcb->CDBurnerVolume));
835 ExFreePool(Vcb->CDBurnerVolume.Buffer);
838 UDFPrint((" set UnsafeIoctl\n"));
839 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_UNSAFE_IOCTL
;
841 return STATUS_SUCCESS
;
842 } // end UDFDoDismountSequence()