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 NTAPI 30 UDFEjectReqWaiter( 31 IN void* Context 32 ) 33 { 34 PUDFEjectWaitContext WC = (PUDFEjectWaitContext)Context; 35 PVCB Vcb; 36 OSSTATUS RC = STATUS_SUCCESS; 37 OSSTATUS WRC; 38 LARGE_INTEGER delay; 39 LARGE_INTEGER time; 40 BOOLEAN UseEvent = TRUE; 41 uint32 d; 42 BOOLEAN FlushWCache = FALSE; 43 IO_STATUS_BLOCK IoStatus; 44 BOOLEAN VcbAcquired; 45 BOOLEAN AllFlushed; 46 PDEVICE_OBJECT TargetDevObj; 47 uint32 BM_FlushPriod; 48 uint32 Tree_FlushPriod; 49 uint32 SkipCount = 0; 50 uint32 SkipEjectCount = 0; 51 uint32 flags = 0; 52 uint32 flush_stat = 0; 53 BOOLEAN UseEject = TRUE; 54 BOOLEAN MediaLoss = FALSE; 55 56 BOOLEAN SkipEject = FALSE; 57 BOOLEAN SkipFlush = FALSE; 58 59 // BOOLEAN FlushAndEject = FALSE; 60 61 UDFPrint((" UDFEjectReqWaiter: start\n")); 62 uint8 supported_evt_classes = 0; 63 uint32 i, j; 64 uint8 evt_type; 65 BOOLEAN OldLowFreeSpace = FALSE; 66 uint32 space_check_counter = 0x7fffffff; 67 PGET_LAST_ERROR_USER_OUT Error = NULL; 68 69 // Drain out Event Queue 70 Vcb = WC->Vcb; 71 TargetDevObj = Vcb->TargetDeviceObject; 72 UseEvent = Vcb->UseEvent; 73 if(UseEvent) { 74 supported_evt_classes = EventStat_Class_Media; 75 } else { 76 UDFPrint((" Eject Button ignored\n")); 77 } 78 for(j=0; j<4; j++) { 79 UDFPrint((" Reading events... (0)\n")); 80 if(supported_evt_classes) { 81 for(i=1; i<=EventRetStat_Class_Mask;i++) { 82 evt_type = (((UCHAR)1) << i); 83 if( !(supported_evt_classes & evt_type) ) 84 continue; 85 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; 86 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type; 87 88 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_EVENT, 89 TargetDevObj, 90 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), 91 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), 92 FALSE,NULL); 93 94 if(RC == STATUS_INVALID_DEVICE_REQUEST) { 95 UseEvent = FALSE; 96 break; 97 } 98 if(RC == STATUS_NO_SUCH_DEVICE) 99 break; 100 if(OS_SUCCESS(RC)) { 101 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses; 102 } 103 } 104 } 105 if(!UseEvent) 106 break; 107 if(RC == STATUS_NO_SUCH_DEVICE) 108 break; 109 } 110 supported_evt_classes = 0; 111 112 // Wait for events 113 while(TRUE) { 114 _SEH2_TRY { 115 116 VcbAcquired = FALSE; 117 delay.QuadPart = -10000000; // 1.0 sec 118 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); 119 if(WRC == STATUS_SUCCESS) { 120 stop_waiter: 121 // if(! 122 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);//) { 123 /* delay.QuadPart = -1000000; // 0.1 sec 124 KeDelayExecutionThread(KernelMode, FALSE, &delay); 125 try_return(RC);*/ 126 // } 127 Vcb->EjectWaiter = NULL; 128 UDFReleaseResource(&(Vcb->VCBResource)); 129 130 KeSetEvent(WC->WaiterStopped, 0, FALSE); 131 MyFreePool__(WC); 132 WC = NULL; 133 UDFPrint((" UDFEjectReqWaiter: exit 3\n")); 134 return; 135 } 136 BM_FlushPriod = Vcb->BM_FlushPriod; 137 Tree_FlushPriod = Vcb->Tree_FlushPriod; 138 139 // check if we approaching end of disk 140 if(space_check_counter > 2) { 141 // update FreeAllocUnits if it is necessary 142 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && Vcb->Modified) { 143 Vcb->FreeAllocUnits = UDFGetFreeSpace(Vcb); 144 } 145 // update LowFreeSpace flag 146 Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128); 147 if(Vcb->LowFreeSpace && !OldLowFreeSpace) { 148 // initiate Flush process if we crossed LowFreeSpace boundary 149 Vcb->Tree_FlushTime = Tree_FlushPriod+1; 150 Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK; 151 } 152 OldLowFreeSpace = Vcb->LowFreeSpace; 153 space_check_counter = 0; 154 } 155 space_check_counter++; 156 157 if(Vcb->VCBFlags & UDF_VCB_SKIP_EJECT_CHECK) { 158 SkipCount++; 159 SkipEjectCount++; 160 SkipEject = (SkipEjectCount <= Vcb->SkipEjectCountLimit); 161 SkipFlush = (SkipEjectCount <= Vcb->SkipCountLimit); 162 if(SkipEject || SkipFlush) { 163 Vcb->VCBFlags &= ~UDF_VCB_SKIP_EJECT_CHECK; 164 } 165 } else { 166 SkipEject = FALSE; 167 SkipFlush = FALSE; 168 } 169 170 if(WC->SoftEjectReq) { 171 SkipEject = FALSE; 172 SkipFlush = FALSE; 173 } 174 175 if(SkipFlush) { 176 Vcb->BM_FlushTime = 177 Vcb->Tree_FlushTime = 0; 178 } else { 179 SkipCount = 0; 180 } 181 if(!SkipEject) { 182 SkipEjectCount = 0; 183 } 184 185 if(SkipEject && SkipFlush) { 186 wait_eject: 187 delay.QuadPart = -10000000; // 1.0 sec 188 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); 189 if(WRC == STATUS_SUCCESS) { 190 goto stop_waiter; 191 } 192 try_return(RC); 193 } 194 195 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) { 196 goto wait_eject; 197 } 198 199 // check if the door is still locked 200 if(!SkipEject && 201 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) && 202 (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) { 203 204 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); 205 RC = UDFPhSendIOCTL( IOCTL_CDRW_GET_CAPABILITIES, 206 TargetDevObj, 207 NULL,0, 208 &(WC->DevCap),sizeof(GET_CAPABILITIES_USER_OUT), 209 FALSE,NULL); 210 211 Error = &(WC->Error); 212 UDFPhSendIOCTL( IOCTL_CDRW_GET_LAST_ERROR, Vcb->TargetDeviceObject, 213 NULL,0, 214 Error,sizeof(GET_LAST_ERROR_USER_OUT), 215 TRUE,NULL); 216 UDFReleaseResource(&(Vcb->IoResource)); 217 UDFPrint(("SK=%x ASC=%x, ASCQ=%x, IE=%x\n", 218 Error->SenseKey, Error->AdditionalSenseCode, Error->AdditionalSenseCodeQualifier, Error->LastError)); 219 // check for Long Write In Progress 220 if( ((Error->SenseKey == SCSI_SENSE_NOT_READY) && 221 (Error->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && 222 (Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS || 223 Error->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS)) ) { 224 if((!Vcb->Modified && 225 !(Vcb->VCBFlags & UDF_VCB_LAST_WRITE)) 226 || 227 (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL)) { 228 // we should forget about this disk... 229 UDFPrint((" LAST_WRITE %x\n", !!(Vcb->VCBFlags & UDF_VCB_LAST_WRITE))); 230 UDFPrint((" UDF_VCB_FLAGS_UNSAFE_IOCTL %x\n", !!(Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL))); 231 UDFPrint((" UDFEjectReqWaiter: Unexpected write-in-progress on !Modified volume\n")); 232 //ASSERT(FALSE); 233 Vcb->ForgetVolume = TRUE; 234 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY | UDF_VCB_FLAGS_MEDIA_READ_ONLY; 235 MediaLoss = TRUE; 236 goto device_failure; 237 } 238 } 239 if( OS_SUCCESS(RC) && 240 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) && 241 !(WC->DevCap.Capabilities2 & DevCap_lock_state)) { 242 // probably bus reset or power failure occured 243 // re-lock tray 244 UDFPrint((" UDFEjectReqWaiter: Unexpected tray unlock encountered. Try to re-lock\n")); 245 246 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 247 VcbAcquired = TRUE; 248 249 /* UDFResetDeviceDriver(Vcb, TargetDevObj, FALSE); 250 delay.QuadPart = -1000000; // 0.1 sec 251 KeDelayExecutionThread(KernelMode, FALSE, &delay);*/ 252 // lock it 253 ((PPREVENT_MEDIA_REMOVAL_USER_IN)(&(WC->DevCap)))->PreventMediaRemoval = TRUE; 254 UDFPhSendIOCTL( IOCTL_STORAGE_MEDIA_REMOVAL, 255 TargetDevObj, 256 &(WC->DevCap),sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), 257 NULL,0, 258 FALSE,NULL); 259 delay.QuadPart = -1000000; // 0.1 sec 260 KeDelayExecutionThread(KernelMode, FALSE, &delay); 261 // force write mode re-initialization 262 Vcb->LastModifiedTrack = 0; 263 // try_return(RC); 264 } 265 } 266 267 UDFVVerify(Vcb, 0 /* partial verify */); 268 269 if(!SkipFlush && 270 !(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && 271 (BM_FlushPriod || Tree_FlushPriod)) { 272 KeQuerySystemTime(&delay); 273 d = (uint32)((delay.QuadPart - time.QuadPart) / 10000000); 274 time = delay; 275 Vcb->BM_FlushTime += d; 276 Vcb->Tree_FlushTime += d; 277 278 if(!Vcb->CDR_Mode) { 279 280 AllFlushed = FALSE; 281 282 UDFPrint((" SkipCount=%x, SkipCountLimit=%x\n", 283 SkipCount, 284 Vcb->SkipCountLimit)); 285 286 if( Tree_FlushPriod && 287 (Tree_FlushPriod < Vcb->Tree_FlushTime)) { 288 289 UDFPrint((" Tree_FlushPriod %I64x, Vcb->Tree_FlushTime %I64x\n", 290 Tree_FlushPriod, 291 Vcb->Tree_FlushTime)); 292 293 // do not touch unchanged volume 294 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) || 295 !Vcb->Modified) 296 goto skip_BM_flush; 297 298 // Acquire Vcb resource 299 if(!VcbAcquired) { 300 if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FALSE)) { 301 delay.QuadPart = -10000000; // 1.0 sec 302 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); 303 if(WRC == STATUS_SUCCESS) { 304 goto stop_waiter; 305 } 306 try_return(RC); 307 } 308 VcbAcquired = TRUE; 309 } 310 311 UDFPrint(("UDF: Flushing Directory Tree....\n")); 312 if( BM_FlushPriod && 313 (BM_FlushPriod < Vcb->BM_FlushTime)) { 314 UDFPrint((" full flush\n")); 315 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE); 316 } else { 317 UDFPrint((" light flush\n")); 318 flush_stat = UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, UDF_FLUSH_FLAGS_BREAKABLE | UDF_FLUSH_FLAGS_LITE); 319 } 320 if(flush_stat & UDF_FLUSH_FLAGS_INTERRUPTED) 321 try_return(RC); 322 FlushWCache = TRUE; 323 UDFVVerify(Vcb, UFD_VERIFY_FLAG_BG /* partial verify */); 324 //UDFVFlush(Vcb); 325 skip_BM_flush: 326 Vcb->Tree_FlushTime = 0; 327 } 328 if( BM_FlushPriod && 329 (BM_FlushPriod < Vcb->BM_FlushTime)) { 330 331 UDFPrint((" BM_FlushPriod %I64x, Vcb->BM_FlushTime %I64x\n", 332 BM_FlushPriod, 333 Vcb->BM_FlushTime)); 334 335 336 // do not touch unchanged volume 337 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) 338 goto skip_BM_flush2; 339 if(!Vcb->Modified) 340 goto skip_BM_flush2; 341 342 if(!VcbAcquired) { 343 if(!UDFAcquireResourceExclusive(&(Vcb->VCBResource), FlushWCache /*|| FALSE*/)) { 344 delay.QuadPart = -10000000; // 1.0 sec 345 WRC = KeWaitForSingleObject(&(Vcb->EjectWaiter->StopReq), Executive, KernelMode, FALSE, &delay); 346 if(WRC == STATUS_SUCCESS) { 347 goto stop_waiter; 348 } 349 try_return(RC); 350 } 351 VcbAcquired = TRUE; 352 } 353 354 UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); 355 // UDF_CHECK_BITMAP_RESOURCE(Vcb); 356 357 if(Vcb->FSBM_ByteCount != RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) { 358 flags |= 1; 359 } 360 /* if(FlushWCache) { 361 AllFlushed = TRUE; 362 }*/ 363 AllFlushed = 364 FlushWCache = TRUE; 365 #ifndef UDF_READ_ONLY_BUILD 366 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE); 367 UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR); 368 369 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)); 370 UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)); 371 372 if(Vcb->VerifyOnWrite) { 373 UDFPrint(("UDF: Flushing cache for verify\n")); 374 //WCacheFlushAll__(&(Vcb->FastCache), Vcb); 375 WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); 376 UDFVFlush(Vcb); 377 } 378 #ifdef UDF_DBG 379 UDFPrint(("UDF: Flushing Free Space Bitmap....\n")); 380 381 // if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)))) 382 // UDFPrint(("Error updating VolIdent\n")); 383 if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags))) 384 UDFPrint(("Error updating Main VDS\n")); 385 if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags))) 386 UDFPrint(("Error updating Reserve VDS\n")); 387 #else 388 UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags); 389 UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags); 390 #endif // UDF_DBG 391 // Update Integrity Desc if any 392 if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) { 393 UDFUpdateLogicalVolInt(Vcb, TRUE); 394 } 395 if(flags & 1) { 396 RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); 397 } 398 #endif //UDF_READ_ONLY_BUILD 399 UDFPreClrModified(Vcb); 400 UDFReleaseResource(&(Vcb->BitMapResource1)); 401 skip_BM_flush2: 402 Vcb->BM_FlushTime = 0; 403 } 404 if(FlushWCache) { 405 FlushWCache = FALSE; 406 WCacheFlushAll__(&(Vcb->FastCache), Vcb); 407 } 408 409 if(AllFlushed) { 410 //Vcb->Modified = FALSE; 411 UDFClrModified(Vcb); 412 } 413 414 if(VcbAcquired) { 415 VcbAcquired = FALSE; 416 UDFReleaseResource(&(Vcb->VCBResource)); 417 } 418 if(!Vcb->Tree_FlushTime && 419 !Vcb->BM_FlushTime) 420 SkipCount = 0; 421 } 422 } else { 423 //SkipCount = 0; 424 } 425 426 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) 427 try_return(RC); 428 429 UDFPrint((" UDFEjectReqWaiter: check removable media\n")); 430 if(!WC->SoftEjectReq && SkipEject) { 431 try_return(RC); 432 } 433 434 if(!WC->SoftEjectReq) { 435 436 if(!UseEvent) { 437 UDFPrint((" Eject Button ignored\n")); 438 try_return(RC); 439 } 440 441 /* if( (Vcb->VCBFlags & UDF_VCB_LAST_WRITE) && 442 !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_SYNC_CACHE) ){ 443 // delay.QuadPart = -100000; // 0.01 sec 444 // KeDelayExecutionThread(KernelMode, FALSE, &delay); 445 OSSTATUS RC; 446 447 UDFPrint((" Sync cache before GET_EVENT\n")); 448 RC = UDFSyncCache(Vcb); 449 if(RC == STATUS_INVALID_DEVICE_REQUEST) { 450 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_SYNC_CACHE; 451 } 452 453 // delay.QuadPart = -300000; // 0.03 sec 454 // KeDelayExecutionThread(KernelMode, FALSE, &delay); 455 Vcb->VCBFlags &= ~UDF_VCB_LAST_WRITE; 456 }*/ 457 458 ASSERT(sizeof(TEST_UNIT_READY_USER_OUT) <= sizeof(GET_EVENT_USER_OUT)); 459 460 RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY, 461 Vcb, 462 NULL,0, 463 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT), 464 FALSE,NULL); 465 466 if(RC != STATUS_SUCCESS && 467 RC != STATUS_DATA_OVERRUN) { 468 if(RC == STATUS_NO_SUCH_DEVICE) { 469 UDFPrint((" Device loss\n")); 470 goto device_failure; 471 } 472 if(RC == STATUS_NO_MEDIA_IN_DEVICE) { 473 UDFPrint((" Media loss\n")); 474 goto media_loss; 475 } 476 } 477 UDFPrint((" Reading events...\n")); 478 if(supported_evt_classes) { 479 for(i=1; i<=EventRetStat_Class_Mask;i++) { 480 evt_type = (((UCHAR)1) << i); 481 if( !(supported_evt_classes & evt_type) ) 482 continue; 483 /* 484 if( evt_type == EventStat_Class_Media ) 485 continue; 486 if( evt_type == EventStat_Class_ExternalReq ) 487 continue; 488 */ 489 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; 490 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = evt_type; 491 492 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, 493 Vcb, 494 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), 495 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), 496 FALSE,NULL); 497 498 if(RC == STATUS_INVALID_DEVICE_REQUEST) { 499 supported_evt_classes &= ~evt_type; 500 continue; 501 } 502 if(RC == STATUS_NO_SUCH_DEVICE) { 503 UDFPrint((" Device loss (2)\n")); 504 goto device_failure; 505 } 506 if(!OS_SUCCESS(RC)) { 507 continue; 508 } 509 510 if(WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_NEA) { 511 continue; 512 } 513 if( evt_type == EventStat_Class_Media ) { 514 UDFPrint((" EventStat_Class_Media:\n")); 515 if((WC->EjectReqBuffer.MediaChange.Header.Flags.Flags & EventRetStat_Class_Mask) != 516 EventRetStat_Class_Media) { 517 continue; 518 } 519 retry_media_presence_check: 520 if(!(WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_Present) || 521 (WC->EjectReqBuffer.MediaChange.Byte1.Flags & EventStat_MediaStat_DoorOpen)) { 522 // something wrong.... 523 RC = UDFTSendIOCTL( IOCTL_CDRW_TEST_UNIT_READY, 524 Vcb, 525 NULL,0, 526 &(WC->EjectReqBuffer),sizeof(TEST_UNIT_READY_USER_OUT), 527 FALSE,NULL); 528 529 if(RC == STATUS_SUCCESS || 530 RC == STATUS_DATA_OVERRUN) { 531 UDFPrint((" Buggy GET_EVENT media presence flag %x\n", 532 WC->EjectReqBuffer.MediaChange.Byte1)); 533 WC->EjectReqBuffer.MediaChange.Byte1.Flags |= EventStat_MediaStat_Present; 534 WC->EjectReqBuffer.MediaChange.Byte1.Flags &= ~EventStat_MediaStat_DoorOpen; 535 goto retry_media_presence_check; 536 } 537 media_loss: 538 UDFPrint((" Unexpected media loss. Check device status\n")); 539 UseEject = FALSE; 540 MediaLoss = TRUE; 541 } else 542 // check if eject request occured 543 if( (WC->EjectReqBuffer.MediaChange.Byte0.Flags & EventStat_MediaEvent_Mask) != 544 EventStat_MediaEvent_EjectReq ) { 545 continue; 546 } 547 UDFPrint((" eject requested\n")); 548 WC->SoftEjectReq = TRUE; 549 break; 550 } 551 if( evt_type == EventStat_Class_ExternalReq ) { 552 UDFPrint((" EventStat_Class_ExternalReq:\n")); 553 if((WC->EjectReqBuffer.ExternalReq.Header.Flags.Flags & EventRetStat_Class_Mask) != 554 EventRetStat_Class_ExternReq) 555 continue; 556 switch(WC->EjectReqBuffer.ExternalReq.Byte0.Flags & EventStat_ExtrnReqEvent_Mask) { 557 case EventStat_ExtrnReqEvent_KeyDown: 558 case EventStat_ExtrnReqEvent_KeyUp: 559 case EventStat_ExtrnReqEvent_ExtrnReq: 560 UDFPrint((" eject requested (%x)\n", WC->EjectReqBuffer.ExternalReq.Byte0.Flags)); 561 WC->SoftEjectReq = TRUE; 562 break; 563 } 564 continue; 565 } 566 } 567 if(!supported_evt_classes) { 568 UseEvent = FALSE; 569 } 570 if(!WC->SoftEjectReq) { 571 try_return(RC); 572 } 573 } else { 574 575 UDFPrint((" Reading Media Event...\n")); 576 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; 577 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_Media; 578 579 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, 580 Vcb, 581 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), 582 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), 583 FALSE,NULL); 584 585 if(!OS_SUCCESS(RC)) { 586 if(RC == STATUS_NO_SUCH_DEVICE) 587 goto device_failure; 588 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->Immed = TRUE; 589 ((PGET_EVENT_USER_IN)(&(WC->EjectReqBuffer)))->EventClass = EventStat_Class_ExternalReq; 590 591 RC = UDFTSendIOCTL( IOCTL_CDRW_GET_EVENT, 592 Vcb, 593 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_IN), 594 &(WC->EjectReqBuffer),sizeof(GET_EVENT_USER_OUT), 595 FALSE,NULL); 596 597 if(RC == STATUS_NO_SUCH_DEVICE) 598 goto device_failure; 599 if(RC == STATUS_INVALID_DEVICE_REQUEST) { 600 UseEvent = FALSE; 601 } 602 try_return(RC); 603 } 604 supported_evt_classes = WC->EjectReqBuffer.MediaChange.Header.SupportedClasses; 605 try_return(RC); 606 } 607 } 608 // FlushAndEject = TRUE; 609 device_failure: 610 // Ok. Lets flush all we have in memory, dismount volume & eject disc 611 // Acquire Vcb resource 612 Vcb->SoftEjectReq = TRUE; 613 614 UDFPrint((" UDFEjectReqWaiter: ejecting...\n")); 615 #ifdef UDF_DELAYED_CLOSE 616 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 617 UDFPrint((" UDFEjectReqWaiter: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n")); 618 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; 619 UDFReleaseResource(&(Vcb->VCBResource)); 620 #endif //UDF_DELAYED_CLOSE 621 622 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllSystemDelayedInDir\n")); 623 RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 624 ASSERT(OS_SUCCESS(RC)); 625 #ifdef UDF_DELAYED_CLOSE 626 UDFPrint((" UDFEjectReqWaiter: UDFCloseAllDelayed\n")); 627 UDFCloseAllDelayed(Vcb); 628 //ASSERT(OS_SUCCESS(RC)); 629 #endif //UDF_DELAYED_CLOSE 630 631 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 632 633 UDFPrint((" UDFEjectReqWaiter: UDFDoDismountSequence\n")); 634 UDFDoDismountSequence(Vcb, (PPREVENT_MEDIA_REMOVAL_USER_IN)&(WC->EjectReqBuffer), UseEject); 635 if (MediaLoss) { 636 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED; 637 Vcb->WriteSecurity = FALSE; 638 } 639 Vcb->EjectWaiter = NULL; 640 Vcb->SoftEjectReq = FALSE; 641 UDFReleaseResource(&(Vcb->VCBResource)); 642 643 UDFPrint((" UDFEjectReqWaiter: set WaiterStopped\n")); 644 KeSetEvent(WC->WaiterStopped, 0, FALSE); 645 MyFreePool__(WC); 646 WC = NULL; 647 648 UDFPrint((" UDFEjectReqWaiter: exit 1\n")); 649 return; 650 651 try_exit: NOTHING; 652 } _SEH2_FINALLY { 653 654 if(VcbAcquired) { 655 VcbAcquired = FALSE; 656 UDFReleaseResource(&(Vcb->VCBResource)); 657 } 658 659 /* if(WC) { 660 delay.QuadPart = -10000000; // 1.0 sec 661 WRC = KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, &delay); 662 if(WRC == STATUS_SUCCESS) { 663 goto stop_waiter; 664 } 665 }*/ 666 } _SEH2_END; 667 } 668 // Simply make compiler happy 669 return; 670 } // end UDFEjectReqWaiter() 671 672 void 673 UDFStopEjectWaiter(PVCB Vcb) { 674 675 UDFPrint((" UDFStopEjectWaiter: try\n")); 676 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 677 _SEH2_TRY { 678 if(Vcb->EjectWaiter) { 679 UDFPrint((" UDFStopEjectWaiter: set flag\n")); 680 KeSetEvent( &(Vcb->EjectWaiter->StopReq), 0, FALSE ); 681 } else { 682 // return; 683 } 684 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 685 BrutePoint(); 686 } _SEH2_END; 687 UDFReleaseResource(&(Vcb->VCBResource)); 688 689 _SEH2_TRY { 690 if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT) { 691 UDFPrint((" UDFStopEjectWaiter: wait\n")); 692 KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL); 693 } 694 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT; 695 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 696 BrutePoint(); 697 } _SEH2_END; 698 ASSERT(!Vcb->EjectWaiter); 699 UDFPrint((" UDFStopEjectWaiter: exit\n")); 700 701 } // end UDFStopEjectWaiter() 702 703 OSSTATUS 704 UDFDoDismountSequence( 705 IN PVCB Vcb, 706 IN PPREVENT_MEDIA_REMOVAL_USER_IN Buf, 707 IN BOOLEAN Eject 708 ) 709 { 710 LARGE_INTEGER delay; 711 // OSSTATUS RC; 712 ULONG i; 713 714 // flush system cache 715 UDFFlushLogicalVolume(NULL, NULL, Vcb, 0); 716 UDFPrint(("UDFDoDismountSequence:\n")); 717 718 delay.QuadPart = -1000000; // 0.1 sec 719 KeDelayExecutionThread(KernelMode, FALSE, &delay); 720 // wait for completion of all backgroung writes 721 while(Vcb->BGWriters) { 722 delay.QuadPart = -5000000; // 0.5 sec 723 KeDelayExecutionThread(KernelMode, FALSE, &delay); 724 } 725 // release WCache 726 WCacheRelease__(&(Vcb->FastCache)); 727 728 UDFAcquireResourceExclusive(&(Vcb->IoResource), TRUE); 729 730 // unlock media, drop our own Locks 731 if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) { 732 UDFPrint((" cleanup tray-lock (%d+2):\n", Vcb->MediaLockCount)); 733 for(i=0; i<Vcb->MediaLockCount+2; i++) { 734 Buf->PreventMediaRemoval = FALSE; 735 UDFPhSendIOCTL(IOCTL_STORAGE_MEDIA_REMOVAL, 736 Vcb->TargetDeviceObject, 737 Buf,sizeof(PREVENT_MEDIA_REMOVAL_USER_IN), 738 NULL,0, 739 FALSE,NULL); 740 KeDelayExecutionThread(KernelMode, FALSE, &delay); 741 } 742 delay.QuadPart = -2000000; // 0.2 sec 743 } 744 745 if(!Vcb->ForgetVolume) { 746 747 if(!UDFIsDvdMedia(Vcb)) { 748 // send speed limits to drive 749 UDFPrint((" Restore drive speed on dismount\n")); 750 Vcb->SpeedBuf.ReadSpeed = Vcb->MaxReadSpeed; 751 Vcb->SpeedBuf.WriteSpeed = Vcb->MaxWriteSpeed; 752 UDFPhSendIOCTL(IOCTL_CDRW_SET_SPEED, 753 Vcb->TargetDeviceObject, 754 &(Vcb->SpeedBuf),sizeof(SET_CD_SPEED_USER_IN), 755 NULL,0,TRUE,NULL); 756 } 757 758 if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) { 759 CLOSE_TRK_SES_USER_IN CBuff; 760 761 // reset driver 762 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); 763 delay.QuadPart = -2000000; // 0.2 sec 764 KeDelayExecutionThread(KernelMode, FALSE, &delay); 765 766 memset(&CBuff,0,sizeof(CLOSE_TRK_SES_USER_IN)); 767 // stop BG format 768 if(Vcb->MRWStatus) { 769 UDFPrint((" Stop background formatting\n")); 770 771 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed; 772 CBuff.Byte2.Flags = CloseTrkSes_Ses; 773 CBuff.TrackNum = 1; 774 775 UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES, 776 Vcb->TargetDeviceObject, 777 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), 778 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), 779 FALSE, NULL ); 780 /* } else 781 if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { 782 UDFPrint((" Close BG-formatted track\n")); 783 784 CBuff.Byte1.Flags = 0;//CloseTrkSes_Immed; 785 CBuff.Byte2.Flags = CloseTrkSes_Trk; 786 CBuff.TrackNum = 1; 787 788 RC = UDFPhSendIOCTL(IOCTL_CDRW_CLOSE_TRK_SES, 789 Vcb->TargetDeviceObject, 790 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), 791 &CBuff,sizeof(CLOSE_TRK_SES_USER_IN), 792 FALSE, NULL ); 793 */ 794 } 795 // reset driver 796 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); 797 delay.QuadPart = -1000000; // 0.1 sec 798 KeDelayExecutionThread(KernelMode, FALSE, &delay); 799 } 800 // eject media 801 if(Eject && 802 (Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA)) { 803 804 UDFPhSendIOCTL(IOCTL_STORAGE_EJECT_MEDIA, 805 Vcb->TargetDeviceObject, 806 NULL,0, 807 NULL,0, 808 FALSE,NULL); 809 } 810 // notify media change 811 /* if(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER) { 812 ((PNOTIFY_MEDIA_CHANGE_USER_IN)Buf)->Autorun = FALSE; 813 RC = UDFPhSendIOCTL(IOCTL_CDRW_NOTIFY_MEDIA_CHANGE, 814 Vcb->TargetDeviceObject, 815 Buf,sizeof(NOTIFY_MEDIA_CHANGE_USER_IN), 816 NULL,0, 817 FALSE,NULL); 818 }*/ 819 } 820 UDFReleaseResource(&(Vcb->IoResource)); 821 // unregister shutdown notification 822 if(Vcb->ShutdownRegistered) { 823 IoUnregisterShutdownNotification(Vcb->VCBDeviceObject); 824 Vcb->ShutdownRegistered = FALSE; 825 } 826 // allow media change checks (this will lead to dismount) 827 // ... and make it Read-Only... :-\~ 828 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_MEDIA_LOCKED; 829 830 // Return back XP CD Burner Volume 831 /* 832 if (Vcb->CDBurnerVolumeValid) { 833 RtlWriteRegistryValue(RTL_REGISTRY_USER | RTL_REGISTRY_OPTIONAL, 834 REG_CD_BURNER_KEY_NAME,REG_CD_BURNER_VOLUME_NAME, 835 REG_SZ,(PVOID)&(Vcb->CDBurnerVolume),sizeof(Vcb->CDBurnerVolume)); 836 ExFreePool(Vcb->CDBurnerVolume.Buffer); 837 } 838 */ 839 UDFPrint((" set UnsafeIoctl\n")); 840 Vcb->VCBFlags |= UDF_VCB_FLAGS_UNSAFE_IOCTL; 841 842 return STATUS_SUCCESS; 843 } // end UDFDoDismountSequence() 844 845