- Timestamp:
- Apr 13, 2007 11:50:25 PM (18 years ago)
- svn:sync-xref-src-repo-rev:
- 20393
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Makefile
r1965 r2084 122 122 VBoxDD_LIBS.darwin = \ 123 123 $(LIB_REM) 124 VBoxDD_LDFLAGS.darwin = -install_name @executable_path/VBoxDD.dylib -framework CoreAudio -framework IOKit -framework Carbon 124 VBoxDD_LDFLAGS.darwin = -install_name @executable_path/VBoxDD.dylib \ 125 -framework CoreAudio \ 126 -framework IOKit \ 127 -framework Carbon \ 128 -framework DiskArbitration 125 129 VBoxDD_LDFLAGS.linux = -Wl,--no-undefined 126 130 VBoxDD_LDFLAGS.l4 = -Wl,--no-undefined -
trunk/src/VBox/Devices/Storage/DrvHostBase.cpp
r1967 r2084 33 33 # include <IOKit/scsi-commands/SCSITaskLib.h> 34 34 # include <IOKit/scsi-commands/SCSICommandOperationCodes.h> 35 # include <IOKit/IOBSD.h> 36 # include <DiskArbitration/DiskArbitration.h> 35 37 # include <mach/mach_error.h> 36 38 # include <VBox/scsi.h> … … 558 560 559 561 /* -=-=-=-=- poller thread -=-=-=-=- */ 562 563 #ifdef __DARWIN__ 564 /** The runloop input source name for the disk arbitration events. */ 565 #define MY_RUN_LOOP_MODE CFSTR("drvHostBaseDA") 566 567 /** 568 * Gets the BSD Name (/dev/disc[0-9]+) for the service. 569 * 570 * This is done by recursing down the I/O registry until we hit upon an entry 571 * with a BSD Name. Usually we find it two levels down. (Further down under 572 * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't 573 * seem to have to go this far fortunately.) 574 * 575 * @return VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise. 576 * @param Entry The current I/O registry entry reference. 577 * @param pszName Where to store the name. 128 bytes. 578 * @param cRecursions Number of recursions. This is used as an precation 579 * just to limit the depth and avoid blowing the stack 580 * should we hit a bug or something. 581 */ 582 static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions) 583 { 584 int rc = VERR_FILE_NOT_FOUND; 585 io_iterator_t Children = 0; 586 kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children); 587 if (krc == KERN_SUCCESS) 588 { 589 io_object_t Child; 590 while ( rc == VERR_FILE_NOT_FOUND 591 && (Child = IOIteratorNext(Children)) != 0) 592 { 593 CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); 594 if (BSDNameStrRef) 595 { 596 if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8)) 597 rc = VINF_SUCCESS; 598 else 599 AssertFailed(); 600 CFRelease(BSDNameStrRef); 601 } 602 if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10) 603 rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1); 604 IOObjectRelease(Child); 605 } 606 IOObjectRelease(Children); 607 } 608 return rc; 609 } 610 611 612 /** 613 * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed. 614 * 615 * @param DiskRef The disk that was attempted claimed / unmounted. 616 * @param DissenterRef NULL on success, contains details on failure. 617 * @param pvContext Pointer to the return code variable. 618 */ 619 static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext) 620 { 621 int *prc = (int *)pvContext; 622 if (!DissenterRef) 623 *prc = 0; 624 else 625 *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1; 626 CFRunLoopStop(CFRunLoopGetCurrent()); 627 } 628 629 630 /** 631 * Obtain exclusive access to the DVD device, umount it if necessary. 632 * 633 * @return VBox status code. 634 * @param pThis The driver instance. 635 * @param DVDService The DVD service object. 636 */ 637 static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService) 638 { 639 PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns); 640 641 for (unsigned iTry = 0;; iTry++) 642 { 643 IOReturn irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI); 644 if (irc == kIOReturnSuccess) 645 { 646 /* 647 * This is a bit weird, but if we unmounted the DVD drive we also need to 648 * unlock it afterwards or the guest won't be able to eject it later on. 649 */ 650 if (pThis->pDADisk) 651 { 652 uint8_t abCmd[16] = 653 { 654 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0, 655 0,0,0,0,0,0,0,0,0,0 656 }; 657 DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0); 658 } 659 return VINF_SUCCESS; 660 } 661 if (irc == kIOReturnExclusiveAccess) 662 return VERR_SHARING_VIOLATION; /* already used exclusivly. */ 663 if (irc != kIOReturnBusy) 664 return VERR_GENERAL_FAILURE; /* not mounted */ 665 666 /* 667 * Attempt to the unmount all volumes of the device. 668 * It seems we can can do this all in one go without having to enumerate the 669 * volumes (sessions) and deal with them one by one. This is very fortuitous 670 * as the disk arbitration API is a bit cumbersome to deal with. 671 */ 672 if (iTry > 2) 673 return VERR_DRIVE_LOCKED; 674 char szName[128]; 675 int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0); 676 if (VBOX_SUCCESS(rc)) 677 { 678 pThis->pDASession = DASessionCreate(kCFAllocatorDefault); 679 if (pThis->pDASession) 680 { 681 DASessionScheduleWithRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 682 pThis->pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->pDASession, szName); 683 if (pThis->pDADisk) 684 { 685 /* 686 * Try claim the device. 687 */ 688 Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName)); 689 int rcDA = -2; 690 DADiskClaim(pThis->pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA); 691 SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE); 692 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32)); 693 if ( rc32 == kCFRunLoopRunStopped 694 && !rcDA) 695 { 696 /* 697 * Try unmount the device. 698 */ 699 Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName)); 700 rcDA = -2; 701 DADiskUnmount(pThis->pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA); 702 SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE); 703 AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32)); 704 if ( rc32 == kCFRunLoopRunStopped 705 && !rcDA) 706 { 707 iTry = 99; 708 DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 709 Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 710 continue; 711 } 712 Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc32, rcDA)); 713 714 /* failed - cleanup */ 715 DADiskUnclaim(pThis->pDADisk); 716 } 717 else 718 Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc32, rcDA)); 719 720 CFRelease(pThis->pDADisk); 721 pThis->pDADisk = NULL; 722 } 723 else 724 Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName)); 725 726 DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE); 727 CFRelease(pThis->pDASession); 728 pThis->pDASession = NULL; 729 } 730 else 731 Log(("%s-%d: failed to create DA session!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 732 } 733 RTThreadSleep(10); 734 } 735 } 736 #endif /* __DARWIN__ */ 737 560 738 561 739 /** … … 710 888 rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc); 711 889 712 /* 713 * Obtain exclusive access to the device 714 * (to prevent the host and/or user from interfering). 715 */ 890 /* Obtain exclusive access to the device so we can send SCSI commands. */ 716 891 if (VBOX_SUCCESS(rc)) 717 { 718 irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI); 719 if (irc == kIOReturnSuccess) 720 rc = VINF_SUCCESS; 721 else if (irc == kIOReturnBusy) 722 rc = VERR_DRIVE_LOCKED; /* mounted. */ 723 else if (irc == kIOReturnExclusiveAccess) 724 rc = VERR_SHARING_VIOLATION; /* already used exclusivly. */ 725 else 726 rc = VERR_GENERAL_FAILURE; 727 } 892 rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService); 728 893 729 894 /* Cleanup on failure. */ … … 1299 1464 1300 1465 /* 1301 * Unlock the drive if we've locked it. 1302 */ 1466 * Unlock the drive if we've locked it or we're in passthru mode. 1467 */ 1468 #ifdef __DARWIN__ 1469 if ( ( pThis->fLocked 1470 || pThis->IBlock.pfnSendCmd) 1471 && pThis->ppScsiTaskDI 1472 #else /** @todo Check if the other guys can mix pfnDoLock with scsi passthru. 1473 * (We're currently not unlocking the device after use. See todo in DevATA.cpp.) */ 1303 1474 if ( pThis->fLocked 1304 #ifdef __DARWIN__1305 && pThis->ppScsiTaskDI1306 #else1307 1475 && pThis->FileDevice != NIL_RTFILE 1308 1476 #endif … … 1333 1501 1334 1502 #ifdef __DARWIN__ 1503 /* 1504 * The unclaiming doesn't seem to mean much, the DVD is actaully 1505 * remounted when we release exclusive access. I'm not quite sure 1506 * if I should put the unclaim first or not... 1507 * 1508 * Anyway, that it's automatically remounted very good news for us, 1509 * because that means we don't have to mess with that ourselves. Of 1510 * course there is the unlikely scenario that we've succeeded in claiming 1511 * and umount the DVD but somehow failed to gain exclusive scsi access... 1512 */ 1335 1513 if (pThis->ppScsiTaskDI) 1336 1514 { 1515 LogFlow(("%s-%d: releasing exclusive scsi access!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 1337 1516 (*pThis->ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI); 1338 1517 (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI); 1339 1518 pThis->ppScsiTaskDI = NULL; 1340 1519 } 1520 if (pThis->pDADisk) 1521 { 1522 LogFlow(("%s-%d: unclaiming the disk!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 1523 DADiskUnclaim(pThis->pDADisk); 1524 CFRelease(pThis->pDADisk); 1525 pThis->pDADisk = NULL; 1526 } 1341 1527 if (pThis->ppMMCDI) 1342 1528 { 1529 LogFlow(("%s-%d: releasing the MMC object!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 1343 1530 (*pThis->ppMMCDI)->Release(pThis->ppMMCDI); 1344 1531 pThis->ppMMCDI = NULL; … … 1348 1535 mach_port_deallocate(mach_task_self(), pThis->MasterPort); 1349 1536 pThis->MasterPort = NULL; 1537 } 1538 if (pThis->pDASession) 1539 { 1540 LogFlow(("%s-%d: releasing the DA session!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 1541 CFRelease(pThis->pDASession); 1542 pThis->pDASession = NULL; 1350 1543 } 1351 1544 #else … … 1372 1565 if (RTCritSectIsInitialized(&pThis->CritSect)) 1373 1566 RTCritSectDelete(&pThis->CritSect); 1567 LogFlow(("%s-%d: drvHostBaseDestruct completed\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance)); 1374 1568 } 1375 1569 … … 1403 1597 pThis->ppScsiTaskDI = NULL; 1404 1598 pThis->cbBlock = 0; 1599 pThis->pDADisk = NULL; 1600 pThis->pDASession = NULL; 1405 1601 #else 1406 1602 pThis->FileDevice = NIL_RTFILE; -
trunk/src/VBox/Devices/Storage/DrvHostBase.h
r1965 r2084 113 113 /** The block size. Set when querying the media size. */ 114 114 uint32_t cbBlock; 115 /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */ 116 DASessionRef pDASession; 117 /** The disk arbritation disk reference. NULL if we didn't have to claim & unmount the device. */ 118 DADiskRef pDADisk; 115 119 #endif 116 120 -
trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
r1965 r2084 174 174 { 175 175 #ifdef __DARWIN__ 176 # if 0 /// @todo dig up the specification for this command and implement it. (not important on mac)177 176 uint8_t abCmd[16] = 178 177 { 179 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0,178 SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, fLock, 0, 180 179 0,0,0,0,0,0,0,0,0,0 181 180 }; 182 181 int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0); 183 # else184 int rc = VINF_SUCCESS;185 # endif186 182 187 183 #elif defined(__LINUX__)
Note:
See TracChangeset
for help on using the changeset viewer.