42806331ea5b6f0132c2a71b208d74f78b38cede
[reactos.git] / reactos / drivers / filesystems / udfs / udf_info / phys_eject.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7 Module Name: Phys_eject.cpp
8
9 Execution: Kernel mode only
10
11 Description:
12
13 Contains code that implement read/write operations for physical device
14 */
15
16 #include "udf.h"
17 // define the file specific bug-check id
18 #define UDF_BUG_CHECK_ID UDF_FILE_PHYS_EJECT
19
20 extern void
21 UDFKeyWaiter(
22 IN void* Context
23 );
24
25 /*
26 This routine checks for User Eject request & initiates Dismount
27 */
28 void
29 UDFEjectReqWaiter(
30 IN void* Context
31 )
32 {
33 PUDFEjectWaitContext WC = (PUDFEjectWaitContext)Context;
34 PVCB Vcb;
35 OSSTATUS RC = STATUS_SUCCESS;
36 OSSTATUS WRC;
37 LARGE_INTEGER delay;
38 LARGE_INTEGER time;
39 BOOLEAN UseEvent = TRUE;
40 uint32 d;
41 BOOLEAN FlushWCache = FALSE;
42 IO_STATUS_BLOCK IoStatus;
43 BOOLEAN VcbAcquired;
44 BOOLEAN AllFlushed;
45 PDEVICE_OBJECT TargetDevObj;
46 uint32 BM_FlushPriod;
47 uint32 Tree_FlushPriod;
48 uint32 SkipCount = 0;
49 uint32 SkipEjectCount = 0;
50 uint32 flags = 0;
51 uint32 flush_stat = 0;
52 BOOLEAN UseEject = TRUE;
53 BOOLEAN MediaLoss = FALSE;
54
55 BOOLEAN SkipEject = FALSE;
56 BOOLEAN SkipFlush = FALSE;
57
58 // BOOLEAN FlushAndEject = FALSE;
59
60 UDFPrint((" UDFEjectReqWaiter: start\n"));
61 uint8 supported_evt_classes = 0;
62 uint32 i, j;
63 uint8 evt_type;
64 BOOLEAN OldLowFreeSpace = FALSE;
65 uint32 space_check_counter = 0x7fffffff;
66 PGET_LAST_ERROR_USER_OUT Error = NULL;
67
68 // Drain out Event Queue
69 Vcb = WC->Vcb;
70 TargetDevObj = Vcb->TargetDeviceObject;
71 UseEvent = Vcb->UseEvent;
72 if(UseEvent) {
73 supported_evt_classes = EventStat_Class_Media;
74 } else {
75 UDFPrint((" Eject Button ignored\n"));
76 }
77 for(j=0; j<4; j++) {
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) )
83 continue;
84 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
85 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type;
86
87 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_EVENT,
88 TargetDevObj,
89 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
90 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
91 FALSE,NULL);
92
93 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
94 UseEvent = FALSE;
95 break;
96 }
97 if(RC == STATUS_NO_SUCH_DEVICE)
98 break;
99 if(OS_SUCCESS(RC)) {
100 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses;
101 }
102 }
103 }
104 if(!UseEvent)
105 break;
106 if(RC == STATUS_NO_SUCH_DEVICE)
107 break;
108 }
109 supported_evt_classes = 0;
110
111 // Wait for events
112 while(TRUE) {
113 _SEH2_TRY {
114
115 VcbAcquired = FALSE;
116 delay.QuadPart = -10000000; // 1.0 sec
117 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
118 if(WRC == STATUS_SUCCESS) {
119 stop_waiter:
120 // if(!
121 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);//) {
122 /* delay.QuadPart = -1000000; // 0.1 sec
123 KeDelayExecutionThread(KernelMode, FALSE, &delay);
124 try_return(RC);*/
125 // }
126 Vcb->EjectWaiter = NULL;
127 UDFReleaseResource(&(Vcb->VCBResource));
128
129 KeSetEvent(WC->WaiterStopped, 0, FALSE);
130 MyFreePool__(WC);
131 WC = NULL;
132 UDFPrint((" UDFEjectReqWaiter: exit 3\n"));
133 return;
134 }
135 BM_FlushPriod = Vcb->BM_FlushPriod;
136 Tree_FlushPriod = Vcb->Tree_FlushPriod;
137
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);
143 }
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;
150 }
151 OldLowFreeSpace = Vcb->LowFreeSpace;
152 space_check_counter = 0;
153 }
154 space_check_counter++;
155
156 if(Vcb->VCBFlags & UDF_VCB_SKIP_EJECT_CHECK) {
157 SkipCount++;
158 SkipEjectCount++;
159 SkipEject = (SkipEjectCount <= Vcb->SkipEjectCountLimit);
160 SkipFlush = (SkipEjectCount <= Vcb->SkipCountLimit);
161 if(SkipEject || SkipFlush) {
162 Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK;
163 }
164 } else {
165 SkipEject = FALSE;
166 SkipFlush = FALSE;
167 }
168
169 if(WC->SoftEjectReq) {
170 SkipEject = FALSE;
171 SkipFlush = FALSE;
172 }
173
174 if(SkipFlush) {
175 Vcb->BM_FlushTime =
176 Vcb->Tree_FlushTime = 0;
177 } else {
178 SkipCount = 0;
179 }
180 if(!SkipEject) {
181 SkipEjectCount = 0;
182 }
183
184 if(SkipEject && SkipFlush) {
185 wait_eject:
186 delay.QuadPart = -10000000; // 1.0 sec
187 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay);
188 if(WRC == STATUS_SUCCESS) {
189 goto stop_waiter;
190 }
191 try_return(RC);
192 }
193
194 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) {
195 goto wait_eject;
196 }
197
198 // check if the door is still locked
199 if(!SkipEject &&
200 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) &&
201 (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) {
202
203 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
204 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_CAPABILITIES,
205 TargetDevObj,
206 NULL,0,
207 &(WC->DevCap),sizeof(GET_CAPABILITIES_USER_OUT),
208 FALSE,NULL);
209
210 Error = &(WC->Error);
211 UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject,
212 NULL,0,
213 Error,sizeof(GET_LAST_ERROR_USER_OUT),
214 TRUE,NULL);
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))
225 ||
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"));
231 //ASSERT(FALSE);
232 Vcb->ForgetVolume = TRUE;
233 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY | UDF_VCB_FLAGS_MEDIA_READ_ONLY;
234 MediaLoss = TRUE;
235 goto device_failure;
236 }
237 }
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
242 // re-lock tray
243 UDFPrint((" UDFEjectReqWaiter: Unexpected tray unlock encountered. Try to re-lock\n"));
244
245 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
246 VcbAcquired = TRUE;
247
248 /* UDFResetDeviceDriver(Vcb, TargetDevObj, FALSE);
249 delay.QuadPart = -1000000; // 0.1 sec
250 KeDelayExecutionThread(KernelMode, FALSE, &delay);*/
251 // lock it
252 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&(WC->DevCap)))->PreventMediaRemoval = TRUE;
253 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL,
254 TargetDevObj,
255 &(WC->DevCap),sizeof(PREVENT_MEDIA_REMOVAL_USER_IN),
256 NULL,0,
257 FALSE,NULL);
258 delay.QuadPart = -1000000; // 0.1 sec
259 KeDelayExecutionThread(KernelMode, FALSE, &delay);
260 // force write mode re-initialization
261 Vcb->LastModifiedTrack = 0;
262 // try_return(RC);
263 }
264 }
265
266 UDFVVerify(Vcb, 0 /* partial verify */);
267
268 if(!SkipFlush &&
269 !(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
270 (BM_FlushPriod || Tree_FlushPriod)) {
271 KeQuerySystemTime(&delay);
272 d = (uint32)((delay.QuadPart - time.QuadPart) / 10000000);
273 time = delay;
274 Vcb->BM_FlushTime += d;
275 Vcb->Tree_FlushTime += d;
276
277 if(!Vcb->CDR_Mode) {
278
279 AllFlushed = FALSE;
280
281 UDFPrint((" SkipCount=%x, SkipCountLimit=%x\n",
282 SkipCount,
283 Vcb->SkipCountLimit));
284
285 if( Tree_FlushPriod &&
286 (Tree_FlushPriod < Vcb->Tree_FlushTime)) {
287
288 UDFPrint((" Tree_FlushPriod %I64x, Vcb->Tree_FlushTime %I64x\n",
289 Tree_FlushPriod,
290 Vcb->Tree_FlushTime));
291
292 // do not touch unchanged volume
293 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ||
294 !Vcb->Modified)
295 goto skip_BM_flush;
296
297 // Acquire Vcb resource
298 if(!VcbAcquired) {
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) {
303 goto stop_waiter;
304 }
305 try_return(RC);
306 }
307 VcbAcquired = TRUE;
308 }
309
310 UDFPrint(("UDF: Flushing Directory Tree....\n"));
311 if( BM_FlushPriod &&
312 (BM_FlushPriod < Vcb->BM_FlushTime)) {
313 UDFPrint((" full flush\n"));
314 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE);
315 } else {
316 UDFPrint((" light flush\n"));
317 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE | UDF_FLUSH_FLAGS_LITE);
318 }
319 if(flush_stat & UDF_FLUSH_FLAGS_INTERRUPTED)
320 try_return(RC);
321 FlushWCache = TRUE;
322 UDFVVerify(Vcb, UFD_VERIFY_FLAG_BG /* partial verify */);
323 //UDFVFlush(Vcb);
324 skip_BM_flush:
325 Vcb->Tree_FlushTime = 0;
326 }
327 if( BM_FlushPriod &&
328 (BM_FlushPriod < Vcb->BM_FlushTime)) {
329
330 UDFPrint((" BM_FlushPriod %I64x, Vcb->BM_FlushTime %I64x\n",
331 BM_FlushPriod,
332 Vcb->BM_FlushTime));
333
334
335 // do not touch unchanged volume
336 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)
337 goto skip_BM_flush2;
338 if(!Vcb->Modified)
339 goto skip_BM_flush2;
340
341 if(!VcbAcquired) {
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) {
346 goto stop_waiter;
347 }
348 try_return(RC);
349 }
350 VcbAcquired = TRUE;
351 }
352
353 UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
354 // UDF_CHECK_BITMAP_RESOURCE(Vcb);
355
356 if(Vcb->FSBM_ByteCount != RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) {
357 flags |= 1;
358 }
359 /* if(FlushWCache) {
360 AllFlushed = TRUE;
361 }*/
362 AllFlushed =
363 FlushWCache = TRUE;
364 #ifndef UDF_READ_ONLY_BUILD
365 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE);
366 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR);
367
368 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent));
369 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent));
370
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);
375 UDFVFlush(Vcb);
376 }
377 #ifdef UDF_DBG
378 UDFPrint(("UDF: Flushing Free Space Bitmap....\n"));
379
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"));
386 #else
387 UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags);
388 UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags);
389 #endif // UDF_DBG
390 // Update Integrity Desc if any
391 if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) {
392 UDFUpdateLogicalVolInt(Vcb, TRUE);
393 }
394 if(flags & 1) {
395 RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount);
396 }
397 #endif //UDF_READ_ONLY_BUILD
398 UDFPreClrModified(Vcb);
399 UDFReleaseResource(&(Vcb->BitMapResource1));
400 skip_BM_flush2:
401 Vcb->BM_FlushTime = 0;
402 }
403 if(FlushWCache) {
404 FlushWCache = FALSE;
405 WCacheFlushAll__(&(Vcb->FastCache), Vcb);
406 }
407
408 if(AllFlushed) {
409 //Vcb->Modified = FALSE;
410 UDFClrModified(Vcb);
411 }
412
413 if(VcbAcquired) {
414 VcbAcquired = FALSE;
415 UDFReleaseResource(&(Vcb->VCBResource));
416 }
417 if(!Vcb->Tree_FlushTime &&
418 !Vcb->BM_FlushTime)
419 SkipCount = 0;
420 }
421 } else {
422 //SkipCount = 0;
423 }
424
425 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA))
426 try_return(RC);
427
428 UDFPrint((" UDFEjectReqWaiter: check removable media\n"));
429 if(!WC->SoftEjectReq && SkipEject) {
430 try_return(RC);
431 }
432
433 if(!WC->SoftEjectReq) {
434
435 if(!UseEvent) {
436 UDFPrint((" Eject Button ignored\n"));
437 try_return(RC);
438 }
439
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);
444 OSSTATUS RC;
445
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;
450 }
451
452 // delay.QuadPart = -300000; // 0.03 sec
453 // KeDelayExecutionThread(KernelMode, FALSE, &delay);
454 Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE;
455 }*/
456
457 ASSERT(sizeof(TEST_UNIT_READY_USER_OUT) <= sizeof(GET_EVENT_USER_OUT));
458
459 RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY,
460 Vcb,
461 NULL,0,
462 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT),
463 FALSE,NULL);
464
465 if(RC != STATUS_SUCCESS &&
466 RC != STATUS_DATA_OVERRUN) {
467 if(RC == STATUS_NO_SUCH_DEVICE) {
468 UDFPrint((" Device loss\n"));
469 goto device_failure;
470 }
471 if(RC == STATUS_NO_MEDIA_IN_DEVICE) {
472 UDFPrint((" Media loss\n"));
473 goto media_loss;
474 }
475 }
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) )
481 continue;
482 /*
483 if( evt_type == EventStat_Class_Media )
484 continue;
485 if( evt_type == EventStat_Class_ExternalReq )
486 continue;
487 */
488 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
489 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type;
490
491 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
492 Vcb,
493 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
494 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
495 FALSE,NULL);
496
497 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
498 supported_evt_classes &= ~evt_type;
499 continue;
500 }
501 if(RC == STATUS_NO_SUCH_DEVICE) {
502 UDFPrint((" Device loss (2)\n"));
503 goto device_failure;
504 }
505 if(!OS_SUCCESS(RC)) {
506 continue;
507 }
508
509 if(WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_NEA) {
510 continue;
511 }
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) {
516 continue;
517 }
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,
523 Vcb,
524 NULL,0,
525 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT),
526 FALSE,NULL);
527
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;
535 }
536 media_loss:
537 UDFPrint((" Unexpected media loss. Check device status\n"));
538 UseEject = FALSE;
539 MediaLoss = TRUE;
540 } else
541 // check if eject request occured
542 if( (WC->EjectReqBuffer.MediaChange.Byte0.Flags & EventStat_MediaEvent_Mask) !=
543 EventStat_MediaEvent_EjectReq ) {
544 continue;
545 }
546 UDFPrint((" eject requested\n"));
547 WC->SoftEjectReq = TRUE;
548 break;
549 }
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)
554 continue;
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;
561 break;
562 }
563 continue;
564 }
565 }
566 if(!supported_evt_classes) {
567 UseEvent = FALSE;
568 }
569 if(!WC->SoftEjectReq) {
570 try_return(RC);
571 }
572 } else {
573
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;
577
578 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
579 Vcb,
580 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
581 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
582 FALSE,NULL);
583
584 if(!OS_SUCCESS(RC)) {
585 if(RC == STATUS_NO_SUCH_DEVICE)
586 goto device_failure;
587 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE;
588 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_ExternalReq;
589
590 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT,
591 Vcb,
592 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN),
593 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT),
594 FALSE,NULL);
595
596 if(RC == STATUS_NO_SUCH_DEVICE)
597 goto device_failure;
598 if(RC == STATUS_INVALID_DEVICE_REQUEST) {
599 UseEvent = FALSE;
600 }
601 try_return(RC);
602 }
603 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses;
604 try_return(RC);
605 }
606 }
607 // FlushAndEject = TRUE;
608 device_failure:
609 // Ok. Lets flush all we have in memory, dismount volume & eject disc
610 // Acquire Vcb resource
611 Vcb->SoftEjectReq = TRUE;
612
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
620
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
629
630 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
631
632 UDFPrint((" UDFEjectReqWaiter: UDFDoDismountSequence\n"));
633 UDFDoDismountSequence(Vcb, (PPREVENT_MEDIA_REMOVAL_USER_IN)&(WC->EjectReqBuffer), UseEject);
634 if (MediaLoss) {
635 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
636 Vcb->WriteSecurity = FALSE;
637 }
638 Vcb->EjectWaiter = NULL;
639 Vcb->SoftEjectReq = FALSE;
640 UDFReleaseResource(&(Vcb->VCBResource));
641
642 UDFPrint((" UDFEjectReqWaiter: set WaiterStopped\n"));
643 KeSetEvent(WC->WaiterStopped, 0, FALSE);
644 MyFreePool__(WC);
645 WC = NULL;
646
647 UDFPrint((" UDFEjectReqWaiter: exit 1\n"));
648 return;
649
650 try_exit: NOTHING;
651 } _SEH2_FINALLY {
652
653 if(VcbAcquired) {
654 VcbAcquired = FALSE;
655 UDFReleaseResource(&(Vcb->VCBResource));
656 }
657
658 /* if(WC) {
659 delay.QuadPart = -10000000; // 1.0 sec
660 WRC = KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, &delay);
661 if(WRC == STATUS_SUCCESS) {
662 goto stop_waiter;
663 }
664 }*/
665 } _SEH2_END;
666 }
667 // Simply make compiler happy
668 return;
669 } // end UDFEjectReqWaiter()
670
671 void
672 UDFStopEjectWaiter(PVCB Vcb) {
673
674 UDFPrint((" UDFStopEjectWaiter: try\n"));
675 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
676 _SEH2_TRY {
677 if(Vcb->EjectWaiter) {
678 UDFPrint((" UDFStopEjectWaiter: set flag\n"));
679 KeSetEvent( &(Vcb->EjectWaiter->StopReq), 0, FALSE );
680 } else {
681 // return;
682 }
683 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
684 BrutePoint();
685 } _SEH2_END;
686 UDFReleaseResource(&(Vcb->VCBResource));
687
688 _SEH2_TRY {
689 if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT) {
690 UDFPrint((" UDFStopEjectWaiter: wait\n"));
691 KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL);
692 }
693 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT;
694 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
695 BrutePoint();
696 } _SEH2_END;
697 ASSERT(!Vcb->EjectWaiter);
698 UDFPrint((" UDFStopEjectWaiter: exit\n"));
699
700 } // end UDFStopEjectWaiter()
701
702 OSSTATUS
703 UDFDoDismountSequence(
704 IN PVCB Vcb,
705 IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf,
706 IN BOOLEAN Eject
707 )
708 {
709 LARGE_INTEGER delay;
710 // OSSTATUS RC;
711 ULONG i;
712
713 // flush system cache
714 UDFFlushLogicalVolume(NULL, NULL, Vcb, 0);
715 UDFPrint(("UDFDoDismountSequence:\n"));
716
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);
723 }
724 // release WCache
725 WCacheRelease__(&(Vcb->FastCache));
726
727 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE);
728
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),
737 NULL,0,
738 FALSE,NULL);
739 KeDelayExecutionThread(KernelMode, FALSE, &delay);
740 }
741 delay.QuadPart = -2000000; // 0.2 sec
742 }
743
744 if(!Vcb->ForgetVolume) {
745
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),
754 NULL,0,TRUE,NULL);
755 }
756
757 if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) {
758 CLOSE_TRK_SES_USER_IN CBuff;
759
760 // reset driver
761 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
762 delay.QuadPart = -2000000; // 0.2 sec
763 KeDelayExecutionThread(KernelMode, FALSE, &delay);
764
765 memset(&CBuff,0,sizeof(CLOSE_TRK_SES_USER_IN));
766 // stop BG format
767 if(Vcb->MRWStatus) {
768 UDFPrint((" Stop background formatting\n"));
769
770 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed;
771 CBuff.Byte2.Flags = CloseTrkSes_Ses;
772 CBuff.TrackNum = 1;
773
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),
778 FALSE, NULL );
779 /* } else
780 if(Vcb->MediaClassEx == CdMediaClass_DVDRW) {
781 UDFPrint((" Close BG-formatted track\n"));
782
783 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed;
784 CBuff.Byte2.Flags = CloseTrkSes_Trk;
785 CBuff.TrackNum = 1;
786
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),
791 FALSE, NULL );
792 */
793 }
794 // reset driver
795 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
796 delay.QuadPart = -1000000; // 0.1 sec
797 KeDelayExecutionThread(KernelMode, FALSE, &delay);
798 }
799 // eject media
800 if(Eject &&
801 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) {
802
803 UDFPhSendIOCTL(IOCTL_STORAGE_EJECT_MEDIA,
804 Vcb->TargetDeviceObject,
805 NULL,0,
806 NULL,0,
807 FALSE,NULL);
808 }
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),
815 NULL,0,
816 FALSE,NULL);
817 }*/
818 }
819 UDFReleaseResource(&(Vcb->IoResource));
820 // unregister shutdown notification
821 if(Vcb->ShutdownRegistered) {
822 IoUnregisterShutdownNotification(Vcb->VCBDeviceObject);
823 Vcb->ShutdownRegistered = FALSE;
824 }
825 // allow media change checks (this will lead to dismount)
826 // ... and make it Read-Only... :-\~
827 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED;
828
829 // Return back XP CD Burner Volume
830 /*
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);
836 }
837 */
838 UDFPrint((" set UnsafeIoctl\n"));
839 Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL;
840
841 return STATUS_SUCCESS;
842 } // end UDFDoDismountSequence()
843