Borrow the eject code for OSX from xine-lib-1.2-macos branch, as contributed
by Matt Messier. This allows to eject disks on Mac OS X without having to call an external utility. Incidentally this fixes libcdio eject function on Mac OS X 10.4 and later, as hditool was moved from /usr/sbin to /usr/bin.
This commit is contained in:
18
configure.ac
18
configure.ac
@@ -19,7 +19,7 @@ define(RELEASE_NUM, 79cvs)
|
||||
define(CDIO_VERSION_STR, 0.$1)
|
||||
|
||||
AC_PREREQ(2.52)
|
||||
AC_REVISION([$Id: configure.ac,v 1.210 2007/05/16 10:00:50 rocky Exp $])dnl
|
||||
AC_REVISION([$Id: configure.ac,v 1.211 2007/08/09 02:19:40 flameeyes Exp $])dnl
|
||||
AC_INIT(libcdio, CDIO_VERSION_STR(RELEASE_NUM))
|
||||
AC_CONFIG_SRCDIR(src/cd-info.c)
|
||||
|
||||
@@ -298,7 +298,7 @@ dnl AM_PROG_LIBTOOL tests whether we have GNU ld
|
||||
dnl this must come before checking --with-versioned-libs
|
||||
dnl which requires GNU ld.
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
|
||||
dnl system
|
||||
|
||||
# FIXME:
|
||||
@@ -380,6 +380,20 @@ case $host_os in
|
||||
AC_DEFINE([HAVE_DARWIN_CDROM], [1],
|
||||
[Define 1 if you have Darwin OS X-type CD-ROM support])
|
||||
DARWIN_PKG_LIB_HACK="-Wl,-framework,CoreFoundation -Wl,-framework,IOKit"
|
||||
|
||||
dnl Prior to Mac OS X 10.4 (Tiger), DiskArbitration was a private framework.
|
||||
dnl It's now public, and it's needed to do cd/dvd unmount/eject.
|
||||
AC_MSG_CHECKING([for DiskArbitration framework])
|
||||
ac_save_LIBS="$LIBS" LIBS="$LIBS -framework CoreFoundation -framework DiskArbitration"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <DiskArbitration/DiskArbitration.h>]], [[]])],
|
||||
[have_diskarbitration_framework=yes], [have_diskarbitration_framework=no])
|
||||
LIBS="$ac_save_LIBS"
|
||||
AC_MSG_RESULT([$have_diskarbitration_framework])
|
||||
if test x"$have_diskarbitration_framework" = x"yes"; then
|
||||
AC_DEFINE([HAVE_DISKARBITRATION], 1, [Define to 1 if you have the Apple DiskArbitration framework])
|
||||
DARWIN_PKG_LIB_HACK="$DARWIN_PKG_LIB_HACK -Wl,-framework,DiskArbitration"
|
||||
fi
|
||||
|
||||
AC_SUBST(DARWIN_PKG_LIB_HACK)
|
||||
LIBCDIO_LIBS="$LIBCDIO_LIBS $DARWIN_PKG_LIB_HACK"
|
||||
cd_drivers="${cd_drivers}, Darwin"
|
||||
|
||||
124
lib/driver/osx.c
124
lib/driver/osx.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $
|
||||
$Id: osx.c,v 1.10 2007/08/09 02:19:40 flameeyes Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006 Rocky Bernstein
|
||||
<rockyb@users.sourceforge.net>
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: osx.c,v 1.10 2007/08/09 02:19:40 flameeyes Exp $";
|
||||
|
||||
#include <cdio/logging.h>
|
||||
#include <cdio/sector.h>
|
||||
@@ -87,6 +87,10 @@ static const char _rcsid[] = "$Id: osx.c,v 1.9 2006/03/26 02:34:41 rocky Exp $";
|
||||
#include <IOKit/storage/IODVDMediaBSDClient.h>
|
||||
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
||||
|
||||
#ifdef HAVE_DISKARBITRATION
|
||||
#include <DiskArbitration/DiskArbitration.h>
|
||||
#endif
|
||||
|
||||
/* FIXME */
|
||||
#define MAX_BIG_BUFF_SIZE 65535
|
||||
|
||||
@@ -1316,13 +1320,17 @@ get_track_lba_osx(void *p_user_data, track_t i_track)
|
||||
/*!
|
||||
Eject media . Return DRIVER_OP_SUCCESS if successful.
|
||||
|
||||
The only way to cleanly unmount the disc under MacOS X is to use the
|
||||
'disktool' command line utility. It uses the non-public Disk
|
||||
Arbitration API, which can not be used by Cocoa or Carbon
|
||||
applications.
|
||||
The only way to cleanly unmount the disc under MacOS X (before
|
||||
Tiger) is to use the 'disktool' command line utility. It uses the
|
||||
non-public DiskArbitration API, which can not be used by Cocoa or
|
||||
Carbon applications.
|
||||
|
||||
Since Tiger (MacOS X 10.4), DiskArbitration is a public framework
|
||||
and we can use it as needed.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HAVE_DISKARBITRATION
|
||||
static driver_return_code_t
|
||||
_eject_media_osx (void *user_data) {
|
||||
|
||||
@@ -1363,6 +1371,110 @@ _eject_media_osx (void *user_data) {
|
||||
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
#else /* HAVE_DISKARBITRATION */
|
||||
typedef struct dacontext_s {
|
||||
int result;
|
||||
Boolean completed;
|
||||
DASessionRef session;
|
||||
CFRunLoopRef runloop;
|
||||
CFRunLoopSourceRef cancel;
|
||||
} dacontext_t;
|
||||
|
||||
static void cancel_runloop(void *info) { /* do nothing */ }
|
||||
|
||||
static CFRunLoopSourceContext cancelRunLoopSourceContext = {
|
||||
.perform = cancel_runloop
|
||||
};
|
||||
|
||||
static void media_eject_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
|
||||
{
|
||||
dacontext_t *dacontext = (dacontext_t *)context;
|
||||
|
||||
dacontext->result = (dissenter ? DRIVER_OP_ERROR : DRIVER_OP_SUCCESS);
|
||||
dacontext->completed = TRUE;
|
||||
CFRunLoopSourceSignal(dacontext->cancel);
|
||||
CFRunLoopWakeUp(dacontext->runloop);
|
||||
}
|
||||
|
||||
static void media_unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *context)
|
||||
{
|
||||
dacontext_t *dacontext = (dacontext_t *)context;
|
||||
|
||||
if (!dissenter) {
|
||||
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, context);
|
||||
}
|
||||
else {
|
||||
dacontext->result = DRIVER_OP_ERROR;
|
||||
dacontext->completed = TRUE;
|
||||
CFRunLoopSourceSignal(dacontext->cancel);
|
||||
CFRunLoopWakeUp(dacontext->runloop);
|
||||
}
|
||||
}
|
||||
|
||||
static driver_return_code_t
|
||||
_eject_media_osx (void *user_data) {
|
||||
|
||||
_img_private_t *p_env = user_data;
|
||||
char *psz_drive;
|
||||
|
||||
DADiskRef disk;
|
||||
dacontext_t dacontext;
|
||||
CFDictionaryRef description;
|
||||
|
||||
if( ( psz_drive = (char *)strstr( p_env->gen.source_name, "disk" ) ) == NULL ||
|
||||
strlen( psz_drive ) <= 4 )
|
||||
{
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
dacontext.result = DRIVER_OP_SUCCESS;
|
||||
dacontext.completed = FALSE;
|
||||
dacontext.runloop = CFRunLoopGetCurrent();
|
||||
dacontext.cancel = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cancelRunLoopSourceContext);
|
||||
|
||||
if (!dacontext.cancel)
|
||||
{
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
if (!(dacontext.session = DASessionCreate(kCFAllocatorDefault)))
|
||||
{
|
||||
CFRelease(dacontext.cancel);
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
if ((disk = DADiskCreateFromBSDName(kCFAllocatorDefault, dacontext.session, psz_drive)) != NULL)
|
||||
{
|
||||
if ((description = DADiskCopyDescription(disk)) != NULL)
|
||||
{
|
||||
/* Does the device need to be unmounted first? */
|
||||
DASessionScheduleWithRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
|
||||
if (CFDictionaryGetValueIfPresent(description, kDADiskDescriptionVolumePathKey, NULL))
|
||||
{
|
||||
DADiskUnmount(disk, kDADiskUnmountOptionDefault, media_unmount_callback, &dacontext);
|
||||
}
|
||||
else
|
||||
{
|
||||
DADiskEject(disk, kDADiskEjectOptionDefault, media_eject_callback, &dacontext);
|
||||
}
|
||||
CFRunLoopAddSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
|
||||
if (!dacontext.completed)
|
||||
{
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 30.0, TRUE); /* timeout after 30 seconds */
|
||||
}
|
||||
CFRunLoopRemoveSource(dacontext.runloop, dacontext.cancel, kCFRunLoopDefaultMode);
|
||||
DASessionUnscheduleFromRunLoop(dacontext.session, dacontext.runloop, kCFRunLoopDefaultMode);
|
||||
CFRelease(description);
|
||||
}
|
||||
CFRelease(disk);
|
||||
}
|
||||
|
||||
CFRunLoopSourceInvalidate(dacontext.cancel);
|
||||
CFRelease(dacontext.cancel);
|
||||
CFRelease(dacontext.session);
|
||||
return dacontext.result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
|
||||
Reference in New Issue
Block a user