- Timestamp:
- Oct 19, 2016 11:59:42 AM (8 years ago)
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvHostBase-darwin.cpp
r64278 r64316 27 27 #include <VBox/scsi.h> 28 28 29 /** 30 * Host backend specific data. 31 */ 32 typedef struct DRVHOSTBASEOS 33 { 34 /** The master port. */ 35 mach_port_t MasterPort; 36 /** The MMC-2 Device Interface. (This is only used to get the scsi task interface.) */ 37 MMCDeviceInterface **ppMMCDI; 38 /** The SCSI Task Device Interface. */ 39 SCSITaskDeviceInterface **ppScsiTaskDI; 40 /** The block size. Set when querying the media size. */ 41 uint32_t cbBlock; 42 /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */ 43 DASessionRef pDASession; 44 /** The disk arbitration disk reference. NULL if we didn't have to claim & unmount the device. */ 45 DADiskRef pDADisk; 46 /** The number of errors that could go into the release log. (flood gate) */ 47 uint32_t cLogRelErrors; 48 } DRVHOSTBASEOS; 49 /** Pointer to the host backend specific data. */ 50 typedef DRVHOSTBASEOS *PDRVHOSBASEOS; 51 AssertCompile(sizeof(DRVHOSTBASEOS) <= 64); 52 53 #define DRVHOSTBASE_OS_INT_DECLARED 29 54 #include "DrvHostBase.h" 55 56 /** The runloop input source name for the disk arbitration events. */ 57 # define MY_RUN_LOOP_MODE CFSTR("drvHostBaseDA") /** @todo r=bird: Check if this will cause trouble in the same way that the one in the USB code did. */ 58 59 /** 60 * Gets the BSD Name (/dev/disc[0-9]+) for the service. 61 * 62 * This is done by recursing down the I/O registry until we hit upon an entry 63 * with a BSD Name. Usually we find it two levels down. (Further down under 64 * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't 65 * seem to have to go this far fortunately.) 66 * 67 * @return VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise. 68 * @param Entry The current I/O registry entry reference. 69 * @param pszName Where to store the name. 128 bytes. 70 * @param cRecursions Number of recursions. This is used as an precaution 71 * just to limit the depth and avoid blowing the stack 72 * should we hit a bug or something. 73 */ 74 static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions) 75 { 76 int rc = VERR_FILE_NOT_FOUND; 77 io_iterator_t Children = 0; 78 kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children); 79 if (krc == KERN_SUCCESS) 80 { 81 io_object_t Child; 82 while ( rc == VERR_FILE_NOT_FOUND 83 && (Child = IOIteratorNext(Children)) != 0) 84 { 85 CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); 86 if (BSDNameStrRef) 87 { 88 if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8)) 89 rc = VINF_SUCCESS; 90 else 91 AssertFailed(); 92 CFRelease(BSDNameStrRef); 93 } 94 if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10) 95 rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1); 96 IOObjectRelease(Child); 97 } 98 IOObjectRelease(Children); 99 } 100 return rc; 101 } 102 103 104 /** 105 * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed. 106 * 107 * @param DiskRef The disk that was attempted claimed / unmounted. 108 * @param DissenterRef NULL on success, contains details on failure. 109 * @param pvContext Pointer to the return code variable. 110 */ 111 static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext) 112 { 113 RT_NOREF(DiskRef); 114 int *prc = (int *)pvContext; 115 if (!DissenterRef) 116 *prc = 0; 117 else 118 *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1; 119 CFRunLoopStop(CFRunLoopGetCurrent()); 120 } 121 122 123 /** 124 * Obtain exclusive access to the DVD device, umount it if necessary. 125 * 126 * @return VBox status code. 127 * @param pThis The driver instance. 128 * @param DVDService The DVD service object. 129 */ 130 static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService) 131 { 132 PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns); 133 134 for (unsigned iTry = 0;; iTry++) 135 { 136 IOReturn irc = (*pThis->Os.ppScsiTaskDI)->ObtainExclusiveAccess(pThis->Os.ppScsiTaskDI); 137 if (irc == kIOReturnSuccess) 138 { 139 /* 140 * This is a bit weird, but if we unmounted the DVD drive we also need to 141 * unlock it afterwards or the guest won't be able to eject it later on. 142 */ 143 if (pThis->Os.pDADisk) 144 { 145 uint8_t abCmd[16] = 146 { 147 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0, 148 0,0,0,0,0,0,0,0,0,0 149 }; 150 drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0); 151 } 152 return VINF_SUCCESS; 153 } 154 if (irc == kIOReturnExclusiveAccess) 155 return VERR_SHARING_VIOLATION; /* already used exclusivly. */ 156 if (irc != kIOReturnBusy) 157 return VERR_GENERAL_FAILURE; /* not mounted */ 158 159 /* 160 * Attempt to the unmount all volumes of the device. 161 * It seems we can can do this all in one go without having to enumerate the 162 * volumes (sessions) and deal with them one by one. This is very fortuitous 163 * as the disk arbitration API is a bit cumbersome to deal with. 164 */ 165 if (iTry > 2) 166 return VERR_DRIVE_LOCKED; 167 char szName[128]; 168 int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0); 169 if (RT_SUCCESS(rc)) 170 { 171 pThis->Os.pDASession = DASessionCreate(kCFAllocatorDefault); 172 if (pThis->Os.pDASession) 173 { 174 DASessionScheduleWithRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 175 pThis->Os.pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->Os.pDASession, szName); 176 if (pThis->Os.pDADisk) 177 { 178 /* 179 * Try claim the device. 180 */ 181 Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName)); 182 int rcDA = -2; 183 DADiskClaim(pThis->Os.pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA); 184 SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE); 185 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32)); 186 if ( rc32 == kCFRunLoopRunStopped 187 && !rcDA) 188 { 189 /* 190 * Try unmount the device. 191 */ 192 Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName)); 193 rcDA = -2; 194 DADiskUnmount(pThis->Os.pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA); 195 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE); 196 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32)); 197 if ( rc32 == kCFRunLoopRunStopped 198 && !rcDA) 199 { 200 iTry = 99; 201 DASessionUnscheduleFromRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 202 Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pReg->szName, pDrvIns->iInstance)); 203 continue; 204 } 205 Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA)); 206 207 /* failed - cleanup */ 208 DADiskUnclaim(pThis->Os.pDADisk); 209 } 210 else 211 Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA)); 212 213 CFRelease(pThis->Os.pDADisk); 214 pThis->Os.pDADisk = NULL; 215 } 216 else 217 Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName)); 218 219 DASessionUnscheduleFromRunLoop(pThis->Os.pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 220 CFRelease(pThis->Os.pDASession); 221 pThis->Os.pDASession = NULL; 222 } 223 else 224 Log(("%s-%d: failed to create DA session!\n", pDrvIns->pReg->szName, pDrvIns->iInstance)); 225 } 226 RTThreadSleep(10); 227 } 228 } 30 229 31 230 DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, … … 45 244 *pcbBuf = 0; 46 245 47 Assert(pThis-> ppScsiTaskDI);246 Assert(pThis->Os.ppScsiTaskDI); 48 247 49 248 int rc = VERR_GENERAL_FAILURE; 50 SCSITaskInterface **ppScsiTaskI = (*pThis-> ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI);249 SCSITaskInterface **ppScsiTaskI = (*pThis->Os.ppScsiTaskDI)->CreateSCSITask(pThis->Os.ppScsiTaskDI); 51 250 if (!ppScsiTaskI) 52 251 return VERR_NO_MEMORY; … … 110 309 ? VERR_READ_ERROR 111 310 : VERR_WRITE_ERROR; 112 if (pThis-> cLogRelErrors++ < 10)311 if (pThis->Os.cLogRelErrors++ < 10) 113 312 LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n", 114 313 cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE, … … 147 346 //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/ 148 347 // Buf.cbBlock = 2048; 149 pThis-> cbBlock = Buf.cbBlock;348 pThis->Os.cbBlock = Buf.cbBlock; 150 349 151 350 *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock; … … 159 358 int rc = VINF_SUCCESS; 160 359 161 if ( pThis-> ppScsiTaskDI162 && pThis-> cbBlock)360 if ( pThis->Os.ppScsiTaskDI 361 && pThis->Os.cbBlock) 163 362 { 164 363 /* … … 167 366 do 168 367 { 169 const uint32_t LBA = off / pThis-> cbBlock;170 AssertReturn(!(off % pThis-> cbBlock), VERR_INVALID_PARAMETER);368 const uint32_t LBA = off / pThis->Os.cbBlock; 369 AssertReturn(!(off % pThis->Os.cbBlock), VERR_INVALID_PARAMETER); 171 370 uint32_t cbRead32 = cbRead > SCSI_MAX_BUFFER_SIZE 172 371 ? SCSI_MAX_BUFFER_SIZE 173 372 : (uint32_t)cbRead; 174 const uint32_t cBlocks = cbRead32 / pThis-> cbBlock;175 AssertReturn(!(cbRead % pThis-> cbBlock), VERR_INVALID_PARAMETER);373 const uint32_t cBlocks = cbRead32 / pThis->Os.cbBlock; 374 AssertReturn(!(cbRead % pThis->Os.cbBlock), VERR_INVALID_PARAMETER); 176 375 uint8_t abCmd[16] = 177 376 { … … 233 432 DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent) 234 433 { 235 AssertReturn(pThis-> ppScsiTaskDI, VERR_INTERNAL_ERROR);434 AssertReturn(pThis->Os.ppScsiTaskDI, VERR_INTERNAL_ERROR); 236 435 237 436 /* … … 266 465 267 466 268 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis) 269 { 270 return RTSemEventSignal(pThis->EventPoller); 467 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis) 468 { 469 pThis->Os.MasterPort = IO_OBJECT_NULL; 470 pThis->Os.ppMMCDI = NULL; 471 pThis->Os.ppScsiTaskDI = NULL; 472 pThis->Os.cbBlock = 0; 473 pThis->Os.pDADisk = NULL; 474 pThis->Os.pDASession = NULL; 475 } 476 477 478 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) 479 { 480 RT_NOREF(fReadOnly); 481 482 /* Darwin is kind of special... */ 483 Assert(!pThis->Os.cbBlock); 484 Assert(pThis->Os.MasterPort == IO_OBJECT_NULL); 485 Assert(!pThis->Os.ppMMCDI); 486 Assert(!pThis->Os.ppScsiTaskDI); 487 488 /* 489 * Open the master port on the first invocation. 490 */ 491 kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &pThis->Os.MasterPort); 492 AssertReturn(krc == KERN_SUCCESS, VERR_GENERAL_FAILURE); 493 494 /* 495 * Create a matching dictionary for searching for CD, DVD and BlueRay services in the IOKit. 496 * 497 * The idea is to find all the devices which are of class IOCDBlockStorageDevice. 498 * CD devices are represented by IOCDBlockStorageDevice class itself, while DVD and BlueRay ones 499 * have it as a parent class. 500 */ 501 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOCDBlockStorageDevice"); 502 AssertReturn(RefMatchingDict, VERR_NOT_FOUND); 503 504 /* 505 * do the search and get a collection of keyboards. 506 */ 507 io_iterator_t DVDServices = IO_OBJECT_NULL; 508 IOReturn irc = IOServiceGetMatchingServices(pThis->Os.MasterPort, RefMatchingDict, &DVDServices); 509 AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), VERR_NOT_FOUND); 510 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */ 511 512 /* 513 * Enumerate the matching drives (services). 514 * (This enumeration must be identical to the one performed in Main/src-server/darwin/iokit.cpp.) 515 */ 516 int rc = VERR_FILE_NOT_FOUND; 517 unsigned i = 0; 518 io_object_t DVDService; 519 while ((DVDService = IOIteratorNext(DVDServices)) != 0) 520 { 521 /* 522 * Get the properties we use to identify the DVD drive. 523 * 524 * While there is a (weird 12 byte) GUID, it isn't persistent 525 * across boots. So, we have to use a combination of the 526 * vendor name and product name properties with an optional 527 * sequence number for identification. 528 */ 529 CFMutableDictionaryRef PropsRef = 0; 530 krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions); 531 if (krc == KERN_SUCCESS) 532 { 533 /* Get the Device Characteristics dictionary. */ 534 CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey)); 535 if (DevCharRef) 536 { 537 /* The vendor name. */ 538 char szVendor[128]; 539 char *pszVendor = &szVendor[0]; 540 CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey)); 541 if ( ValueRef 542 && CFGetTypeID(ValueRef) == CFStringGetTypeID() 543 && CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8)) 544 pszVendor = RTStrStrip(szVendor); 545 else 546 *pszVendor = '\0'; 547 548 /* The product name. */ 549 char szProduct[128]; 550 char *pszProduct = &szProduct[0]; 551 ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey)); 552 if ( ValueRef 553 && CFGetTypeID(ValueRef) == CFStringGetTypeID() 554 && CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8)) 555 pszProduct = RTStrStrip(szProduct); 556 else 557 *pszProduct = '\0'; 558 559 /* Construct the two names and compare thwm with the one we're searching for. */ 560 char szName1[256 + 32]; 561 char szName2[256 + 32]; 562 if (*pszVendor || *pszProduct) 563 { 564 if (*pszVendor && *pszProduct) 565 { 566 RTStrPrintf(szName1, sizeof(szName1), "%s %s", pszVendor, pszProduct); 567 RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", pszVendor, pszProduct, i); 568 } 569 else 570 { 571 strcpy(szName1, *pszVendor ? pszVendor : pszProduct); 572 RTStrPrintf(szName2, sizeof(szName2), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i); 573 } 574 } 575 else 576 { 577 RTStrPrintf(szName1, sizeof(szName1), "(#%u)", i); 578 strcpy(szName2, szName1); 579 } 580 581 if ( !strcmp(szName1, pThis->pszDevice) 582 || !strcmp(szName2, pThis->pszDevice)) 583 { 584 /* 585 * Found it! Now, get the client interface and stuff. 586 * Note that we could also query kIOSCSITaskDeviceUserClientTypeID here if the 587 * MMC client plugin is missing. For now we assume this won't be necessary. 588 */ 589 SInt32 Score = 0; 590 IOCFPlugInInterface **ppPlugInInterface = NULL; 591 krc = IOCreatePlugInInterfaceForService(DVDService, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID, 592 &ppPlugInInterface, &Score); 593 if (krc == KERN_SUCCESS) 594 { 595 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface, 596 CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID), 597 (LPVOID *)&pThis->Os.ppMMCDI); 598 (*ppPlugInInterface)->Release(ppPlugInInterface); 599 ppPlugInInterface = NULL; 600 if (hrc == S_OK) 601 { 602 pThis->Os.ppScsiTaskDI = (*pThis->Os.ppMMCDI)->GetSCSITaskDeviceInterface(pThis->Os.ppMMCDI); 603 if (pThis->Os.ppScsiTaskDI) 604 rc = VINF_SUCCESS; 605 else 606 { 607 LogRel(("GetSCSITaskDeviceInterface failed on '%s'\n", pThis->pszDevice)); 608 rc = VERR_NOT_SUPPORTED; 609 (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI); 610 } 611 } 612 else 613 { 614 rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinCOM(krc); 615 pThis->Os.ppMMCDI = NULL; 616 } 617 } 618 else /* Check for kIOSCSITaskDeviceUserClientTypeID? */ 619 rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc); 620 621 /* Obtain exclusive access to the device so we can send SCSI commands. */ 622 if (RT_SUCCESS(rc)) 623 rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService); 624 625 /* Cleanup on failure. */ 626 if (RT_FAILURE(rc)) 627 { 628 if (pThis->Os.ppScsiTaskDI) 629 { 630 (*pThis->Os.ppScsiTaskDI)->Release(pThis->Os.ppScsiTaskDI); 631 pThis->Os.ppScsiTaskDI = NULL; 632 } 633 if (pThis->Os.ppMMCDI) 634 { 635 (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI); 636 pThis->Os.ppMMCDI = NULL; 637 } 638 } 639 640 IOObjectRelease(DVDService); 641 break; 642 } 643 } 644 CFRelease(PropsRef); 645 } 646 else 647 AssertMsgFailed(("krc=%#x\n", krc)); 648 649 IOObjectRelease(DVDService); 650 i++; 651 } 652 653 IOObjectRelease(DVDServices); 654 return rc; 655 656 } 657 658 659 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis) 660 { 661 RT_NOREF(pThis); 662 return VINF_SUCCESS; 663 } 664 665 666 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis) 667 { 668 if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 669 return true; 670 671 AssertMsgFailed(("Darwin supports only CD/DVD host drive access\n")); 672 return false; 271 673 } 272 674 … … 274 676 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis) 275 677 { 276 if (pThis->EventPoller != NULL) 277 { 278 RTSemEventDestroy(pThis->EventPoller); 279 pThis->EventPoller = NULL; 678 /* 679 * Unlock the drive if we've locked it or we're in passthru mode. 680 */ 681 if ( ( pThis->fLocked 682 || pThis->IMedia.pfnSendCmd) 683 && pThis->Os.ppScsiTaskDI 684 && pThis->pfnDoLock) 685 { 686 int rc = pThis->pfnDoLock(pThis, false); 687 if (RT_SUCCESS(rc)) 688 pThis->fLocked = false; 280 689 } 281 690 … … 290 699 * and umount the DVD but somehow failed to gain exclusive scsi access... 291 700 */ 292 if (pThis-> ppScsiTaskDI)701 if (pThis->Os.ppScsiTaskDI) 293 702 { 294 703 LogFlow(("%s-%d: releasing exclusive scsi access!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 295 (*pThis-> ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI);296 (*pThis-> ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);297 pThis-> ppScsiTaskDI = NULL;298 } 299 if (pThis-> pDADisk)704 (*pThis->Os.ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->Os.ppScsiTaskDI); 705 (*pThis->Os.ppScsiTaskDI)->Release(pThis->Os.ppScsiTaskDI); 706 pThis->Os.ppScsiTaskDI = NULL; 707 } 708 if (pThis->Os.pDADisk) 300 709 { 301 710 LogFlow(("%s-%d: unclaiming the disk!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 302 DADiskUnclaim(pThis-> pDADisk);303 CFRelease(pThis-> pDADisk);304 pThis-> pDADisk = NULL;305 } 306 if (pThis-> ppMMCDI)711 DADiskUnclaim(pThis->Os.pDADisk); 712 CFRelease(pThis->Os.pDADisk); 713 pThis->Os.pDADisk = NULL; 714 } 715 if (pThis->Os.ppMMCDI) 307 716 { 308 717 LogFlow(("%s-%d: releasing the MMC object!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 309 (*pThis-> ppMMCDI)->Release(pThis->ppMMCDI);310 pThis-> ppMMCDI = NULL;311 } 312 if (pThis-> MasterPort != IO_OBJECT_NULL)313 { 314 mach_port_deallocate(mach_task_self(), pThis-> MasterPort);315 pThis-> MasterPort = IO_OBJECT_NULL;316 } 317 if (pThis-> pDASession)718 (*pThis->Os.ppMMCDI)->Release(pThis->Os.ppMMCDI); 719 pThis->Os.ppMMCDI = NULL; 720 } 721 if (pThis->Os.MasterPort != IO_OBJECT_NULL) 722 { 723 mach_port_deallocate(mach_task_self(), pThis->Os.MasterPort); 724 pThis->Os.MasterPort = IO_OBJECT_NULL; 725 } 726 if (pThis->Os.pDASession) 318 727 { 319 728 LogFlow(("%s-%d: releasing the DA session!\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 320 CFRelease(pThis-> pDASession);321 pThis-> pDASession = NULL;322 } 323 } 324 729 CFRelease(pThis->Os.pDASession); 730 pThis->Os.pDASession = NULL; 731 } 732 } 733 -
trunk/src/VBox/Devices/Storage/DrvHostBase-freebsd.cpp
r64278 r64316 27 27 #include <iprt/log.h> 28 28 29 /** 30 * Host backend specific data. 31 */ 32 typedef struct DRVHOSTBASEOS 33 { 34 /** The filehandle of the device. */ 35 RTFILE hFileDevice; 36 /** The block size. Set when querying the media size. */ 37 uint32_t cbBlock; 38 /** SCSI bus number. */ 39 path_id_t ScsiBus; 40 /** target ID of the passthrough device. */ 41 target_id_t ScsiTargetID; 42 /** LUN of the passthrough device. */ 43 lun_id_t ScsiLunID; 44 } DRVHOSTBASEOS; 45 /** Pointer to the host backend specific data. */ 46 typedef DRVHOSTBASEOS *PDRVHOSBASEOS; 47 AssertCompile(sizeof(DRVHOSTBASEOS) <= 64); 48 49 #define DRVHOSTBASE_OS_INT_DECLARED 29 50 #include "DrvHostBase.h" 30 51 … … 46 67 *pcbBuf = 0; 47 68 48 Assert(pThis->ppScsiTaskDI); 49 50 int rc = VERR_GENERAL_FAILURE; 51 SCSITaskInterface **ppScsiTaskI = (*pThis->ppScsiTaskDI)->CreateSCSITask(pThis->ppScsiTaskDI); 52 if (!ppScsiTaskI) 53 return VERR_NO_MEMORY; 54 do 55 { 56 /* Setup the scsi command. */ 57 SCSICommandDescriptorBlock cdb = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; 58 memcpy(&cdb[0], pbCmd, cbCmd); 59 IOReturn irc = (*ppScsiTaskI)->SetCommandDescriptorBlock(ppScsiTaskI, cdb, cbCmd); 60 AssertBreak(irc == kIOReturnSuccess); 61 62 /* Setup the buffer. */ 69 int rc = VINF_SUCCESS; 70 int rcBSD = 0; 71 union ccb DeviceCCB; 72 union ccb *pDeviceCCB = &DeviceCCB; 73 u_int32_t fFlags; 74 75 memset(pDeviceCCB, 0, sizeof(DeviceCCB)); 76 pDeviceCCB->ccb_h.path_id = pThis->Os.ScsiBus; 77 pDeviceCCB->ccb_h.target_id = pThis->Os.ScsiTargetID; 78 pDeviceCCB->ccb_h.target_lun = pThis->Os.ScsiLunID; 79 80 /* The SCSI INQUIRY command can't be passed through directly. */ 81 if (pbCmd[0] == SCSI_INQUIRY) 82 { 83 pDeviceCCB->ccb_h.func_code = XPT_GDEV_TYPE; 84 85 rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); 86 if (!rcBSD) 87 { 88 uint32_t cbCopy = cbBuf < sizeof(struct scsi_inquiry_data) 89 ? cbBuf 90 : sizeof(struct scsi_inquiry_data);; 91 memcpy(pvBuf, &pDeviceCCB->cgd.inq_data, cbCopy); 92 memset(pbSense, 0, cbSense); 93 94 if (pcbBuf) 95 *pcbBuf = cbCopy; 96 } 97 else 98 rc = RTErrConvertFromErrno(errno); 99 } 100 else 101 { 102 /* Copy the CDB. */ 103 memcpy(&pDeviceCCB->csio.cdb_io.cdb_bytes, pbCmd, cbCmd); 104 105 /* Set direction. */ 63 106 if (enmTxDir == PDMMEDIATXDIR_NONE) 64 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, NULL, 0, 0, kSCSIDataTransfer_NoDataTransfer); 107 fFlags = CAM_DIR_NONE; 108 else if (enmTxDir == PDMMEDIATXDIR_FROM_DEVICE) 109 fFlags = CAM_DIR_IN; 65 110 else 111 fFlags = CAM_DIR_OUT; 112 113 fFlags |= CAM_DEV_QFRZDIS; 114 115 cam_fill_csio(&pDeviceCCB->csio, 1, NULL, fFlags, MSG_SIMPLE_Q_TAG, 116 (u_int8_t *)pvBuf, cbBuf, cbSense, cbCmd, 117 cTimeoutMillies ? cTimeoutMillies : 30000/* timeout */); 118 119 /* Send command */ 120 rcBSD = ioctl(RTFileToNative(pThis->Os.hFileDevice), CAMIOCOMMAND, pDeviceCCB); 121 if (!rcBSD) 66 122 { 67 IOVirtualRange Range = { (IOVirtualAddress)pvBuf, cbBuf }; 68 irc = (*ppScsiTaskI)->SetScatterGatherEntries(ppScsiTaskI, &Range, 1, cbBuf, 69 enmTxDir == PDMMEDIATXDIR_FROM_DEVICE 70 ? kSCSIDataTransfer_FromTargetToInitiator 71 : kSCSIDataTransfer_FromInitiatorToTarget); 123 switch (pDeviceCCB->ccb_h.status & CAM_STATUS_MASK) 124 { 125 case CAM_REQ_CMP: 126 rc = VINF_SUCCESS; 127 break; 128 case CAM_SEL_TIMEOUT: 129 rc = VERR_DEV_IO_ERROR; 130 break; 131 case CAM_CMD_TIMEOUT: 132 rc = VERR_TIMEOUT; 133 break; 134 default: 135 rc = VERR_DEV_IO_ERROR; 136 } 137 138 if (pcbBuf) 139 *pcbBuf = cbBuf - pDeviceCCB->csio.resid; 140 141 if (pbSense) 142 memcpy(pbSense, &pDeviceCCB->csio.sense_data, 143 cbSense - pDeviceCCB->csio.sense_resid); 72 144 } 73 AssertBreak(irc == kIOReturnSuccess);74 75 /* Set the timeout. */76 irc = (*ppScsiTaskI)->SetTimeoutDuration(ppScsiTaskI, cTimeoutMillies ? cTimeoutMillies : 30000 /*ms*/);77 AssertBreak(irc == kIOReturnSuccess);78 79 /* Execute the command and get the response. */80 SCSI_Sense_Data SenseData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };81 SCSIServiceResponse ServiceResponse = kSCSIServiceResponse_Request_In_Process;82 SCSITaskStatus TaskStatus = kSCSITaskStatus_GOOD;83 UInt64 cbReturned = 0;84 irc = (*ppScsiTaskI)->ExecuteTaskSync(ppScsiTaskI, &SenseData, &TaskStatus, &cbReturned);85 AssertBreak(irc == kIOReturnSuccess);86 if (pcbBuf)87 *pcbBuf = (int32_t)cbReturned;88 89 irc = (*ppScsiTaskI)->GetSCSIServiceResponse(ppScsiTaskI, &ServiceResponse);90 AssertBreak(irc == kIOReturnSuccess);91 AssertBreak(ServiceResponse == kSCSIServiceResponse_TASK_COMPLETE);92 93 if (TaskStatus == kSCSITaskStatus_GOOD)94 rc = VINF_SUCCESS;95 else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION96 && pbSense)97 {98 memset(pbSense, 0, cbSense); /* lazy */99 memcpy(pbSense, &SenseData, RT_MIN(sizeof(SenseData), cbSense));100 rc = VERR_UNRESOLVED_ERROR;101 }102 /** @todo convert sense codes when caller doesn't wish to do this himself. */103 /*else if ( TaskStatus == kSCSITaskStatus_CHECK_CONDITION104 && SenseData.ADDITIONAL_SENSE_CODE == 0x3A)105 rc = VERR_MEDIA_NOT_PRESENT; */106 145 else 107 { 108 rc = enmTxDir == PDMMEDIATXDIR_NONE 109 ? VERR_DEV_IO_ERROR 110 : enmTxDir == PDMMEDIATXDIR_FROM_DEVICE 111 ? VERR_READ_ERROR 112 : VERR_WRITE_ERROR; 113 if (pThis->cLogRelErrors++ < 10) 114 LogRel(("DVD scsi error: cmd={%.*Rhxs} TaskStatus=%#x key=%#x ASC=%#x ASCQ=%#x (%Rrc)\n", 115 cbCmd, pbCmd, TaskStatus, SenseData.SENSE_KEY, SenseData.ADDITIONAL_SENSE_CODE, 116 SenseData.ADDITIONAL_SENSE_CODE_QUALIFIER, rc)); 117 } 118 } while (0); 119 120 (*ppScsiTaskI)->Release(ppScsiTaskI); 121 122 return rc; 146 rc = RTErrConvertFromErrno(errno); 147 } 123 148 } 124 149 … … 148 173 //if (Buf.cbBlock > 2048) /* everyone else is doing this... check if it needed/right.*/ 149 174 // Buf.cbBlock = 2048; 150 pThis-> cbBlock = Buf.cbBlock;175 pThis->Os.cbBlock = Buf.cbBlock; 151 176 152 177 *pcb = (uint64_t)Buf.cBlocks * Buf.cbBlock; … … 160 185 int rc = VINF_SUCCESS; 161 186 162 if (pThis-> cbBlock)187 if (pThis->Os.cbBlock) 163 188 { 164 189 /* … … 167 192 do 168 193 { 169 const uint32_t LBA = off / pThis-> cbBlock;170 AssertReturn(!(off % pThis-> cbBlock), VERR_INVALID_PARAMETER);194 const uint32_t LBA = off / pThis->Os.cbBlock; 195 AssertReturn(!(off % pThis->Os.cbBlock), VERR_INVALID_PARAMETER); 171 196 uint32_t cbRead32 = cbRead > SCSI_MAX_BUFFER_SIZE 172 197 ? SCSI_MAX_BUFFER_SIZE 173 198 : (uint32_t)cbRead; 174 const uint32_t cBlocks = cbRead32 / pThis-> cbBlock;175 AssertReturn(!(cbRead % pThis-> cbBlock), VERR_INVALID_PARAMETER);199 const uint32_t cBlocks = cbRead32 / pThis->Os.cbBlock; 200 AssertReturn(!(cbRead % pThis->Os.cbBlock), VERR_INVALID_PARAMETER); 176 201 uint8_t abCmd[16] = 177 202 { … … 264 289 265 290 266 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis) 267 { 268 return RTSemEventSignal(pThis->EventPoller); 291 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis) 292 { 293 pThis->Os.hFileDevice = NIL_RTFILE; 294 } 295 296 297 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) 298 { 299 RT_NOREF(fReadOnly); 300 RTFILE hFileDevice; 301 int rc = RTFileOpen(&hFileDevice, pThis->pszDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 302 if (RT_FAILURE(rc)) 303 return rc; 304 305 /* 306 * The current device handle can't passthrough SCSI commands. 307 * We have to get he passthrough device path and open this. 308 */ 309 union ccb DeviceCCB; 310 memset(&DeviceCCB, 0, sizeof(DeviceCCB)); 311 312 DeviceCCB.ccb_h.func_code = XPT_GDEVLIST; 313 int rcBSD = ioctl(RTFileToNative(hFileDevice), CAMGETPASSTHRU, &DeviceCCB); 314 if (!rcBSD) 315 { 316 char *pszPassthroughDevice = NULL; 317 rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u", 318 DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number); 319 if (rc >= 0) 320 { 321 RTFILE hPassthroughDevice; 322 rc = RTFileOpen(&hPassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 323 RTStrFree(pszPassthroughDevice); 324 if (RT_SUCCESS(rc)) 325 { 326 /* Get needed device parameters. */ 327 328 /* 329 * The device path, target id and lun id. Those are 330 * needed for the SCSI passthrough ioctl. 331 */ 332 memset(&DeviceCCB, 0, sizeof(DeviceCCB)); 333 DeviceCCB.ccb_h.func_code = XPT_GDEVLIST; 334 335 rcBSD = ioctl(RTFileToNative(hPassthroughDevice), CAMGETPASSTHRU, &DeviceCCB); 336 if (!rcBSD) 337 { 338 if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR) 339 { 340 pThis->Os.ScsiBus = DeviceCCB.ccb_h.path_id; 341 pThis->Os.ScsiTargetID = DeviceCCB.ccb_h.target_id; 342 pThis->Os.ScsiLunID = DeviceCCB.ccb_h.target_lun; 343 pThis->Os.hFileDevice = hPassthroughDevice; 344 } 345 else 346 { 347 /* The passthrough device wasn't found. */ 348 rc = VERR_NOT_FOUND; 349 } 350 } 351 else 352 rc = RTErrConvertFromErrno(errno); 353 354 if (RT_FAILURE(rc)) 355 RTFileClose(hPassthroughDevice); 356 } 357 } 358 else 359 rc = VERR_NO_STR_MEMORY; 360 } 361 else 362 rc = RTErrConvertFromErrno(errno); 363 364 RTFileClose(hFileDevice); 365 return rc; 366 } 367 368 369 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis) 370 { 371 RT_NOREF(pThis); 372 return VINF_SUCCESS; 373 } 374 375 376 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis) 377 { 378 if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 379 return true; 380 381 AssertMsgFailed(("FreeBSD supports only CD/DVD host drive access\n")); 382 return false; 269 383 } 270 384 … … 272 386 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis) 273 387 { 274 if (pThis->EventPoller != NULL) 275 { 276 RTSemEventDestroy(pThis->EventPoller); 277 pThis->EventPoller = NULL; 278 } 279 280 if (pThis->hFileDevice != NIL_RTFILE) 281 { 282 int rc = RTFileClose(pThis->hFileDevice); 388 /* 389 * Unlock the drive if we've locked it or we're in passthru mode. 390 */ 391 if ( pThis->fLocked 392 && pThis->Os.hFileDevice != NIL_RTFILE 393 && pThis->pfnDoLock) 394 { 395 int rc = pThis->pfnDoLock(pThis, false); 396 if (RT_SUCCESS(rc)) 397 pThis->fLocked = false; 398 } 399 400 if (pThis->Os.hFileDevice != NIL_RTFILE) 401 { 402 int rc = RTFileClose(pThis->Os.hFileDevice); 283 403 AssertRC(rc); 284 pThis-> hFileDevice = NIL_RTFILE;285 } 286 } 287 404 pThis->Os.hFileDevice = NIL_RTFILE; 405 } 406 } 407 -
trunk/src/VBox/Devices/Storage/DrvHostBase-linux.cpp
r64278 r64316 39 39 #include <VBox/scsi.h> 40 40 41 /** 42 * Host backend specific data. 43 */ 44 typedef struct DRVHOSTBASEOS 45 { 46 /** The filehandle of the device. */ 47 RTFILE hFileDevice; 48 /** Double buffer required for ioctl with the Linux kernel as long as we use 49 * remap_pfn_range() instead of vm_insert_page(). */ 50 uint8_t *pbDoubleBuffer; 51 /** Previous disk inserted indicator for the media polling on floppy drives. */ 52 bool fPrevDiskIn; 53 } DRVHOSTBASEOS; 54 /** Pointer to the host backend specific data. */ 55 typedef DRVHOSTBASEOS *PDRVHOSBASEOS; 56 AssertCompile(sizeof(DRVHOSTBASEOS) <= 64); 57 58 #define DRVHOSTBASE_OS_INT_DECLARED 41 59 #include "DrvHostBase.h" 42 60 … … 53 71 AssertPtr(pbCmd); 54 72 Assert(cbCmd <= 16 && cbCmd >= 1); 73 74 /* Allocate the temporary buffer lazily. */ 75 if(RT_UNLIKELY(!pThis->Os.pbDoubleBuffer)) 76 { 77 pThis->Os.pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE); 78 if (!pThis->Os.pbDoubleBuffer) 79 return VERR_NO_MEMORY; 80 } 55 81 56 82 int rc = VERR_GENERAL_FAILURE; … … 74 100 * security problems inside the guest OS, if users can issue 75 101 * commands to the CDROM device. */ 76 memset(pThis-> pbDoubleBuffer, '\0', *pcbBuf);102 memset(pThis->Os.pbDoubleBuffer, '\0', *pcbBuf); 77 103 direction = CGC_DATA_READ; 78 104 break; … … 80 106 Assert(*pcbBuf != 0); 81 107 Assert(*pcbBuf <= SCSI_MAX_BUFFER_SIZE); 82 memcpy(pThis-> pbDoubleBuffer, pvBuf, *pcbBuf);108 memcpy(pThis->Os.pbDoubleBuffer, pvBuf, *pcbBuf); 83 109 direction = CGC_DATA_WRITE; 84 110 break; … … 89 115 memset(&cgc, '\0', sizeof(cgc)); 90 116 memcpy(cgc.cmd, pbCmd, RT_MIN(CDROM_PACKET_SIZE, cbCmd)); 91 cgc.buffer = (unsigned char *)pThis-> pbDoubleBuffer;117 cgc.buffer = (unsigned char *)pThis->Os.pbDoubleBuffer; 92 118 cgc.buflen = *pcbBuf; 93 119 cgc.stat = 0; … … 97 123 cgc.quiet = false; 98 124 cgc.timeout = cTimeoutMillies; 99 rc = ioctl(RTFileToNative(pThis-> hFileDevice), CDROM_SEND_PACKET, &cgc);125 rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_SEND_PACKET, &cgc); 100 126 if (rc < 0) 101 127 { … … 115 141 { 116 142 case PDMMEDIATXDIR_FROM_DEVICE: 117 memcpy(pvBuf, pThis-> pbDoubleBuffer, *pcbBuf);143 memcpy(pvBuf, pThis->Os.pbDoubleBuffer, *pcbBuf); 118 144 break; 119 145 default: … … 134 160 if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType)) 135 161 { 136 rc = ioctl(RTFileToNative(pThis-> hFileDevice), FDFLUSH);162 rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDFLUSH); 137 163 if (rc) 138 164 { … … 143 169 144 170 floppy_drive_struct DrvStat; 145 rc = ioctl(RTFileToNative(pThis-> hFileDevice), FDGETDRVSTAT, &DrvStat);171 rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDGETDRVSTAT, &DrvStat); 146 172 if (rc) 147 173 { … … 151 177 } 152 178 pThis->fReadOnly = !(DrvStat.flags & FD_DISK_WRITABLE); 153 rc = RTFileSeek(pThis-> hFileDevice, 0, RTFILE_SEEK_END, pcb);179 rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb); 154 180 } 155 181 else if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 156 182 { 157 183 /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */ 158 ioctl(RTFileToNative(pThis-> hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT);159 rc = RTFileSeek(pThis-> hFileDevice, 0, RTFILE_SEEK_END, pcb);184 ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT); 185 rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb); 160 186 } 161 187 … … 166 192 DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead) 167 193 { 168 return RTFileReadAt(pThis-> hFileDevice, off, pvBuf, cbRead, NULL);194 return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL); 169 195 } 170 196 … … 172 198 DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite) 173 199 { 174 return RTFileWriteAt(pThis-> hFileDevice, off, pvBuf, cbWrite, NULL);200 return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL); 175 201 } 176 202 … … 178 204 DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis) 179 205 { 180 return RTFileFlush(pThis-> hFileDevice);206 return RTFileFlush(pThis->Os.hFileDevice); 181 207 } 182 208 … … 184 210 DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock) 185 211 { 186 int rc = ioctl(RTFileToNative(pThis-> hFileDevice), CDROM_LOCKDOOR, (int)fLock);212 int rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_LOCKDOOR, (int)fLock); 187 213 if (rc < 0) 188 214 { … … 201 227 DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis) 202 228 { 203 int rc = ioctl(RTFileToNative(pThis-> hFileDevice), CDROMEJECT, 0);229 int rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROMEJECT, 0); 204 230 if (rc < 0) 205 231 { … … 218 244 DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent) 219 245 { 220 *pfMediaPresent = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK; 221 *pfMediaChanged = false; 222 if (pThis->fMediaPresent != *pfMediaPresent) 223 *pfMediaChanged = ioctl(RTFileToNative(pThis->hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1; 224 225 return VINF_SUCCESS; 226 } 227 228 229 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis) 230 { 231 return RTSemEventSignal(pThis->EventPoller); 246 int rc = VINF_SUCCESS; 247 248 if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType)) 249 { 250 floppy_drive_struct DrvStat; 251 int rcLnx = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDPOLLDRVSTAT, &DrvStat); 252 if (!rcLnx) 253 { 254 bool fDiskIn = !(DrvStat.flags & (FD_VERIFY | FD_DISK_NEWCHANGE)); 255 *pfMediaPresent = fDiskIn; 256 257 if (fDiskIn != pThis->Os.fPrevDiskIn) 258 *pfMediaChanged = true; 259 260 pThis->Os.fPrevDiskIn = fDiskIn; 261 } 262 else 263 rc = RTErrConvertFromErrno(errno); 264 } 265 else 266 { 267 *pfMediaPresent = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK; 268 *pfMediaChanged = false; 269 if (pThis->fMediaPresent != *pfMediaPresent) 270 *pfMediaChanged = ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT) == 1; 271 } 272 273 return rc; 274 } 275 276 277 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis) 278 { 279 pThis->Os.hFileDevice = NIL_RTFILE; 280 pThis->Os.pbDoubleBuffer = NULL; 281 pThis->Os.fPrevDiskIn = false; 282 } 283 284 285 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) 286 { 287 uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK; 288 return RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDevice, fFlags); 289 } 290 291 292 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis) 293 { 294 /* 295 * Need to re-open the device because it will kill off any cached data 296 * that Linux for some peculiar reason thinks should survive a media change. 297 */ 298 if (pThis->Os.hFileDevice != NIL_RTFILE) 299 { 300 RTFileClose(pThis->Os.hFileDevice); 301 pThis->Os.hFileDevice = NIL_RTFILE; 302 } 303 int rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig); 304 if (RT_FAILURE(rc)) 305 { 306 if (!pThis->fReadOnlyConfig) 307 { 308 LogFlow(("%s-%d: drvHostBaseMediaRefreshOs: '%s' - retry readonly (%Rrc)\n", 309 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc)); 310 rc = drvHostBaseOpenOs(pThis, true); 311 } 312 if (RT_FAILURE(rc)) 313 { 314 LogFlow(("%s-%d: failed to open device '%s', rc=%Rrc\n", 315 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc)); 316 return rc; 317 } 318 pThis->fReadOnly = true; 319 } 320 else 321 pThis->fReadOnly = pThis->fReadOnlyConfig; 322 323 return rc; 324 } 325 326 327 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis) 328 { 329 RT_NOREF(pThis); 330 return true; /* On Linux we always use media polling. */ 232 331 } 233 332 … … 235 334 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis) 236 335 { 237 if (pThis->pbDoubleBuffer) 238 { 239 RTMemFree(pThis->pbDoubleBuffer); 240 pThis->pbDoubleBuffer = NULL; 241 } 242 243 if (pThis->EventPoller != NULL) 244 { 245 RTSemEventDestroy(pThis->EventPoller); 246 pThis->EventPoller = NULL; 247 } 248 249 if (pThis->hFileDevice != NIL_RTFILE) 250 { 251 int rc = RTFileClose(pThis->hFileDevice); 336 /* 337 * Unlock the drive if we've locked it or we're in passthru mode. 338 */ 339 if ( pThis->fLocked 340 && pThis->Os.hFileDevice != NIL_RTFILE 341 && pThis->pfnDoLock) 342 { 343 int rc = pThis->pfnDoLock(pThis, false); 344 if (RT_SUCCESS(rc)) 345 pThis->fLocked = false; 346 } 347 348 if (pThis->Os.pbDoubleBuffer) 349 { 350 RTMemFree(pThis->Os.pbDoubleBuffer); 351 pThis->Os.pbDoubleBuffer = NULL; 352 } 353 354 if (pThis->Os.hFileDevice != NIL_RTFILE) 355 { 356 int rc = RTFileClose(pThis->Os.hFileDevice); 252 357 AssertRC(rc); 253 pThis-> hFileDevice = NIL_RTFILE;254 } 255 } 256 358 pThis->Os.hFileDevice = NIL_RTFILE; 359 } 360 } 361 -
trunk/src/VBox/Devices/Storage/DrvHostBase-solaris.cpp
r64278 r64316 33 33 34 34 #include <iprt/file.h> 35 36 /** 37 * Host backend specific data. 38 */ 39 typedef struct DRVHOSTBASEOS 40 { 41 /** The filehandle of the device. */ 42 RTFILE hFileDevice; 43 /** The raw filehandle of the device. */ 44 RTFILE hFileRawDevice; 45 /** Device name of raw device (RTStrFree). */ 46 char *pszRawDeviceOpen; 47 } DRVHOSTBASEOS; 48 /** Pointer to the host backend specific data. */ 49 typedef DRVHOSTBASEOS *PDRVHOSBASEOS; 50 AssertCompile(sizeof(DRVHOSTBASEOS) <= 64); 51 52 #define DRVHOSTBASE_OS_INT_DECLARED 35 53 #include "DrvHostBase.h" 36 54 … … 40 58 * return the value. BUT... this might be prohibitively slow. 41 59 */ 60 61 /** 62 * Checks if the current user is authorized using Solaris' role-based access control. 63 * Made as a separate function with so that it need not be invoked each time we need 64 * to gain root access. 65 * 66 * @returns VBox error code. 67 */ 68 static int solarisCheckUserAuth() 69 { 70 /* Uses Solaris' role-based access control (RBAC).*/ 71 struct passwd *pPass = getpwuid(getuid()); 72 if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0) 73 return VERR_PERMISSION_DENIED; 74 75 return VINF_SUCCESS; 76 } 42 77 43 78 /** … … 148 183 solarisEnterRootMode(&effUserID); /** @todo check return code when this really works. */ 149 184 #endif 150 rc = ioctl(RTFileToNative(pThis-> hFileRawDevice), USCSICMD, &usc);185 rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), USCSICMD, &usc); 151 186 #ifdef VBOX_WITH_SUID_WRAPPER 152 187 solarisExitRootMode(&effUserID); … … 175 210 */ 176 211 struct dk_minfo MediaInfo; 177 if (ioctl(RTFileToNative(pThis-> hFileRawDevice), DKIOCGMEDIAINFO, &MediaInfo) == 0)212 if (ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCGMEDIAINFO, &MediaInfo) == 0) 178 213 { 179 214 *pcb = MediaInfo.dki_capacity * (uint64_t)MediaInfo.dki_lbsize; 180 215 return VINF_SUCCESS; 181 216 } 182 return RTFileSeek(pThis-> hFileDevice, 0, RTFILE_SEEK_END, pcb);217 return RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb); 183 218 } 184 219 … … 186 221 DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead) 187 222 { 188 return RTFileReadAt(pThis-> hFileDevice, off, pvBuf, cbRead, NULL);223 return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL); 189 224 } 190 225 … … 192 227 DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite) 193 228 { 194 return RTFileWriteAt(pThis-> hFileDevice, off, pvBuf, cbWrite, NULL);229 return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL); 195 230 } 196 231 … … 198 233 DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis) 199 234 { 200 return RTFileFlush(pThis-> hFileDevice);235 return RTFileFlush(pThis->Os.hFileDevice); 201 236 } 202 237 … … 204 239 DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock) 205 240 { 206 int rc = ioctl(RTFileToNative(pThis-> hFileRawDevice), fLock ? DKIOCLOCK : DKIOCUNLOCK, 0);241 int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), fLock ? DKIOCLOCK : DKIOCUNLOCK, 0); 207 242 if (rc < 0) 208 243 { … … 221 256 DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis) 222 257 { 223 int rc = ioctl(RTFileToNative(pThis-> hFileRawDevice), DKIOCEJECT, 0);258 int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCEJECT, 0); 224 259 if (rc < 0) 225 260 { … … 246 281 static dkio_state s_DeviceState = DKIO_NONE; 247 282 dkio_state PreviousState = s_DeviceState; 248 int rc = ioctl(RTFileToNative(pThis-> hFileRawDevice), DKIOCSTATE, &s_DeviceState);283 int rc = ioctl(RTFileToNative(pThis->Os.hFileRawDevice), DKIOCSTATE, &s_DeviceState); 249 284 if (rc == 0) 250 285 { … … 258 293 259 294 260 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis) 261 { 262 return RTSemEventSignal(pThis->EventPoller); 295 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis) 296 { 297 pThis->Os.hFileDevice = NIL_RTFILE; 298 pThis->Os.hFileRawDevice = NIL_RTFILE; 299 pThis->Os.pszRawDeviceOpen = NULL; 300 } 301 302 303 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) 304 { 305 #ifdef VBOX_WITH_SUID_WRAPPER /* Solaris setuid for Passthrough mode. */ 306 if ( (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 307 && pThis->IMedia.pfnSendCmd) 308 { 309 rc = solarisCheckUserAuth(); 310 if (RT_FAILURE(rc)) 311 { 312 Log(("DVD: solarisCheckUserAuth failed. Permission denied!\n")); 313 return rc; 314 } 315 } 316 #endif /* VBOX_WITH_SUID_WRAPPER */ 317 318 char *pszBlockDevName = getfullblkname(pThis->pszDevice); 319 if (!pszBlockDevName) 320 return VERR_NO_MEMORY; 321 pThis->pszDeviceOpen = RTStrDup(pszBlockDevName); /* for RTStrFree() */ 322 free(pszBlockDevName); 323 pThis->Os.pszRawDeviceOpen = RTStrDup(pThis->pszDevice); 324 if (!pThis->pszDeviceOpen || !pThis->Os.pszRawDeviceOpen); 325 return VERR_NO_MEMORY; 326 327 unsigned fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) 328 | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK; 329 int rc = RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDeviceOpen, fFlags); 330 if (RT_SUCCESS(rc)) 331 { 332 rc = RTFileOpen(&pThis->Os.hFileRawDevice, pThis->Os.pszRawDeviceOpen, fFlags); 333 if (RT_SUCCESS(rc)) 334 return rc; 335 336 LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->Os.pszRawDeviceOpen, rc)); 337 RTFileClose(pThis->Os.hFileDevice); 338 } 339 else 340 LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszDeviceOpen, rc)); 341 return rc; 342 } 343 344 345 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis) 346 { 347 RT_NOREF(pThis); 348 return VINF_SUCCESS; 349 } 350 351 352 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis) 353 { 354 if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 355 return true; 356 357 AssertMsgFailed(("Solaris supports only CD/DVD host drive access\n")); 358 return false; 263 359 } 264 360 … … 266 362 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis) 267 363 { 268 if (pThis->EventPoller != NULL) 269 { 270 RTSemEventDestroy(pThis->EventPoller); 271 pThis->EventPoller = NULL; 272 } 273 274 if (pThis->hFileDevice != NIL_RTFILE) 275 { 276 int rc = RTFileClose(pThis->hFileDevice); 364 /* 365 * Unlock the drive if we've locked it or we're in passthru mode. 366 */ 367 if ( pThis->fLocked 368 && pThis->Os.hFileDevice != NIL_RTFILE 369 && pThis->pfnDoLock) 370 { 371 int rc = pThis->pfnDoLock(pThis, false); 372 if (RT_SUCCESS(rc)) 373 pThis->fLocked = false; 374 } 375 376 if (pThis->Os.hFileDevice != NIL_RTFILE) 377 { 378 int rc = RTFileClose(pThis->Os.hFileDevice); 277 379 AssertRC(rc); 278 pThis-> hFileDevice = NIL_RTFILE;279 } 280 281 if (pThis-> hFileRawDevice != NIL_RTFILE)282 { 283 int rc = RTFileClose(pThis-> hFileRawDevice);380 pThis->Os.hFileDevice = NIL_RTFILE; 381 } 382 383 if (pThis->Os.hFileRawDevice != NIL_RTFILE) 384 { 385 int rc = RTFileClose(pThis->Os.hFileRawDevice); 284 386 AssertRC(rc); 285 pThis-> hFileRawDevice = NIL_RTFILE;286 } 287 288 if (pThis-> pszRawDeviceOpen)289 { 290 RTStrFree(pThis-> pszRawDeviceOpen);291 pThis-> pszRawDeviceOpen = NULL;292 } 293 } 294 387 pThis->Os.hFileRawDevice = NIL_RTFILE; 388 } 389 390 if (pThis->Os.pszRawDeviceOpen) 391 { 392 RTStrFree(pThis->Os.pszRawDeviceOpen); 393 pThis->Os.pszRawDeviceOpen = NULL; 394 } 395 } 396 -
trunk/src/VBox/Devices/Storage/DrvHostBase-win.cpp
r64278 r64316 77 77 /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass ); 78 78 79 #include <iprt/ctype.h> 79 80 #include <iprt/file.h> 80 81 #include <VBox/scsi.h> 81 82 83 /** 84 * Host backend specific data. 85 */ 86 typedef struct DRVHOSTBASEOS 87 { 88 /** The filehandle of the device. */ 89 RTFILE hFileDevice; 90 /** Handle to the window we use to catch the device change broadcast messages. */ 91 volatile HWND hwndDeviceChange; 92 /** The unit mask. */ 93 DWORD fUnitMask; 94 /** Handle of the poller thread. */ 95 RTTHREAD hThrdMediaChange; 96 } DRVHOSTBASEOS; 97 /** Pointer to the host backend specific data. */ 98 typedef DRVHOSTBASEOS *PDRVHOSBASEOS; 99 AssertCompile(sizeof(DRVHOSTBASEOS) <= 64); 100 101 #define DRVHOSTBASE_OS_INT_DECLARED 82 102 #include "DrvHostBase.h" 103 104 105 /** 106 * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts. 107 */ 108 static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 109 { 110 Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg)); 111 if (uMsg == WM_DESTROY) 112 { 113 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA); 114 if (pThis) 115 ASMAtomicXchgSize(&pThis->Os.hwndDeviceChange, NULL); 116 PostQuitMessage(0); 117 } 118 119 if (uMsg != WM_DEVICECHANGE) 120 return DefWindowProc(hwnd, uMsg, wParam, lParam); 121 122 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam; 123 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA); 124 Assert(pThis); 125 if (pThis == NULL) 126 return 0; 127 128 switch (wParam) 129 { 130 case DBT_DEVICEARRIVAL: 131 case DBT_DEVICEREMOVECOMPLETE: 132 // Check whether a CD or DVD was inserted into or removed from a drive. 133 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) 134 { 135 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; 136 if ( (lpdbv->dbcv_flags & DBTF_MEDIA) 137 && (pThis->Os.fUnitMask & lpdbv->dbcv_unitmask)) 138 { 139 RTCritSectEnter(&pThis->CritSect); 140 if (wParam == DBT_DEVICEARRIVAL) 141 { 142 int cRetries = 10; 143 int rc = DRVHostBaseMediaPresent(pThis); 144 while (RT_FAILURE(rc) && cRetries-- > 0) 145 { 146 RTThreadSleep(50); 147 rc = DRVHostBaseMediaPresent(pThis); 148 } 149 } 150 else 151 DRVHostBaseMediaNotPresent(pThis); 152 RTCritSectLeave(&pThis->CritSect); 153 } 154 } 155 break; 156 } 157 return TRUE; 158 } 159 160 161 /** 162 * This thread will wait for changed media notificatons. 163 * 164 * @returns Ignored. 165 * @param ThreadSelf Handle of this thread. Ignored. 166 * @param pvUser Pointer to the driver instance structure. 167 */ 168 static DECLCALLBACK(int) drvHostBaseMediaThreadWin(RTTHREAD ThreadSelf, void *pvUser) 169 { 170 PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser; 171 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: ThreadSelf=%p pvUser=%p\n", 172 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser)); 173 static WNDCLASS s_classDeviceChange = {0}; 174 static ATOM s_hAtomDeviceChange = 0; 175 176 /* 177 * Register custom window class. 178 */ 179 if (s_hAtomDeviceChange == 0) 180 { 181 memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange)); 182 s_classDeviceChange.lpfnWndProc = DeviceChangeWindowProc; 183 s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass"; 184 s_classDeviceChange.hInstance = GetModuleHandle("VBoxDD.dll"); 185 Assert(s_classDeviceChange.hInstance); 186 s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange); 187 Assert(s_hAtomDeviceChange); 188 } 189 190 /* 191 * Create Window w/ the pThis as user data. 192 */ 193 HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0); 194 AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError())); 195 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis); 196 197 /* 198 * Signal the waiting EMT thread that everything went fine. 199 */ 200 ASMAtomicXchgPtr((void * volatile *)&pThis->Os.hwndDeviceChange, hwnd); 201 RTThreadUserSignal(ThreadSelf); 202 if (!hwnd) 203 { 204 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 205 return VERR_GENERAL_FAILURE; 206 } 207 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, hwnd)); 208 209 /* 210 * Message pump. 211 */ 212 MSG Msg; 213 BOOL fRet; 214 while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE) 215 { 216 if (fRet != -1) 217 { 218 TranslateMessage(&Msg); 219 DispatchMessage(&Msg); 220 } 221 //else: handle the error and possibly exit 222 } 223 Assert(!pThis->Os.hwndDeviceChange); 224 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */ 225 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VINF_SUCCESS\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance)); 226 return VINF_SUCCESS; 227 } 228 83 229 84 230 DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir, … … 139 285 Req.spt.SenseInfoLength = (UCHAR)RT_MIN(sizeof(Req.aSense), cbSense); 140 286 Req.spt.SenseInfoOffset = RT_OFFSETOF(struct _REQ, aSense); 141 if (DeviceIoControl((HANDLE)RTFileToNative(pThis-> hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT,287 if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT, 142 288 &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL)) 143 289 { … … 171 317 172 318 memset(&geom, 0, sizeof(geom)); 173 rc = DeviceIoControl((HANDLE)RTFileToNative(pThis-> hFileDevice), IOCTL_DISK_GET_DRIVE_GEOMETRY,319 rc = DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_DISK_GET_DRIVE_GEOMETRY, 174 320 NULL, 0, &geom, sizeof(geom), &cbBytesReturned, NULL); 175 321 if (rc) { … … 194 340 IO_STATUS_BLOCK IoStatusBlock = {0}; 195 341 FILE_FS_SIZE_INFORMATION FsSize= {0}; 196 NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis-> hFileDevice), &IoStatusBlock,342 NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice), &IoStatusBlock, 197 343 &FsSize, sizeof(FsSize), FileFsSizeInformation); 198 344 int cRetries = 5; … … 200 346 { 201 347 RTThreadSleep(10); 202 rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis-> hFileDevice), &IoStatusBlock,348 rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice), &IoStatusBlock, 203 349 &FsSize, sizeof(FsSize), FileFsSizeInformation); 204 350 } … … 224 370 DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead) 225 371 { 226 return RTFileReadAt(pThis-> hFileDevice, off, pvBuf, cbRead, NULL);372 return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL); 227 373 } 228 374 … … 230 376 DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite) 231 377 { 232 return RTFileWriteAt(pThis-> hFileDevice, off, pvBuf, cbWrite, NULL);378 return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL); 233 379 } 234 380 … … 236 382 DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis) 237 383 { 238 return RTFileFlush(pThis-> hFileDevice);384 return RTFileFlush(pThis->Os.hFileDevice); 239 385 } 240 386 … … 245 391 DWORD cbReturned; 246 392 int rc; 247 if (DeviceIoControl((HANDLE)RTFileToNative(pThis-> hFileDevice), IOCTL_STORAGE_MEDIA_REMOVAL,393 if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_STORAGE_MEDIA_REMOVAL, 248 394 &PreventMediaRemoval, sizeof(PreventMediaRemoval), 249 395 NULL, 0, &cbReturned, … … 261 407 { 262 408 int rc = VINF_SUCCESS; 263 RTFILE hFileDevice = pThis-> hFileDevice;409 RTFILE hFileDevice = pThis->Os.hFileDevice; 264 410 if (hFileDevice == NIL_RTFILE) /* obsolete crap */ 265 411 rc = RTFileOpen(&hFileDevice, pThis->pszDeviceOpen, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); … … 277 423 278 424 /* clean up handle */ 279 if (hFileDevice != pThis-> hFileDevice)425 if (hFileDevice != pThis->Os.hFileDevice) 280 426 RTFileClose(hFileDevice); 281 427 } … … 287 433 288 434 435 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis) 436 { 437 pThis->Os.hFileDevice = NIL_RTFILE; 438 pThis->Os.hwndDeviceChange = NULL; 439 pThis->Os.hThrdMediaChange = NIL_RTTHREAD; 440 } 441 442 443 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly) 444 { 445 UINT uDriveType = GetDriveType(pThis->pszDevice); 446 switch (pThis->enmType) 447 { 448 case PDMMEDIATYPE_FLOPPY_360: 449 case PDMMEDIATYPE_FLOPPY_720: 450 case PDMMEDIATYPE_FLOPPY_1_20: 451 case PDMMEDIATYPE_FLOPPY_1_44: 452 case PDMMEDIATYPE_FLOPPY_2_88: 453 case PDMMEDIATYPE_FLOPPY_FAKE_15_6: 454 case PDMMEDIATYPE_FLOPPY_FAKE_63_5: 455 if (uDriveType != DRIVE_REMOVABLE) 456 { 457 AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n", 458 pThis->pszDevice, uDriveType)); 459 return VERR_INVALID_PARAMETER; 460 } 461 break; 462 case PDMMEDIATYPE_CDROM: 463 case PDMMEDIATYPE_DVD: 464 if (uDriveType != DRIVE_CDROM) 465 { 466 AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n", 467 pThis->pszDevice, uDriveType)); 468 return VERR_INVALID_PARAMETER; 469 } 470 break; 471 case PDMMEDIATYPE_HARD_DISK: 472 default: 473 AssertMsgFailed(("enmType=%d\n", pThis->enmType)); 474 return VERR_INVALID_PARAMETER; 475 } 476 477 int iBit = RT_C_TO_UPPER(pThis->pszDevice[0]) - 'A'; 478 if ( iBit > 'Z' - 'A' 479 || pThis->pszDevice[1] != ':' 480 || pThis->pszDevice[2]) 481 { 482 AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice)); 483 return VERR_INVALID_PARAMETER; 484 } 485 pThis->Os.fUnitMask = 1 << iBit; 486 RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice); 487 if (!pThis->pszDeviceOpen) 488 return VERR_NO_MEMORY; 489 490 uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE; 491 int rc = RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDeviceOpen, fFlags); 492 493 if (RT_SUCCESS(rc)) 494 { 495 /* 496 * Start the thread which will wait for the media change events. 497 */ 498 rc = RTThreadCreate(&pThis->Os.hThrdMediaChange, drvHostBaseMediaThreadWin, pThis, 0, 499 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA"); 500 if (RT_FAILURE(rc)) 501 { 502 AssertMsgFailed(("Failed to create poller thread. rc=%Rrc\n", rc)); 503 return rc; 504 } 505 506 /* 507 * Wait for the thread to start up (!w32:) and do one detection loop. 508 */ 509 rc = RTThreadUserWait(pThis->Os.hThrdMediaChange, 10000); 510 AssertRC(rc); 511 512 if (!pThis->Os.hwndDeviceChange) 513 return VERR_GENERAL_FAILURE; 514 515 DRVHostBaseMediaPresent(pThis); 516 } 517 518 return rc; 519 } 520 521 522 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis) 523 { 524 RT_NOREF(pThis); 525 return VINF_SUCCESS; 526 } 527 528 289 529 DECLHIDDEN(int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis) 290 530 { 291 if (pThis-> hwndDeviceChange)292 PostMessage(pThis-> hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */531 if (pThis->Os.hwndDeviceChange) 532 PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */ 293 533 294 534 return VINF_SUCCESS; … … 296 536 297 537 538 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis) 539 { 540 /* For Windows we alwys use an internal approach. */ 541 RT_NOREF(pThis); 542 return false; 543 } 544 545 298 546 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis) 299 547 { 300 if (pThis->hwndDeviceChange) 301 { 302 if (SetWindowLongPtr(pThis->hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis) 303 PostMessage(pThis->hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */ 304 pThis->hwndDeviceChange = NULL; 305 } 306 307 if (pThis->hFileDevice != NIL_RTFILE) 308 { 309 int rc = RTFileClose(pThis->hFileDevice); 548 /* 549 * Unlock the drive if we've locked it or we're in passthru mode. 550 */ 551 if ( pThis->fLocked 552 && pThis->Os.hFileDevice != NIL_RTFILE 553 && pThis->pfnDoLock) 554 { 555 int rc = pThis->pfnDoLock(pThis, false); 556 if (RT_SUCCESS(rc)) 557 pThis->fLocked = false; 558 } 559 560 if (pThis->Os.hwndDeviceChange) 561 { 562 if (SetWindowLongPtr(pThis->Os.hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis) 563 PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */ 564 pThis->Os.hwndDeviceChange = NULL; 565 } 566 567 if (pThis->Os.hFileDevice != NIL_RTFILE) 568 { 569 int rc = RTFileClose(pThis->Os.hFileDevice); 310 570 AssertRC(rc); 311 pThis-> hFileDevice = NIL_RTFILE;312 } 313 } 314 571 pThis->Os.hFileDevice = NIL_RTFILE; 572 } 573 } 574 -
trunk/src/VBox/Devices/Storage/DrvHostBase.cpp
r64278 r64316 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_DRV_HOST_BASE 23 #ifdef RT_OS_DARWIN24 # include <mach/mach.h>25 # include <Carbon/Carbon.h>26 # include <IOKit/IOKitLib.h>27 # include <IOKit/storage/IOStorageDeviceCharacteristics.h>28 # include <IOKit/scsi/SCSITaskLib.h>29 # include <IOKit/scsi/SCSICommandOperationCodes.h>30 # include <IOKit/IOBSD.h>31 # include <DiskArbitration/DiskArbitration.h>32 # include <mach/mach_error.h>33 # include <VBox/scsi.h>34 35 #elif defined(RT_OS_L4)36 /* Nothing special requires... yeah, right. */37 38 #elif defined(RT_OS_LINUX)39 # include <sys/ioctl.h>40 # include <sys/fcntl.h>41 # include <errno.h>42 43 #elif defined(RT_OS_SOLARIS)44 # include <fcntl.h>45 # include <errno.h>46 # include <stropts.h>47 # include <malloc.h>48 # include <sys/dkio.h>49 extern "C" char *getfullblkname(char *);50 51 #elif defined(RT_OS_WINDOWS)52 # define WIN32_NO_STATUS53 # include <iprt/win/windows.h>54 # include <dbt.h>55 # undef WIN32_NO_STATUS56 # include <ntstatus.h>57 58 /* from ntdef.h */59 typedef LONG NTSTATUS;60 61 /* from ntddk.h */62 typedef struct _IO_STATUS_BLOCK {63 union {64 NTSTATUS Status;65 PVOID Pointer;66 };67 ULONG_PTR Information;68 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;69 70 71 /* from ntinternals.com */72 typedef enum _FS_INFORMATION_CLASS {73 FileFsVolumeInformation=1,74 FileFsLabelInformation,75 FileFsSizeInformation,76 FileFsDeviceInformation,77 FileFsAttributeInformation,78 FileFsControlInformation,79 FileFsFullSizeInformation,80 FileFsObjectIdInformation,81 FileFsMaximumInformation82 } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;83 84 typedef struct _FILE_FS_SIZE_INFORMATION {85 LARGE_INTEGER TotalAllocationUnits;86 LARGE_INTEGER AvailableAllocationUnits;87 ULONG SectorsPerAllocationUnit;88 ULONG BytesPerSector;89 } FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;90 91 extern "C"92 NTSTATUS __stdcall NtQueryVolumeInformationFile(93 /*IN*/ HANDLE FileHandle,94 /*OUT*/ PIO_STATUS_BLOCK IoStatusBlock,95 /*OUT*/ PVOID FileSystemInformation,96 /*IN*/ ULONG Length,97 /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );98 99 #elif defined(RT_OS_FREEBSD)100 # include <sys/cdefs.h>101 # include <sys/param.h>102 # include <errno.h>103 # include <stdio.h>104 # include <cam/cam.h>105 # include <cam/cam_ccb.h>106 # include <cam/scsi/scsi_message.h>107 # include <cam/scsi/scsi_pass.h>108 # include <VBox/scsi.h>109 # include <iprt/log.h>110 #else111 # error "Unsupported Platform."112 #endif113 23 114 24 #include <VBox/vmm/pdmdrv.h> … … 136 46 static DECLCALLBACK(int) drvHostBaseRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead) 137 47 { 138 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);48 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 139 49 LogFlow(("%s-%d: drvHostBaseRead: off=%#llx pvBuf=%p cbRead=%#x (%s)\n", 140 50 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbRead, pThis->pszDevice)); … … 174 84 static DECLCALLBACK(int) drvHostBaseWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite) 175 85 { 176 RT_NOREF(off, pvBuf, cbWrite); 177 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface); 86 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 178 87 LogFlow(("%s-%d: drvHostBaseWrite: off=%#llx pvBuf=%p cbWrite=%#x (%s)\n", 179 88 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, off, pvBuf, cbWrite, pThis->pszDevice)); … … 216 125 { 217 126 int rc; 218 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);127 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 219 128 LogFlow(("%s-%d: drvHostBaseFlush: (%s)\n", 220 129 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice)); … … 235 144 static DECLCALLBACK(bool) drvHostBaseIsReadOnly(PPDMIMEDIA pInterface) 236 145 { 237 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);146 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 238 147 return pThis->fReadOnly; 239 148 } … … 251 160 static DECLCALLBACK(uint64_t) drvHostBaseGetSize(PPDMIMEDIA pInterface) 252 161 { 253 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);162 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 254 163 RTCritSectEnter(&pThis->CritSect); 255 164 … … 267 176 static DECLCALLBACK(PDMMEDIATYPE) drvHostBaseGetType(PPDMIMEDIA pInterface) 268 177 { 269 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);178 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 270 179 LogFlow(("%s-%d: drvHostBaseGetType: returns %d\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->enmType)); 271 180 return pThis->enmType; … … 276 185 static DECLCALLBACK(int) drvHostBaseGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid) 277 186 { 278 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);187 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 279 188 280 189 *pUuid = pThis->Uuid; … … 288 197 static DECLCALLBACK(int) drvHostBaseGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry) 289 198 { 290 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);199 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 291 200 RTCritSectEnter(&pThis->CritSect); 292 201 … … 316 225 static DECLCALLBACK(int) drvHostBaseSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry) 317 226 { 318 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);227 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 319 228 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n", 320 229 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors)); … … 340 249 static DECLCALLBACK(int) drvHostBaseGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry) 341 250 { 342 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);251 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 343 252 RTCritSectEnter(&pThis->CritSect); 344 253 … … 368 277 static DECLCALLBACK(int) drvHostBaseSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry) 369 278 { 370 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);279 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 371 280 LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n", 372 281 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors)); … … 392 301 static DECLCALLBACK(bool) drvHostBaseIsVisible(PPDMIMEDIA pInterface) 393 302 { 394 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface);303 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 395 304 return pThis->fBiosVisible; 396 305 } … … 405 314 RT_NOREF(fEject); 406 315 /* While we're not mountable (see drvHostBaseMount), we're unmountable. */ 407 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);316 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount); 408 317 RTCritSectEnter(&pThis->CritSect); 409 318 … … 423 332 } 424 333 334 if (fEject) 335 { 336 /* 337 * Eject the disc. 338 */ 339 rc = drvHostBaseEjectOs(pThis); 340 } 341 425 342 /* 426 343 * Media is no longer present. … … 430 347 else 431 348 { 432 Log(("drvHost iBaseUnmount: Locked\n"));349 Log(("drvHostBaseUnmount: Locked\n")); 433 350 rc = VERR_PDM_MEDIA_LOCKED; 434 351 } … … 443 360 static DECLCALLBACK(bool) drvHostBaseIsMounted(PPDMIMOUNT pInterface) 444 361 { 445 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);362 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount); 446 363 RTCritSectEnter(&pThis->CritSect); 447 364 … … 456 373 static DECLCALLBACK(int) drvHostBaseLock(PPDMIMOUNT pInterface) 457 374 { 458 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);375 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount); 459 376 RTCritSectEnter(&pThis->CritSect); 460 377 … … 479 396 static DECLCALLBACK(int) drvHostBaseUnlock(PPDMIMOUNT pInterface) 480 397 { 481 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);398 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount); 482 399 RTCritSectEnter(&pThis->CritSect); 483 400 … … 502 419 static DECLCALLBACK(bool) drvHostBaseIsLocked(PPDMIMOUNT pInterface) 503 420 { 504 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);421 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMount); 505 422 RTCritSectEnter(&pThis->CritSect); 506 423 … … 530 447 531 448 /* -=-=-=-=- poller thread -=-=-=-=- */ 532 533 #ifdef RT_OS_DARWIN534 /** The runloop input source name for the disk arbitration events. */535 # define MY_RUN_LOOP_MODE CFSTR("drvHostBaseDA") /** @todo r=bird: Check if this will cause trouble in the same way that the one in the USB code did. */536 537 /**538 * Gets the BSD Name (/dev/disc[0-9]+) for the service.539 *540 * This is done by recursing down the I/O registry until we hit upon an entry541 * with a BSD Name. Usually we find it two levels down. (Further down under542 * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't543 * seem to have to go this far fortunately.)544 *545 * @return VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise.546 * @param Entry The current I/O registry entry reference.547 * @param pszName Where to store the name. 128 bytes.548 * @param cRecursions Number of recursions. This is used as an precaution549 * just to limit the depth and avoid blowing the stack550 * should we hit a bug or something.551 */552 static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions)553 {554 int rc = VERR_FILE_NOT_FOUND;555 io_iterator_t Children = 0;556 kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children);557 if (krc == KERN_SUCCESS)558 {559 io_object_t Child;560 while ( rc == VERR_FILE_NOT_FOUND561 && (Child = IOIteratorNext(Children)) != 0)562 {563 CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);564 if (BSDNameStrRef)565 {566 if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8))567 rc = VINF_SUCCESS;568 else569 AssertFailed();570 CFRelease(BSDNameStrRef);571 }572 if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10)573 rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1);574 IOObjectRelease(Child);575 }576 IOObjectRelease(Children);577 }578 return rc;579 }580 581 582 /**583 * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed.584 *585 * @param DiskRef The disk that was attempted claimed / unmounted.586 * @param DissenterRef NULL on success, contains details on failure.587 * @param pvContext Pointer to the return code variable.588 */589 static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext)590 {591 RT_NOREF(DiskRef);592 int *prc = (int *)pvContext;593 if (!DissenterRef)594 *prc = 0;595 else596 *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1;597 CFRunLoopStop(CFRunLoopGetCurrent());598 }599 600 601 /**602 * Obtain exclusive access to the DVD device, umount it if necessary.603 *604 * @return VBox status code.605 * @param pThis The driver instance.606 * @param DVDService The DVD service object.607 */608 static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService)609 {610 PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns);611 612 for (unsigned iTry = 0;; iTry++)613 {614 IOReturn irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI);615 if (irc == kIOReturnSuccess)616 {617 /*618 * This is a bit weird, but if we unmounted the DVD drive we also need to619 * unlock it afterwards or the guest won't be able to eject it later on.620 */621 if (pThis->pDADisk)622 {623 uint8_t abCmd[16] =624 {625 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0,626 0,0,0,0,0,0,0,0,0,0627 };628 drvHostBaseScsiCmdOs(pThis, abCmd, 6, PDMMEDIATXDIR_NONE, NULL, NULL, NULL, 0, 0);629 }630 return VINF_SUCCESS;631 }632 if (irc == kIOReturnExclusiveAccess)633 return VERR_SHARING_VIOLATION; /* already used exclusivly. */634 if (irc != kIOReturnBusy)635 return VERR_GENERAL_FAILURE; /* not mounted */636 637 /*638 * Attempt to the unmount all volumes of the device.639 * It seems we can can do this all in one go without having to enumerate the640 * volumes (sessions) and deal with them one by one. This is very fortuitous641 * as the disk arbitration API is a bit cumbersome to deal with.642 */643 if (iTry > 2)644 return VERR_DRIVE_LOCKED;645 char szName[128];646 int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0);647 if (RT_SUCCESS(rc))648 {649 pThis->pDASession = DASessionCreate(kCFAllocatorDefault);650 if (pThis->pDASession)651 {652 DASessionScheduleWithRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);653 pThis->pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->pDASession, szName);654 if (pThis->pDADisk)655 {656 /*657 * Try claim the device.658 */659 Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));660 int rcDA = -2;661 DADiskClaim(pThis->pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA);662 SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);663 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));664 if ( rc32 == kCFRunLoopRunStopped665 && !rcDA)666 {667 /*668 * Try unmount the device.669 */670 Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));671 rcDA = -2;672 DADiskUnmount(pThis->pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA);673 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);674 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));675 if ( rc32 == kCFRunLoopRunStopped676 && !rcDA)677 {678 iTry = 99;679 DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);680 Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pReg->szName, pDrvIns->iInstance));681 continue;682 }683 Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));684 685 /* failed - cleanup */686 DADiskUnclaim(pThis->pDADisk);687 }688 else689 Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc32, rcDA));690 691 CFRelease(pThis->pDADisk);692 pThis->pDADisk = NULL;693 }694 else695 Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pReg->szName, pDrvIns->iInstance, szName));696 697 DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);698 CFRelease(pThis->pDASession);699 pThis->pDASession = NULL;700 }701 else702 Log(("%s-%d: failed to create DA session!\n", pDrvIns->pReg->szName, pDrvIns->iInstance));703 }704 RTThreadSleep(10);705 }706 }707 #endif /* RT_OS_DARWIN */708 709 710 #ifndef RT_OS_SOLARIS711 /**712 * Wrapper for open / RTFileOpen / IOKit.713 *714 * @remark The Darwin code must correspond exactly to the enumeration715 * done in Main/darwin/iokit.c.716 */717 static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileDevice, bool fReadOnly)718 {719 # ifdef RT_OS_DARWIN720 RT_NOREF(fReadOnly);721 722 /* Darwin is kind of special... */723 Assert(!pFileDevice); NOREF(pFileDevice);724 Assert(!pThis->cbBlock);725 Assert(pThis->MasterPort == IO_OBJECT_NULL);726 Assert(!pThis->ppMMCDI);727 Assert(!pThis->ppScsiTaskDI);728 729 /*730 * Open the master port on the first invocation.731 */732 kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &pThis->MasterPort);733 AssertReturn(krc == KERN_SUCCESS, VERR_GENERAL_FAILURE);734 735 /*736 * Create a matching dictionary for searching for CD, DVD and BlueRay services in the IOKit.737 *738 * The idea is to find all the devices which are of class IOCDBlockStorageDevice.739 * CD devices are represented by IOCDBlockStorageDevice class itself, while DVD and BlueRay ones740 * have it as a parent class.741 */742 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching("IOCDBlockStorageDevice");743 AssertReturn(RefMatchingDict, VERR_NOT_FOUND);744 745 /*746 * do the search and get a collection of keyboards.747 */748 io_iterator_t DVDServices = IO_OBJECT_NULL;749 IOReturn irc = IOServiceGetMatchingServices(pThis->MasterPort, RefMatchingDict, &DVDServices);750 AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%d\n", irc), VERR_NOT_FOUND);751 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */752 753 /*754 * Enumerate the matching drives (services).755 * (This enumeration must be identical to the one performed in Main/src-server/darwin/iokit.cpp.)756 */757 int rc = VERR_FILE_NOT_FOUND;758 unsigned i = 0;759 io_object_t DVDService;760 while ((DVDService = IOIteratorNext(DVDServices)) != 0)761 {762 /*763 * Get the properties we use to identify the DVD drive.764 *765 * While there is a (weird 12 byte) GUID, it isn't persistent766 * across boots. So, we have to use a combination of the767 * vendor name and product name properties with an optional768 * sequence number for identification.769 */770 CFMutableDictionaryRef PropsRef = 0;771 krc = IORegistryEntryCreateCFProperties(DVDService, &PropsRef, kCFAllocatorDefault, kNilOptions);772 if (krc == KERN_SUCCESS)773 {774 /* Get the Device Characteristics dictionary. */775 CFDictionaryRef DevCharRef = (CFDictionaryRef)CFDictionaryGetValue(PropsRef, CFSTR(kIOPropertyDeviceCharacteristicsKey));776 if (DevCharRef)777 {778 /* The vendor name. */779 char szVendor[128];780 char *pszVendor = &szVendor[0];781 CFTypeRef ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyVendorNameKey));782 if ( ValueRef783 && CFGetTypeID(ValueRef) == CFStringGetTypeID()784 && CFStringGetCString((CFStringRef)ValueRef, szVendor, sizeof(szVendor), kCFStringEncodingUTF8))785 pszVendor = RTStrStrip(szVendor);786 else787 *pszVendor = '\0';788 789 /* The product name. */790 char szProduct[128];791 char *pszProduct = &szProduct[0];792 ValueRef = CFDictionaryGetValue(DevCharRef, CFSTR(kIOPropertyProductNameKey));793 if ( ValueRef794 && CFGetTypeID(ValueRef) == CFStringGetTypeID()795 && CFStringGetCString((CFStringRef)ValueRef, szProduct, sizeof(szProduct), kCFStringEncodingUTF8))796 pszProduct = RTStrStrip(szProduct);797 else798 *pszProduct = '\0';799 800 /* Construct the two names and compare thwm with the one we're searching for. */801 char szName1[256 + 32];802 char szName2[256 + 32];803 if (*pszVendor || *pszProduct)804 {805 if (*pszVendor && *pszProduct)806 {807 RTStrPrintf(szName1, sizeof(szName1), "%s %s", pszVendor, pszProduct);808 RTStrPrintf(szName2, sizeof(szName2), "%s %s (#%u)", pszVendor, pszProduct, i);809 }810 else811 {812 strcpy(szName1, *pszVendor ? pszVendor : pszProduct);813 RTStrPrintf(szName2, sizeof(szName2), "%s (#%u)", *pszVendor ? pszVendor : pszProduct, i);814 }815 }816 else817 {818 RTStrPrintf(szName1, sizeof(szName1), "(#%u)", i);819 strcpy(szName2, szName1);820 }821 822 if ( !strcmp(szName1, pThis->pszDeviceOpen)823 || !strcmp(szName2, pThis->pszDeviceOpen))824 {825 /*826 * Found it! Now, get the client interface and stuff.827 * Note that we could also query kIOSCSITaskDeviceUserClientTypeID here if the828 * MMC client plugin is missing. For now we assume this won't be necessary.829 */830 SInt32 Score = 0;831 IOCFPlugInInterface **ppPlugInInterface = NULL;832 krc = IOCreatePlugInInterfaceForService(DVDService, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID,833 &ppPlugInInterface, &Score);834 if (krc == KERN_SUCCESS)835 {836 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,837 CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID),838 (LPVOID *)&pThis->ppMMCDI);839 (*ppPlugInInterface)->Release(ppPlugInInterface);840 ppPlugInInterface = NULL;841 if (hrc == S_OK)842 {843 pThis->ppScsiTaskDI = (*pThis->ppMMCDI)->GetSCSITaskDeviceInterface(pThis->ppMMCDI);844 if (pThis->ppScsiTaskDI)845 rc = VINF_SUCCESS;846 else847 {848 LogRel(("GetSCSITaskDeviceInterface failed on '%s'\n", pThis->pszDeviceOpen));849 rc = VERR_NOT_SUPPORTED;850 (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);851 }852 }853 else854 {855 rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinCOM(krc);856 pThis->ppMMCDI = NULL;857 }858 }859 else /* Check for kIOSCSITaskDeviceUserClientTypeID? */860 rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc);861 862 /* Obtain exclusive access to the device so we can send SCSI commands. */863 if (RT_SUCCESS(rc))864 rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService);865 866 /* Cleanup on failure. */867 if (RT_FAILURE(rc))868 {869 if (pThis->ppScsiTaskDI)870 {871 (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);872 pThis->ppScsiTaskDI = NULL;873 }874 if (pThis->ppMMCDI)875 {876 (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);877 pThis->ppMMCDI = NULL;878 }879 }880 881 IOObjectRelease(DVDService);882 break;883 }884 }885 CFRelease(PropsRef);886 }887 else888 AssertMsgFailed(("krc=%#x\n", krc));889 890 IOObjectRelease(DVDService);891 i++;892 }893 894 IOObjectRelease(DVDServices);895 return rc;896 897 #elif defined(RT_OS_FREEBSD)898 RTFILE hFileDevice;899 int rc = RTFileOpen(&hFileDevice, pThis->pszDeviceOpen, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);900 if (RT_FAILURE(rc))901 return rc;902 903 /*904 * The current device handle can't passthrough SCSI commands.905 * We have to get he passthrough device path and open this.906 */907 union ccb DeviceCCB;908 memset(&DeviceCCB, 0, sizeof(DeviceCCB));909 910 DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;911 int rcBSD = ioctl(RTFileToNative(hFileDevice), CAMGETPASSTHRU, &DeviceCCB);912 if (!rcBSD)913 {914 char *pszPassthroughDevice = NULL;915 rc = RTStrAPrintf(&pszPassthroughDevice, "/dev/%s%u",916 DeviceCCB.cgdl.periph_name, DeviceCCB.cgdl.unit_number);917 if (rc >= 0)918 {919 RTFILE hPassthroughDevice;920 rc = RTFileOpen(&hPassthroughDevice, pszPassthroughDevice, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);921 RTStrFree(pszPassthroughDevice);922 if (RT_SUCCESS(rc))923 {924 /* Get needed device parameters. */925 926 /*927 * The device path, target id and lun id. Those are928 * needed for the SCSI passthrough ioctl.929 */930 memset(&DeviceCCB, 0, sizeof(DeviceCCB));931 DeviceCCB.ccb_h.func_code = XPT_GDEVLIST;932 933 rcBSD = ioctl(RTFileToNative(hPassthroughDevice), CAMGETPASSTHRU, &DeviceCCB);934 if (!rcBSD)935 {936 if (DeviceCCB.cgdl.status != CAM_GDEVLIST_ERROR)937 {938 pThis->ScsiBus = DeviceCCB.ccb_h.path_id;939 pThis->ScsiTargetID = DeviceCCB.ccb_h.target_id;940 pThis->ScsiLunID = DeviceCCB.ccb_h.target_lun;941 *pFileDevice = hPassthroughDevice;942 }943 else944 {945 /* The passthrough device wasn't found. */946 rc = VERR_NOT_FOUND;947 }948 }949 else950 rc = RTErrConvertFromErrno(errno);951 952 if (RT_FAILURE(rc))953 RTFileClose(hPassthroughDevice);954 }955 }956 else957 rc = VERR_NO_STR_MEMORY;958 }959 else960 rc = RTErrConvertFromErrno(errno);961 962 RTFileClose(hFileDevice);963 return rc;964 965 #else966 uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;967 # ifdef RT_OS_LINUX968 fFlags |= RTFILE_O_NON_BLOCK;969 # endif970 return RTFileOpen(pFileDevice, pThis->pszDeviceOpen, fFlags);971 #endif972 }973 974 #else /* RT_OS_SOLARIS */975 976 /**977 * Solaris wrapper for RTFileOpen.978 *979 * Solaris has to deal with two filehandles, a block and a raw one. Rather than messing980 * with drvHostBaseOpen's function signature & body, having a separate one is better.981 *982 * @returns VBox status code.983 */984 static int drvHostBaseOpen(PDRVHOSTBASE pThis, PRTFILE pFileBlockDevice, PRTFILE pFileRawDevice, bool fReadOnly)985 {986 unsigned fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE)987 | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK;988 int rc = RTFileOpen(pFileBlockDevice, pThis->pszDeviceOpen, fFlags);989 if (RT_SUCCESS(rc))990 {991 rc = RTFileOpen(pFileRawDevice, pThis->pszRawDeviceOpen, fFlags);992 if (RT_SUCCESS(rc))993 return rc;994 995 LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszRawDeviceOpen, rc));996 RTFileClose(*pFileBlockDevice);997 }998 else999 LogRel(("DVD: failed to open device %s rc=%Rrc\n", pThis->pszDeviceOpen, rc));1000 return rc;1001 }1002 #endif /* RT_OS_SOLARIS */1003 1004 1005 /**1006 * (Re)opens the device.1007 *1008 * This is used to open the device during construction, but it's also used to re-open1009 * the device when a media is inserted. This re-open will kill off any cached data1010 * that Linux for some peculiar reason thinks should survive a media change...1011 *1012 * @returns VBOX status code.1013 * @param pThis Instance data.1014 */1015 static int drvHostBaseReopen(PDRVHOSTBASE pThis)1016 {1017 #ifndef RT_OS_DARWIN /* Only *one* open for darwin. */1018 LogFlow(("%s-%d: drvHostBaseReopen: '%s'\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen));1019 1020 RTFILE hFileDevice;1021 #ifdef RT_OS_SOLARIS1022 if (pThis->hFileRawDevice != NIL_RTFILE)1023 {1024 RTFileClose(pThis->hFileRawDevice);1025 pThis->hFileRawDevice = NIL_RTFILE;1026 }1027 if (pThis->hFileDevice != NIL_RTFILE)1028 {1029 RTFileClose(pThis->hFileDevice);1030 pThis->hFileDevice = NIL_RTFILE;1031 }1032 RTFILE hFileRawDevice;1033 int rc = drvHostBaseOpen(pThis, &hFileDevice, &hFileRawDevice, pThis->fReadOnlyConfig);1034 #else1035 int rc = drvHostBaseOpen(pThis, &hFileDevice, pThis->fReadOnlyConfig);1036 #endif1037 if (RT_FAILURE(rc))1038 {1039 if (!pThis->fReadOnlyConfig)1040 {1041 LogFlow(("%s-%d: drvHostBaseReopen: '%s' - retry readonly (%Rrc)\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDeviceOpen, rc));1042 #ifdef RT_OS_SOLARIS1043 rc = drvHostBaseOpen(pThis, &hFileDevice, &hFileRawDevice, false);1044 #else1045 rc = drvHostBaseOpen(pThis, &hFileDevice, false);1046 #endif1047 }1048 if (RT_FAILURE(rc))1049 {1050 LogFlow(("%s-%d: failed to open device '%s', rc=%Rrc\n",1051 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, pThis->pszDevice, rc));1052 return rc;1053 }1054 pThis->fReadOnly = true;1055 }1056 else1057 pThis->fReadOnly = pThis->fReadOnlyConfig;1058 1059 #ifdef RT_OS_SOLARIS1060 if (pThis->hFileRawDevice != NIL_RTFILE)1061 RTFileClose(pThis->hFileRawDevice);1062 pThis->hFileRawDevice = hFileRawDevice;1063 #endif1064 1065 if (pThis->hFileDevice != NIL_RTFILE)1066 RTFileClose(pThis->hFileDevice);1067 pThis->hFileDevice = hFileDevice;1068 #else /* RT_OS_DARWIN */1069 RT_NOREF(pThis);1070 #endif /* RT_OS_DARWIN */1071 return VINF_SUCCESS;1072 }1073 1074 1075 /**1076 * Queries the media size.1077 *1078 * @returns VBox status code.1079 * @param pThis Pointer to the instance data.1080 * @param pcb Where to store the media size in bytes.1081 */1082 static DECLCALLBACK(int) drvHostBaseGetMediaSize(PDRVHOSTBASE pThis, uint64_t *pcb)1083 {1084 return drvHostBaseGetMediaSizeOs(pThis, pcb);1085 }1086 449 1087 450 … … 1092 455 * @param pThis The instance data. 1093 456 */ 1094 intDRVHostBaseMediaPresent(PDRVHOSTBASE pThis)457 DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis) 1095 458 { 1096 459 /* 1097 460 * Open the drive. 1098 461 */ 1099 int rc = drvHostBase Reopen(pThis);462 int rc = drvHostBaseMediaRefreshOs(pThis); 1100 463 if (RT_FAILURE(rc)) 1101 464 return rc; … … 1105 468 */ 1106 469 uint64_t cb; 1107 rc = pThis->pfnGetMediaSize(pThis, &cb);470 rc = drvHostBaseGetMediaSizeOs(pThis, &cb); 1108 471 if (RT_FAILURE(rc)) 1109 472 { … … 1130 493 * @param pThis The instance data. 1131 494 */ 1132 voidDRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis)495 DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis) 1133 496 { 1134 497 pThis->fMediaPresent = false; … … 1145 508 1146 509 1147 #ifdef RT_OS_WINDOWS 1148 1149 /** 1150 * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts. 1151 */ 1152 static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 1153 { 1154 Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg)); 1155 if (uMsg == WM_DESTROY) 1156 { 1157 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA); 1158 if (pThis) 1159 ASMAtomicXchgSize(&pThis->hwndDeviceChange, NULL); 1160 PostQuitMessage(0); 1161 } 1162 1163 if (uMsg != WM_DEVICECHANGE) 1164 return DefWindowProc(hwnd, uMsg, wParam, lParam); 1165 1166 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam; 1167 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA); 1168 Assert(pThis); 1169 if (pThis == NULL) 1170 return 0; 1171 1172 switch (wParam) 1173 { 1174 case DBT_DEVICEARRIVAL: 1175 case DBT_DEVICEREMOVECOMPLETE: 1176 // Check whether a CD or DVD was inserted into or removed from a drive. 1177 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) 1178 { 1179 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; 1180 if ( (lpdbv->dbcv_flags & DBTF_MEDIA) 1181 && (pThis->fUnitMask & lpdbv->dbcv_unitmask)) 1182 { 1183 RTCritSectEnter(&pThis->CritSect); 1184 if (wParam == DBT_DEVICEARRIVAL) 1185 { 1186 int cRetries = 10; 1187 int rc = DRVHostBaseMediaPresent(pThis); 1188 while (RT_FAILURE(rc) && cRetries-- > 0) 1189 { 1190 RTThreadSleep(50); 1191 rc = DRVHostBaseMediaPresent(pThis); 1192 } 1193 } 1194 else 1195 DRVHostBaseMediaNotPresent(pThis); 1196 RTCritSectLeave(&pThis->CritSect); 1197 } 1198 } 1199 break; 1200 } 1201 return TRUE; 1202 } 1203 1204 #endif /* RT_OS_WINDOWS */ 510 static int drvHostBaseMediaPoll(PDRVHOSTBASE pThis) 511 { 512 /* 513 * Poll for media change. 514 */ 515 bool fMediaPresent = false; 516 bool fMediaChanged = false; 517 drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent); 518 519 RTCritSectEnter(&pThis->CritSect); 520 521 int rc = VINF_SUCCESS; 522 if (pThis->fMediaPresent != fMediaPresent) 523 { 524 LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent)); 525 pThis->fMediaPresent = false; 526 if (fMediaPresent) 527 rc = DRVHostBaseMediaPresent(pThis); 528 else 529 DRVHostBaseMediaNotPresent(pThis); 530 } 531 else if (fMediaPresent) 532 { 533 /* 534 * Poll for media change. 535 */ 536 if (fMediaChanged) 537 { 538 LogFlow(("drvHostDVDMediaThread: Media changed!\n")); 539 DRVHostBaseMediaNotPresent(pThis); 540 rc = DRVHostBaseMediaPresent(pThis); 541 } 542 } 543 544 RTCritSectLeave(&pThis->CritSect); 545 return rc; 546 } 1205 547 1206 548 … … 1217 559 LogFlow(("%s-%d: drvHostBaseMediaThread: ThreadSelf=%p pvUser=%p\n", 1218 560 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser)); 1219 #ifdef RT_OS_WINDOWS1220 static WNDCLASS s_classDeviceChange = {0};1221 static ATOM s_hAtomDeviceChange = 0;1222 1223 /*1224 * Register custom window class.1225 */1226 if (s_hAtomDeviceChange == 0)1227 {1228 memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange));1229 s_classDeviceChange.lpfnWndProc = DeviceChangeWindowProc;1230 s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass";1231 s_classDeviceChange.hInstance = GetModuleHandle("VBoxDD.dll");1232 Assert(s_classDeviceChange.hInstance);1233 s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange);1234 Assert(s_hAtomDeviceChange);1235 }1236 1237 /*1238 * Create Window w/ the pThis as user data.1239 */1240 HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0);1241 AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError()));1242 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);1243 1244 /*1245 * Signal the waiting EMT thread that everything went fine.1246 */1247 ASMAtomicXchgPtr((void * volatile *)&pThis->hwndDeviceChange, hwnd);1248 RTThreadUserSignal(ThreadSelf);1249 if (!hwnd)1250 {1251 LogFlow(("%s-%d: drvHostBaseMediaThread: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));1252 return VERR_GENERAL_FAILURE;1253 }1254 LogFlow(("%s-%d: drvHostBaseMediaThread: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, hwnd));1255 1256 /*1257 * Message pump.1258 */1259 MSG Msg;1260 BOOL fRet;1261 while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE)1262 {1263 if (fRet != -1)1264 {1265 TranslateMessage(&Msg);1266 DispatchMessage(&Msg);1267 }1268 //else: handle the error and possibly exit1269 }1270 Assert(!pThis->hwndDeviceChange);1271 1272 #else /* !RT_OS_WINDOWS */1273 561 bool fFirst = true; 1274 562 int cRetries = 10; … … 1278 566 * Perform the polling (unless we've run out of 50ms retries). 1279 567 */ 1280 if ( pThis->pfnPoll 1281 && cRetries-- > 0) 1282 { 1283 1284 int rc = pThis->pfnPoll(pThis); 568 if (cRetries-- > 0) 569 { 570 571 int rc = drvHostBaseMediaPoll(pThis); 1285 572 if (RT_FAILURE(rc)) 1286 573 { … … 1313 600 cRetries = 10; 1314 601 } 1315 1316 #endif /* !RT_OS_WINDOWS */1317 602 1318 603 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */ … … 1369 654 do 1370 655 { 1371 drvHostBasePollerWakeupOs(pThis);656 RTSemEventSignal(pThis->EventPoller); 1372 657 rc = RTThreadWait(pThis->ThreadPoller, 100, NULL); 1373 658 } while (cTimes-- > 0 && rc == VERR_TIMEOUT); … … 1378 663 1379 664 /* 1380 * Unlock the drive if we've locked it or we're in passthru mode.1381 */1382 #ifdef RT_OS_DARWIN1383 if ( ( pThis->fLocked1384 || pThis->IMedia.pfnSendCmd)1385 && pThis->ppScsiTaskDI1386 #else /** @todo Check if the other guys can mix pfnDoLock with scsi passthru.1387 * (We're currently not unlocking the device after use. See todo in DevATA.cpp.) */1388 if ( pThis->fLocked1389 && pThis->hFileDevice != NIL_RTFILE1390 #endif1391 && pThis->pfnDoLock)1392 {1393 int rc = pThis->pfnDoLock(pThis, false);1394 if (RT_SUCCESS(rc))1395 pThis->fLocked = false;1396 }1397 1398 /*1399 665 * Cleanup the other resources. 1400 666 */ 1401 667 drvHostBaseDestructOs(pThis); 668 669 if (pThis->EventPoller != NULL) 670 { 671 RTSemEventDestroy(pThis->EventPoller); 672 pThis->EventPoller = NULL; 673 } 1402 674 1403 675 if (pThis->pszDevice) … … 1425 697 1426 698 /** 1427 * Initializes the instance data (init part 1). 1428 * 1429 * The driver which derives from this base driver will override function pointers after 1430 * calling this method, and complete the construction by calling DRVHostBaseInitFinish(). 699 * Initializes the instance data . 1431 700 * 1432 701 * On failure call DRVHostBaseDestruct(). … … 1434 703 * @returns VBox status code. 1435 704 * @param pDrvIns Driver instance. 1436 * @param pszCfgValid Pointer to a string of valid CFGM options.705 * @param pszCfgValid Pointer to a string of valid CFGM options. 1437 706 * @param pCfg Configuration handle. 1438 707 * @param enmType Device type. 1439 708 */ 1440 int DRVHostBaseInitData(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType) 1441 { 709 DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType) 710 { 711 int src = VINF_SUCCESS; 1442 712 PDRVHOSTBASE pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTBASE); 1443 LogFlow(("%s-%d: DRVHostBaseInit Data: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance));713 LogFlow(("%s-%d: DRVHostBaseInit: iInstance=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pDrvIns->iInstance)); 1444 714 1445 715 /* … … 1449 719 pThis->fKeepInstance = false; 1450 720 pThis->ThreadPoller = NIL_RTTHREAD; 1451 #ifdef RT_OS_DARWIN1452 pThis->MasterPort = IO_OBJECT_NULL;1453 pThis->ppMMCDI = NULL;1454 pThis->ppScsiTaskDI = NULL;1455 pThis->cbBlock = 0;1456 pThis->pDADisk = NULL;1457 pThis->pDASession = NULL;1458 #else1459 pThis->hFileDevice = NIL_RTFILE;1460 #endif1461 #ifdef RT_OS_SOLARIS1462 pThis->hFileRawDevice = NIL_RTFILE;1463 #endif1464 721 pThis->enmType = enmType; 1465 //pThis->cErrors = 0;1466 722 pThis->fAttachFailError = true; /* It's an error until we've read the config. */ 1467 1468 pThis->pfnGetMediaSize = drvHostBaseGetMediaSize;1469 723 1470 724 /* IBase. */ … … 1493 747 pThis->IMount.pfnIsLocked = drvHostBaseIsLocked; 1494 748 749 drvHostBaseInitOs(pThis); 750 1495 751 if (!CFGMR3AreValuesValid(pCfg, pszCfgValid)) 1496 752 { … … 1523 779 /* Mountable */ 1524 780 uint32_t u32; 1525 rc = CFGMR3QueryU32 (pCfg, "Interval", &u32);781 rc = CFGMR3QueryU32Def(pCfg, "Interval", &u32, 1000); 1526 782 if (RT_SUCCESS(rc)) 1527 783 pThis->cMilliesPoller = u32; 1528 else if (rc == VERR_CFGM_VALUE_NOT_FOUND) 1529 pThis->cMilliesPoller = 1000; 1530 else if (RT_FAILURE(rc)) 784 else 1531 785 { 1532 786 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Rrc.\n", rc)); … … 1534 788 } 1535 789 1536 /* ReadOnly */ 1537 rc = CFGMR3QueryBool(pCfg, "ReadOnly", &pThis->fReadOnlyConfig); 1538 if (rc == VERR_CFGM_VALUE_NOT_FOUND) 1539 pThis->fReadOnlyConfig = enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM ? true : false; 1540 else if (RT_FAILURE(rc)) 1541 { 1542 AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc)); 1543 return rc; 790 /* ReadOnly - passthrough mode requires read/write access in any case. */ 791 if ( (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) 792 && pThis->IMedia.pfnSendCmd) 793 pThis->fReadOnlyConfig = false; 794 else 795 { 796 rc = CFGMR3QueryBoolDef(pCfg, "ReadOnly", &pThis->fReadOnlyConfig, 797 enmType == PDMMEDIATYPE_DVD || enmType == PDMMEDIATYPE_CDROM 798 ? true 799 : false); 800 if (RT_FAILURE(rc)) 801 { 802 AssertMsgFailed(("Configuration error: Query \"ReadOnly\" resulted in %Rrc.\n", rc)); 803 return rc; 804 } 1544 805 } 1545 806 1546 807 /* Locked */ 1547 rc = CFGMR3QueryBool(pCfg, "Locked", &pThis->fLocked); 1548 if (rc == VERR_CFGM_VALUE_NOT_FOUND) 1549 pThis->fLocked = false; 1550 else if (RT_FAILURE(rc)) 808 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false); 809 if (RT_FAILURE(rc)) 1551 810 { 1552 811 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Rrc.\n", rc)); … … 1555 814 1556 815 /* BIOS visible */ 1557 rc = CFGMR3QueryBool(pCfg, "BIOSVisible", &pThis->fBiosVisible); 1558 if (rc == VERR_CFGM_VALUE_NOT_FOUND) 1559 pThis->fBiosVisible = true; 1560 else if (RT_FAILURE(rc)) 816 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true); 817 if (RT_FAILURE(rc)) 1561 818 { 1562 819 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Rrc.\n", rc)); … … 1587 844 1588 845 /* Define whether attach failure is an error (default) or not. */ 1589 bool fAttachFailError; 1590 rc = CFGMR3QueryBool(pCfg, "AttachFailError", &fAttachFailError); 1591 if (RT_FAILURE(rc)) 1592 fAttachFailError = true; 846 bool fAttachFailError = true; 847 rc = CFGMR3QueryBoolDef(pCfg, "AttachFailError", &fAttachFailError, true); 1593 848 pThis->fAttachFailError = fAttachFailError; 1594 1595 /* name to open & watch for */1596 #ifdef RT_OS_WINDOWS1597 int iBit = RT_C_TO_UPPER(pThis->pszDevice[0]) - 'A';1598 if ( iBit > 'Z' - 'A'1599 || pThis->pszDevice[1] != ':'1600 || pThis->pszDevice[2])1601 {1602 AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice));1603 return VERR_INVALID_PARAMETER;1604 }1605 pThis->fUnitMask = 1 << iBit;1606 RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice);1607 1608 #elif defined(RT_OS_SOLARIS)1609 char *pszBlockDevName = getfullblkname(pThis->pszDevice);1610 if (!pszBlockDevName)1611 return VERR_NO_MEMORY;1612 pThis->pszDeviceOpen = RTStrDup(pszBlockDevName); /* for RTStrFree() */1613 free(pszBlockDevName);1614 pThis->pszRawDeviceOpen = RTStrDup(pThis->pszDevice);1615 1616 #else1617 pThis->pszDeviceOpen = RTStrDup(pThis->pszDevice);1618 #endif1619 1620 if (!pThis->pszDeviceOpen)1621 return VERR_NO_MEMORY;1622 1623 return VINF_SUCCESS;1624 }1625 1626 1627 /**1628 * Do the 2nd part of the init after the derived driver has overridden the defaults.1629 *1630 * On failure call DRVHostBaseDestruct().1631 *1632 * @returns VBox status code.1633 * @param pThis Pointer to the instance data.1634 */1635 int DRVHostBaseInitFinish(PDRVHOSTBASE pThis)1636 {1637 int src = VINF_SUCCESS;1638 PPDMDRVINS pDrvIns = pThis->pDrvIns;1639 849 1640 850 /* log config summary */ … … 1653 863 * Register saved state. 1654 864 */ 1655 intrc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone);865 rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, drvHostBaseLoadDone); 1656 866 if (RT_FAILURE(rc)) 1657 867 return rc; 1658 868 1659 869 /* 1660 * Verify type. 1661 */ 1662 #ifdef RT_OS_WINDOWS 1663 UINT uDriveType = GetDriveType(pThis->pszDevice); 1664 switch (pThis->enmType) 1665 { 1666 case PDMMEDIATYPE_FLOPPY_360: 1667 case PDMMEDIATYPE_FLOPPY_720: 1668 case PDMMEDIATYPE_FLOPPY_1_20: 1669 case PDMMEDIATYPE_FLOPPY_1_44: 1670 case PDMMEDIATYPE_FLOPPY_2_88: 1671 case PDMMEDIATYPE_FLOPPY_FAKE_15_6: 1672 case PDMMEDIATYPE_FLOPPY_FAKE_63_5: 1673 if (uDriveType != DRIVE_REMOVABLE) 1674 { 1675 AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n", 1676 pThis->pszDevice, uDriveType)); 1677 return VERR_INVALID_PARAMETER; 1678 } 1679 break; 1680 case PDMMEDIATYPE_CDROM: 1681 case PDMMEDIATYPE_DVD: 1682 if (uDriveType != DRIVE_CDROM) 1683 { 1684 AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n", 1685 pThis->pszDevice, uDriveType)); 1686 return VERR_INVALID_PARAMETER; 1687 } 1688 break; 1689 case PDMMEDIATYPE_HARD_DISK: 1690 default: 1691 AssertMsgFailed(("enmType=%d\n", pThis->enmType)); 1692 return VERR_INVALID_PARAMETER; 1693 } 1694 #endif 870 * Initialize the critical section used for serializing the access to the media. 871 */ 872 rc = RTCritSectInit(&pThis->CritSect); 873 if (RT_FAILURE(rc)) 874 return rc; 1695 875 1696 876 /* 1697 877 * Open the device. 1698 878 */ 1699 #if defined(RT_OS_DARWIN) 1700 rc = drvHostBaseOpen(pThis, NULL, pThis->fReadOnlyConfig); 1701 #else 1702 rc = drvHostBaseReopen(pThis); 1703 #endif 879 rc = drvHostBaseOpenOs(pThis, pThis->fReadOnlyConfig); 1704 880 if (RT_FAILURE(rc)) 1705 881 { … … 1710 886 && RT_SUCCESS(RTPathReal(pszDevice, szPathReal, sizeof(szPathReal)))) 1711 887 pszDevice = szPathReal; 1712 pThis->hFileDevice = NIL_RTFILE;1713 #endif1714 #ifdef RT_OS_SOLARIS1715 pThis->hFileRawDevice = NIL_RTFILE;1716 888 #endif 1717 889 … … 1752 924 } 1753 925 } 1754 #ifdef RT_OS_WINDOWS1755 if (RT_SUCCESS(src))1756 DRVHostBaseMediaPresent(pThis);1757 #endif1758 926 1759 927 /* … … 1771 939 } 1772 940 1773 #ifndef RT_OS_WINDOWS 1774 if (RT_SUCCESS(src)) 941 if (RT_SUCCESS(src) && drvHostBaseIsMediaPollingRequiredOs(pThis)) 1775 942 { 1776 943 /* … … 1780 947 if (RT_FAILURE(rc)) 1781 948 return rc; 1782 } 1783 #endif 1784 1785 /* 1786 * Initialize the critical section used for serializing the access to the media. 1787 */ 1788 rc = RTCritSectInit(&pThis->CritSect); 1789 if (RT_FAILURE(rc)) 1790 return rc; 1791 1792 if (RT_SUCCESS(src)) 1793 { 949 1794 950 /* 1795 951 * Start the thread which will poll for the media. … … 1808 964 rc = RTThreadUserWait(pThis->ThreadPoller, 10000); 1809 965 AssertRC(rc); 1810 #ifdef RT_OS_WINDOWS 1811 if (!pThis->hwndDeviceChange) 1812 return VERR_GENERAL_FAILURE; 1813 #endif 966 } 967 968 if (RT_FAILURE(rc)) 969 { 970 if (!pThis->fAttachFailError) 971 { 972 /* Suppressing the attach failure error must not affect the normal 973 * DRVHostBaseDestruct, so reset this flag below before leaving. */ 974 pThis->fKeepInstance = true; 975 rc = VINF_SUCCESS; 976 } 977 DRVHostBaseDestruct(pDrvIns); 978 pThis->fKeepInstance = false; 1814 979 } 1815 980 1816 981 if (RT_FAILURE(src)) 1817 982 return src; 1818 return rc; 1819 } 1820 983 984 return rc; 985 } 986 -
trunk/src/VBox/Devices/Storage/DrvHostBase.h
r64278 r64316 62 62 /** Device name to open (RTStrFree). */ 63 63 char *pszDeviceOpen; 64 #ifdef RT_OS_SOLARIS65 /** Device name of raw device (RTStrFree). */66 char *pszRawDeviceOpen;67 #endif68 64 /** Uuid of the drive. */ 69 65 RTUUID Uuid; … … 85 81 * This is invalid if no drive is in the drive. */ 86 82 uint64_t volatile cbSize; 87 #if !defined(RT_OS_DARWIN)88 /** The filehandle of the device. */89 RTFILE hFileDevice;90 #endif91 #ifdef RT_OS_SOLARIS92 /** The raw filehandle of the device. */93 RTFILE hFileRawDevice;94 #endif95 83 96 84 /** Handle of the poller thread. */ 97 85 RTTHREAD ThreadPoller; 98 #ifndef RT_OS_WINDOWS99 86 /** Event semaphore the thread will wait on. */ 100 87 RTSEMEVENT EventPoller; 101 #endif102 88 /** The poller interval. */ 103 89 RTMSINTERVAL cMilliesPoller; … … 109 95 /** BIOS LCHS geometry. */ 110 96 PDMMEDIAGEOMETRY LCHSGeometry; 111 112 /** The number of errors that could go into the release log. (flood gate) */113 uint32_t cLogRelErrors;114 115 #ifdef RT_OS_DARWIN116 /** The master port. */117 mach_port_t MasterPort;118 /** The MMC-2 Device Interface. (This is only used to get the scsi task interface.) */119 MMCDeviceInterface **ppMMCDI;120 /** The SCSI Task Device Interface. */121 SCSITaskDeviceInterface **ppScsiTaskDI;122 /** The block size. Set when querying the media size. */123 uint32_t cbBlock;124 /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */125 DASessionRef pDASession;126 /** The disk arbitration disk reference. NULL if we didn't have to claim & unmount the device. */127 DADiskRef pDADisk;128 #endif129 130 #ifdef RT_OS_WINDOWS131 /** Handle to the window we use to catch the device change broadcast messages. */132 volatile HWND hwndDeviceChange;133 /** The unit mask. */134 DWORD fUnitMask;135 #endif136 137 #ifdef RT_OS_LINUX138 /** Double buffer required for ioctl with the Linux kernel as long as we use139 * remap_pfn_range() instead of vm_insert_page(). */140 uint8_t *pbDoubleBuffer;141 #endif142 143 #ifdef RT_OS_FREEBSD144 /** The block size. Set when querying the media size. */145 uint32_t cbBlock;146 /** SCSI bus number. */147 path_id_t ScsiBus;148 /** target ID of the passthrough device. */149 target_id_t ScsiTargetID;150 /** LUN of the passthrough device. */151 lun_id_t ScsiLunID;152 #endif153 97 154 98 /** … … 163 107 DECLCALLBACKMEMBER(int, pfnDoLock)(PDRVHOSTBASE pThis, bool fLock); 164 108 165 /** 166 * Queries the media size. 167 * Can also be used to perform actions on media change. 168 * 169 * This callback pointer should be set to NULL if the default action is fine for this device. 170 * 171 * @returns VBox status code. 172 * @param pThis Pointer to the instance data. 173 * @param pcb Where to store the media size in bytes. 174 */ 175 DECLCALLBACKMEMBER(int, pfnGetMediaSize)(PDRVHOSTBASE pThis, uint64_t *pcb); 176 177 /*** 178 * Performs the polling operation. 179 * 180 * @returns VBox status code. (Failure means retry.) 181 * @param pThis Pointer to the instance data. 182 */ 183 DECLCALLBACKMEMBER(int, pfnPoll)(PDRVHOSTBASE pThis); 109 union 110 { 111 #ifdef DRVHOSTBASE_OS_INT_DECLARED 112 DRVHOSTBASEOS Os; 113 #endif 114 uint8_t abPadding[64]; 115 }; 184 116 } DRVHOSTBASE; 185 117 186 118 187 int DRVHostBaseInitData(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType); 188 int DRVHostBaseInitFinish(PDRVHOSTBASE pThis); 189 int DRVHostBaseMediaPresent(PDRVHOSTBASE pThis); 190 void DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis); 119 DECLHIDDEN(int) DRVHostBaseInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, const char *pszCfgValid, PDMMEDIATYPE enmType); 120 DECLHIDDEN(int) DRVHostBaseMediaPresent(PDRVHOSTBASE pThis); 121 DECLHIDDEN(void) DRVHostBaseMediaNotPresent(PDRVHOSTBASE pThis); 191 122 DECLCALLBACK(void) DRVHostBaseDestruct(PPDMDRVINS pDrvIns); 192 123 … … 200 131 DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis); 201 132 133 DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis); 134 DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly); 135 DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis); 202 136 DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent); 203 DECLHIDDEN( int) drvHostBasePollerWakeupOs(PDRVHOSTBASE pThis);137 DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis); 204 138 DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis); 205 206 /** Makes a PDRVHOSTBASE out of a PPDMIMOUNT. */207 #define PDMIMOUNT_2_DRVHOSTBASE(pInterface) ( (PDRVHOSTBASE)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTBASE, IMount)) )208 209 /** Makes a PDRVHOSTBASE out of a PPDMIMEDIA. */210 #define PDMIMEDIA_2_DRVHOSTBASE(pInterface) ( (PDRVHOSTBASE)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTBASE, IMedia)) )211 139 212 140 RT_C_DECLS_END -
trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
r64278 r64316 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_DRV_HOST_DVD 23 #define __STDC_LIMIT_MACROS 24 #define __STDC_CONSTANT_MACROS 23 #if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 24 # define USE_MEDIA_POLLING 25 #endif 25 26 26 #ifdef RT_OS_DARWIN 27 # include <mach/mach.h> 28 # include <Carbon/Carbon.h> 29 # include <IOKit/IOKitLib.h> 30 # include <IOKit/IOCFPlugIn.h> 31 # include <IOKit/scsi/SCSITaskLib.h> 32 # include <IOKit/scsi/SCSICommandOperationCodes.h> 33 # include <IOKit/storage/IOStorageDeviceCharacteristics.h> 34 # include <mach/mach_error.h> 35 # define USE_MEDIA_POLLING 36 37 #elif defined RT_OS_LINUX 38 # include <sys/ioctl.h> 39 # include <linux/version.h> 40 /* All the following crap is apparently not necessary anymore since Linux 41 * version 2.6.29. */ 42 # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) 43 /* This is a hack to work around conflicts between these linux kernel headers 44 * and the GLIBC tcpip headers. They have different declarations of the 4 45 * standard byte order functions. */ 46 # define _LINUX_BYTEORDER_GENERIC_H 47 /* This is another hack for not bothering with C++ unfriendly byteswap macros. */ 48 /* Those macros that are needed are defined in the header below. */ 49 # include "swab.h" 50 # endif 51 # include <linux/cdrom.h> 52 # include <sys/fcntl.h> 53 # include <errno.h> 54 # include <limits.h> 55 # include <iprt/mem.h> 56 # define USE_MEDIA_POLLING 57 58 #elif defined(RT_OS_SOLARIS) 59 # include <stropts.h> 60 # include <fcntl.h> 61 # include <errno.h> 62 # include <pwd.h> 63 # include <unistd.h> 64 # include <syslog.h> 65 # ifdef VBOX_WITH_SUID_WRAPPER 66 # include <auth_attr.h> 67 # endif 68 # include <sys/dkio.h> 69 # include <sys/sockio.h> 70 # include <sys/scsi/scsi.h> 71 # define USE_MEDIA_POLLING 72 73 #elif defined(RT_OS_WINDOWS) 74 # pragma warning(disable : 4163) 75 # define _interlockedbittestandset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset 76 # define _interlockedbittestandreset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset 77 # define _interlockedbittestandset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset64 78 # define _interlockedbittestandreset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset64 79 # include <iprt/win/windows.h> 80 # include <winioctl.h> 81 # include <ntddscsi.h> 82 # pragma warning(default : 4163) 83 # undef _interlockedbittestandset 84 # undef _interlockedbittestandreset 85 # undef _interlockedbittestandset64 86 # undef _interlockedbittestandreset64 87 # undef USE_MEDIA_POLLING 88 89 #elif defined(RT_OS_FREEBSD) 90 # include <sys/cdefs.h> 91 # include <sys/param.h> 92 # include <stdio.h> 93 # include <cam/cam.h> 94 # include <cam/cam_ccb.h> 95 # define USE_MEDIA_POLLING 96 97 #else 98 # error "Unsupported Platform." 27 #if defined(RT_OS_SOLARIS) && defined(VBOX_WITH_SUID_WRAPPER) 28 # include <auth_attr.h> 99 29 #endif 100 30 … … 117 47 * Internal Functions * 118 48 *********************************************************************************************************************************/ 119 static DECLCALLBACK(int) drvHostDvdDoLock(PDRVHOSTBASE pThis, bool fLock);120 121 #ifdef VBOX_WITH_SUID_WRAPPER122 /**123 * Checks if the current user is authorized using Solaris' role-based access control.124 * Made as a separate function with so that it need not be invoked each time we need125 * to gain root access.126 *127 * @returns VBox error code.128 */129 static int solarisCheckUserAuth()130 {131 /* Uses Solaris' role-based access control (RBAC).*/132 struct passwd *pPass = getpwuid(getuid());133 if (pPass == NULL || chkauthattr("solaris.device.cdrw", pPass->pw_name) == 0)134 return VERR_PERMISSION_DENIED;135 136 return VINF_SUCCESS;137 }138 #endif139 140 /** @interface_method_impl{PDMIMOUNT,pfnUnmount} */141 static DECLCALLBACK(int) drvHostDvdUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)142 {143 PDRVHOSTBASE pThis = PDMIMOUNT_2_DRVHOSTBASE(pInterface);144 RTCritSectEnter(&pThis->CritSect);145 146 /*147 * Validate state.148 */149 int rc = VINF_SUCCESS;150 if (!pThis->fLocked || fForce)151 {152 /* Unlock drive if necessary. */153 if (pThis->fLocked)154 drvHostBaseDoLockOs(pThis, false);155 156 if (fEject)157 {158 /*159 * Eject the disc.160 */161 rc = drvHostBaseEjectOs(pThis);162 }163 164 /*165 * Media is no longer present.166 */167 DRVHostBaseMediaNotPresent(pThis); /** @todo This isn't thread safe! */168 }169 else170 {171 Log(("drvHostDvdUnmount: Locked\n"));172 rc = VERR_PDM_MEDIA_LOCKED;173 }174 175 RTCritSectLeave(&pThis->CritSect);176 LogFlow(("drvHostDvdUnmount: returns %Rrc\n", rc));177 return rc;178 }179 49 180 50 … … 195 65 196 66 197 #ifdef USE_MEDIA_POLLING198 /**199 * Do media change polling.200 */201 static DECLCALLBACK(int) drvHostDvdPoll(PDRVHOSTBASE pThis)202 {203 /*204 * Poll for media change.205 */206 bool fMediaPresent = false;207 bool fMediaChanged = false;208 drvHostBaseQueryMediaStatusOs(pThis, &fMediaChanged, &fMediaPresent);209 210 RTCritSectEnter(&pThis->CritSect);211 212 int rc = VINF_SUCCESS;213 if (pThis->fMediaPresent != fMediaPresent)214 {215 LogFlow(("drvHostDvdPoll: %d -> %d\n", pThis->fMediaPresent, fMediaPresent));216 pThis->fMediaPresent = false;217 if (fMediaPresent)218 rc = DRVHostBaseMediaPresent(pThis);219 else220 DRVHostBaseMediaNotPresent(pThis);221 }222 else if (fMediaPresent)223 {224 /*225 * Poll for media change.226 */227 if (fMediaChanged)228 {229 LogFlow(("drvHostDVDMediaThread: Media changed!\n"));230 DRVHostBaseMediaNotPresent(pThis);231 rc = DRVHostBaseMediaPresent(pThis);232 }233 }234 235 RTCritSectLeave(&pThis->CritSect);236 return rc;237 }238 #endif /* USE_MEDIA_POLLING */239 240 241 67 /** @interface_method_impl{PDMIMEDIA,pfnSendCmd} */ 242 68 static DECLCALLBACK(int) drvHostDvdSendCmd(PPDMIMEDIA pInterface, const uint8_t *pbCmd, … … 244 70 uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies) 245 71 { 246 RT_NOREF(cbSense); 247 PDRVHOSTBASE pThis = PDMIMEDIA_2_DRVHOSTBASE(pInterface); 72 PDRVHOSTBASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE, IMedia); 248 73 int rc; 249 74 LogFlow(("%s: cmd[0]=%#04x txdir=%d pcbBuf=%d timeout=%d\n", __FUNCTION__, pbCmd[0], enmTxDir, *pcbBuf, cTimeoutMillies)); … … 276 101 277 102 278 /** @copydoc FNPDMDRVDESTRUCT */279 static DECLCALLBACK(void) drvHostDvdDestruct(PPDMDRVINS pDrvIns)280 {281 return DRVHostBaseDestruct(pDrvIns);282 }283 284 285 103 /** 286 104 * Construct a host dvd drive driver instance. … … 294 112 LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance)); 295 113 114 bool fPassthrough; 115 int rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough); 116 if (RT_SUCCESS(rc) && fPassthrough) 117 { 118 pThis->IMedia.pfnSendCmd = drvHostDvdSendCmd; 119 /* Passthrough requires opening the device in R/W mode. */ 120 pThis->fReadOnlyConfig = false; 121 } 122 123 pThis->pfnDoLock = drvHostDvdDoLock; 124 296 125 /* 297 126 * Init instance data. 298 127 */ 299 int rc = DRVHostBaseInitData(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0", 300 PDMMEDIATYPE_DVD); 301 if (RT_SUCCESS(rc)) 302 { 303 /* 304 * Override stuff. 305 */ 306 #ifdef RT_OS_LINUX 307 pThis->pbDoubleBuffer = (uint8_t *)RTMemAlloc(SCSI_MAX_BUFFER_SIZE); 308 if (!pThis->pbDoubleBuffer) 309 return VERR_NO_MEMORY; 310 #endif 311 312 bool fPassthrough; 313 rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough); 314 if (RT_SUCCESS(rc) && fPassthrough) 315 { 316 pThis->IMedia.pfnSendCmd = drvHostDvdSendCmd; 317 /* Passthrough requires opening the device in R/W mode. */ 318 pThis->fReadOnlyConfig = false; 319 #ifdef VBOX_WITH_SUID_WRAPPER /* Solaris setuid for Passthrough mode. */ 320 rc = solarisCheckUserAuth(); 321 if (RT_FAILURE(rc)) 322 { 323 Log(("DVD: solarisCheckUserAuth failed. Permission denied!\n")); 324 return rc; 325 } 326 #endif /* VBOX_WITH_SUID_WRAPPER */ 327 } 328 329 pThis->IMount.pfnUnmount = drvHostDvdUnmount; 330 pThis->pfnDoLock = drvHostDvdDoLock; 331 #ifdef USE_MEDIA_POLLING 332 if (!fPassthrough) 333 pThis->pfnPoll = drvHostDvdPoll; 334 else 335 pThis->pfnPoll = NULL; 336 #endif 337 338 /* 339 * 2nd init part. 340 */ 341 rc = DRVHostBaseInitFinish(pThis); 342 } 343 if (RT_FAILURE(rc)) 344 { 345 if (!pThis->fAttachFailError) 346 { 347 /* Suppressing the attach failure error must not affect the normal 348 * DRVHostBaseDestruct, so reset this flag below before leaving. */ 349 pThis->fKeepInstance = true; 350 rc = VINF_SUCCESS; 351 } 352 DRVHostBaseDestruct(pDrvIns); 353 pThis->fKeepInstance = false; 354 } 355 128 rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0", 129 PDMMEDIATYPE_DVD); 356 130 LogFlow(("drvHostDvdConstruct: returns %Rrc\n", rc)); 357 131 return rc; … … 385 159 drvHostDvdConstruct, 386 160 /* pfnDestruct */ 387 drvHostDvdDestruct,161 DRVHostBaseDestruct, 388 162 /* pfnRelocate */ 389 163 NULL, -
trunk/src/VBox/Devices/Storage/DrvHostFloppy.cpp
r64278 r64316 23 23 *********************************************************************************************************************************/ 24 24 #define LOG_GROUP LOG_GROUP_DRV_HOST_FLOPPY 25 #ifdef RT_OS_LINUX26 # include <sys/ioctl.h>27 # include <linux/fd.h>28 # include <sys/fcntl.h>29 # include <errno.h>30 # elif defined(RT_OS_WINDOWS)31 # include <iprt/win/windows.h>32 # include <dbt.h>33 #endif34 25 35 26 #include <VBox/vmm/pdmdrv.h> … … 48 39 49 40 50 /**51 * Floppy driver instance data.52 */53 typedef struct DRVHOSTFLOPPY54 {55 DRVHOSTBASE Base;56 /** Previous poll status. */57 bool fPrevDiskIn;58 59 } DRVHOSTFLOPPY, *PDRVHOSTFLOPPY;60 61 62 #ifdef RT_OS_LINUX63 /**64 * This thread will periodically poll the Floppy for media presence.65 *66 * @returns Ignored.67 * @param ThreadSelf Handle of this thread. Ignored.68 * @param pvUser Pointer to the driver instance structure.69 */70 static DECLCALLBACK(int) drvHostFloppyPoll(PDRVHOSTBASE pThis)71 {72 PDRVHOSTFLOPPY pThisFloppy = (PDRVHOSTFLOPPY)pThis;73 floppy_drive_struct DrvStat;74 int rc = ioctl(RTFileToNative(pThis->hFileDevice), FDPOLLDRVSTAT, &DrvStat);75 if (rc)76 return RTErrConvertFromErrno(errno);77 78 RTCritSectEnter(&pThis->CritSect);79 bool fDiskIn = !(DrvStat.flags & (FD_VERIFY | FD_DISK_NEWCHANGE));80 if ( fDiskIn81 && !pThisFloppy->fPrevDiskIn)82 {83 if (pThis->fMediaPresent)84 DRVHostBaseMediaNotPresent(pThis);85 rc = DRVHostBaseMediaPresent(pThis);86 if (RT_FAILURE(rc))87 {88 pThisFloppy->fPrevDiskIn = fDiskIn;89 RTCritSectLeave(&pThis->CritSect);90 return rc;91 }92 }93 94 if ( !fDiskIn95 && pThisFloppy->fPrevDiskIn96 && pThis->fMediaPresent)97 DRVHostBaseMediaNotPresent(pThis);98 pThisFloppy->fPrevDiskIn = fDiskIn;99 100 RTCritSectLeave(&pThis->CritSect);101 return VINF_SUCCESS;102 }103 #endif /* RT_OS_LINUX */104 105 41 106 42 /** … … 110 46 { 111 47 RT_NOREF(fFlags); 112 PDRVHOSTFLOPPY pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTFLOPPY);113 48 LogFlow(("drvHostFloppyConstruct: iInstance=%d\n", pDrvIns->iInstance)); 114 49 … … 116 51 * Init instance data. 117 52 */ 118 int rc = DRVHostBaseInitData(pDrvIns, pCfg, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0", 119 PDMMEDIATYPE_FLOPPY_1_44); 120 if (RT_SUCCESS(rc)) 121 { 122 /* 123 * Override stuff. 124 */ 125 #ifdef RT_OS_LINUX 126 pThis->Base.pfnPoll = drvHostFloppyPoll; 127 #endif 128 129 /* 130 * 2nd init part. 131 */ 132 rc = DRVHostBaseInitFinish(&pThis->Base); 133 } 134 135 if (RT_FAILURE(rc)) 136 { 137 if (!pThis->Base.fAttachFailError) 138 { 139 /* Suppressing the attach failure error must not affect the normal 140 * DRVHostBaseDestruct, so reset this flag below before leaving. */ 141 pThis->Base.fKeepInstance = true; 142 rc = VINF_SUCCESS; 143 } 144 DRVHostBaseDestruct(pDrvIns); 145 pThis->Base.fKeepInstance = false; 146 } 147 53 int rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0ReadOnly\0Interval\0Locked\0BIOSVisible\0", 54 PDMMEDIATYPE_FLOPPY_1_44); 148 55 LogFlow(("drvHostFloppyConstruct: returns %Rrc\n", rc)); 149 56 return rc; … … 173 80 ~0U, 174 81 /* cbInstance */ 175 sizeof(DRVHOST FLOPPY),82 sizeof(DRVHOSTBASE), 176 83 /* pfnConstruct */ 177 84 drvHostFloppyConstruct,
Note:
See TracChangeset
for help on using the changeset viewer.