4 * OSX native cd-rom driver.
6 * Copyright (c) 2005 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <IOKit/IOKitLib.h>
20 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
21 #include <IOKit/scsi-commands/SCSITaskLib.h>
22 #include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
24 #include "gdrom/gddriver.h"
26 static gboolean osx_image_is_valid( FILE *f );
27 static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f );
29 struct gdrom_image_class cdrom_device_class = { "osx", NULL,
30 osx_image_is_valid, osx_open_device };
32 typedef struct osx_cdrom_disc {
33 struct gdrom_disc disc;
36 MMCDeviceInterface **mmc;
37 SCSITaskDeviceInterface **scsi;
41 * CD-ROM drive visitor. Returns FALSE to continue iterating, TRUE if the desired CD-ROM
42 * has been found. In the latter case, the io_object is returned from find_cdrom_device
45 typedef gboolean (*find_cdrom_callback_t)( io_object_t object, char *vendor, char *product,
48 io_object_t find_cdrom_device( find_cdrom_callback_t callback, void *user_data )
50 mach_port_t master_port;
51 CFMutableDictionaryRef match;
52 io_iterator_t services;
55 if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {
56 return; // Failed to get the master port?
59 match = IOServiceMatching("IODVDServices");
60 if( IOServiceGetMatchingServices(master_port, match, &services) != kIOReturnSuccess ) {
64 while( (object = IOIteratorNext(services)) != 0 ) {
65 CFMutableDictionaryRef props = 0;
66 if( IORegistryEntryCreateCFProperties(object, &props, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS ) {
67 CFDictionaryRef dict =
68 (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOPropertyDeviceCharacteristicsKey));
70 /* The vendor name. */
71 char vendor[256] = "", product[256] = "";
72 CFTypeRef value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyVendorNameKey));
73 if( value && CFGetTypeID(value) == CFStringGetTypeID() ) {
74 CFStringGetCString( (CFStringRef)value, vendor, sizeof(vendor),
75 kCFStringEncodingUTF8 );
77 value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyProductNameKey));
78 if ( value && CFGetTypeID(value) == CFStringGetTypeID() ) {
79 CFStringGetCString( (CFStringRef)value, product, sizeof(product),
80 kCFStringEncodingUTF8 );
82 if( callback(object, vendor, product, user_data) ) {
84 IOObjectRelease(services);
91 IOObjectRelease(object);
93 IOObjectRelease(services);
96 io_object_t get_cdrom_by_service_path( const gchar *path )
98 mach_port_t master_port;
101 if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {
102 return MACH_PORT_NULL; // Failed to get the master port?
105 return IORegistryEntryFromPath( master_port, path );
108 void cdrom_osx_destroy( gdrom_disc_t disc )
110 osx_cdrom_disc_t cdrom = (osx_cdrom_disc_t)disc;
112 if( cdrom->scsi != NULL ) {
113 (*cdrom->scsi)->Release(cdrom->scsi);
116 if( cdrom->mmc != NULL ) {
117 (*cdrom->mmc)->Release(cdrom->mmc);
120 if( cdrom->entry != MACH_PORT_NULL ) {
121 IOObjectRelease( cdrom->entry );
122 cdrom->entry = MACH_PORT_NULL;
125 if( disc->name != NULL ) {
126 g_free( (gpointer)disc->name );
132 gdrom_disc_t cdrom_osx_new( io_object_t obj )
134 osx_cdrom_disc_t cdrom = g_malloc0( sizeof(struct osx_cdrom_disc) );
135 gdrom_disc_t disc = &cdrom->disc;
136 IOCFPlugInInterface **pluginInterface = NULL;
142 if( IOCreatePlugInInterfaceForService( obj, kIOMMCDeviceUserClientTypeID,
143 kIOCFPlugInInterfaceID, &pluginInterface, &score ) != KERN_SUCCESS ) {
144 ERROR( "Failed to create plugin interface" );
145 cdrom_osx_destroy(disc);
149 herr = (*pluginInterface)->QueryInterface( pluginInterface,
150 CFUUIDGetUUIDBytes( kIOMMCDeviceInterfaceID ), (LPVOID *)&cdrom->mmc );
151 (*pluginInterface)->Release(pluginInterface);
152 pluginInterface = NULL;
154 ERROR( "Failed to create MMC interface" );
155 cdrom_osx_destroy(disc);
159 cdrom->scsi = (*cdrom->mmc)->GetSCSITaskDeviceInterface( cdrom->mmc );
160 if( cdrom->scsi == NULL ) {
161 ERROR( "Failed to create SCSI interface" );
162 cdrom_osx_destroy(disc);
166 char name[sizeof(io_string_t) + 6] = "dvd://";
167 IORegistryEntryGetPath( cdrom->entry, kIOServicePlane, name+6 );
168 disc->name = g_strdup(name);
170 disc->close = cdrom_osx_destroy;
174 gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, void *ptr )
176 GList **list = (GList **)ptr;
177 char tmp1[sizeof(io_string_t) + 6] = "dvd://";
179 IORegistryEntryGetPath( object, kIOServicePlane, tmp1+6 );
180 snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product );
181 *list = g_list_append( *list, gdrom_device_new( tmp1, tmp2 ) );
185 GList *cdrom_get_native_devices(void)
188 find_cdrom_device(cdrom_enum_callback, &list);
192 gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )
195 gdrom_disc_t result = NULL;
197 if( strncasecmp( path, "IOService:", 10 ) == 0 ) {
198 obj = get_cdrom_by_service_path( path );
201 if( obj == MACH_PORT_NULL ) {
204 return cdrom_osx_new( obj );
210 static gboolean osx_image_is_valid( FILE *f )
215 static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f )
.