nkeynes@709 | 1 | /**
|
nkeynes@709 | 2 | * $Id$
|
nkeynes@709 | 3 | *
|
nkeynes@709 | 4 | * OSX native cd-rom driver.
|
nkeynes@709 | 5 | *
|
nkeynes@709 | 6 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@709 | 7 | *
|
nkeynes@709 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@709 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@709 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@709 | 11 | * (at your option) any later version.
|
nkeynes@709 | 12 | *
|
nkeynes@709 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@709 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@709 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@709 | 16 | * GNU General Public License for more details.
|
nkeynes@709 | 17 | */
|
nkeynes@709 | 18 |
|
nkeynes@709 | 19 | #include <IOKit/IOKitLib.h>
|
nkeynes@709 | 20 | #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
nkeynes@709 | 21 | #include <IOKit/scsi-commands/SCSITaskLib.h>
|
nkeynes@709 | 22 | #include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
|
nkeynes@709 | 23 | #include <stdio.h>
|
nkeynes@709 | 24 | #include "gdrom/gddriver.h"
|
nkeynes@709 | 25 |
|
nkeynes@709 | 26 | static gboolean osx_image_is_valid( FILE *f );
|
nkeynes@709 | 27 | static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f );
|
nkeynes@709 | 28 |
|
nkeynes@709 | 29 | struct gdrom_image_class cdrom_device_class = { "osx", NULL,
|
nkeynes@709 | 30 | osx_image_is_valid, osx_open_device };
|
nkeynes@709 | 31 |
|
nkeynes@709 | 32 | typedef struct osx_cdrom_disc {
|
nkeynes@709 | 33 | struct gdrom_disc disc;
|
nkeynes@709 | 34 |
|
nkeynes@709 | 35 | io_object_t entry;
|
nkeynes@709 | 36 | MMCDeviceInterface **mmc;
|
nkeynes@709 | 37 | SCSITaskDeviceInterface **scsi;
|
nkeynes@709 | 38 | } *osx_cdrom_disc_t;
|
nkeynes@709 | 39 |
|
nkeynes@709 | 40 | /**
|
nkeynes@709 | 41 | * CD-ROM drive visitor. Returns FALSE to continue iterating, TRUE if the desired CD-ROM
|
nkeynes@709 | 42 | * has been found. In the latter case, the io_object is returned from find_cdrom_device
|
nkeynes@709 | 43 | * (and not freed)
|
nkeynes@709 | 44 | */
|
nkeynes@709 | 45 | typedef gboolean (*find_cdrom_callback_t)( io_object_t object, char *vendor, char *product,
|
nkeynes@709 | 46 | void *user_data );
|
nkeynes@709 | 47 |
|
nkeynes@709 | 48 | io_object_t find_cdrom_device( find_cdrom_callback_t callback, void *user_data )
|
nkeynes@709 | 49 | {
|
nkeynes@709 | 50 | mach_port_t master_port;
|
nkeynes@709 | 51 | CFMutableDictionaryRef match;
|
nkeynes@709 | 52 | io_iterator_t services;
|
nkeynes@709 | 53 | io_object_t object;
|
nkeynes@709 | 54 |
|
nkeynes@709 | 55 | if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {
|
nkeynes@709 | 56 | return; // Failed to get the master port?
|
nkeynes@709 | 57 | }
|
nkeynes@709 | 58 |
|
nkeynes@709 | 59 | match = IOServiceMatching("IODVDServices");
|
nkeynes@709 | 60 | if( IOServiceGetMatchingServices(master_port, match, &services) != kIOReturnSuccess ) {
|
nkeynes@709 | 61 | return;
|
nkeynes@709 | 62 | }
|
nkeynes@709 | 63 |
|
nkeynes@709 | 64 | while( (object = IOIteratorNext(services)) != 0 ) {
|
nkeynes@709 | 65 | CFMutableDictionaryRef props = 0;
|
nkeynes@709 | 66 | if( IORegistryEntryCreateCFProperties(object, &props, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS ) {
|
nkeynes@709 | 67 | CFDictionaryRef dict =
|
nkeynes@709 | 68 | (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOPropertyDeviceCharacteristicsKey));
|
nkeynes@709 | 69 | if( dict ) {
|
nkeynes@709 | 70 | /* The vendor name. */
|
nkeynes@709 | 71 | char vendor[256] = "", product[256] = "";
|
nkeynes@709 | 72 | CFTypeRef value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyVendorNameKey));
|
nkeynes@709 | 73 | if( value && CFGetTypeID(value) == CFStringGetTypeID() ) {
|
nkeynes@709 | 74 | CFStringGetCString( (CFStringRef)value, vendor, sizeof(vendor),
|
nkeynes@709 | 75 | kCFStringEncodingUTF8 );
|
nkeynes@709 | 76 | }
|
nkeynes@709 | 77 | value = CFDictionaryGetValue(dict, CFSTR(kIOPropertyProductNameKey));
|
nkeynes@709 | 78 | if ( value && CFGetTypeID(value) == CFStringGetTypeID() ) {
|
nkeynes@709 | 79 | CFStringGetCString( (CFStringRef)value, product, sizeof(product),
|
nkeynes@709 | 80 | kCFStringEncodingUTF8 );
|
nkeynes@709 | 81 | }
|
nkeynes@709 | 82 | if( callback(object, vendor, product, user_data) ) {
|
nkeynes@709 | 83 | CFRelease(props);
|
nkeynes@709 | 84 | IOObjectRelease(services);
|
nkeynes@709 | 85 | return object;
|
nkeynes@709 | 86 | }
|
nkeynes@709 | 87 | }
|
nkeynes@709 | 88 | CFRelease(props);
|
nkeynes@709 | 89 | }
|
nkeynes@709 | 90 |
|
nkeynes@709 | 91 | IOObjectRelease(object);
|
nkeynes@709 | 92 | }
|
nkeynes@709 | 93 | IOObjectRelease(services);
|
nkeynes@709 | 94 | }
|
nkeynes@709 | 95 |
|
nkeynes@709 | 96 | io_object_t get_cdrom_by_service_path( const gchar *path )
|
nkeynes@709 | 97 | {
|
nkeynes@709 | 98 | mach_port_t master_port;
|
nkeynes@709 | 99 | io_object_t result;
|
nkeynes@709 | 100 |
|
nkeynes@709 | 101 | if( IOMasterPort( MACH_PORT_NULL, &master_port ) != KERN_SUCCESS ) {
|
nkeynes@709 | 102 | return MACH_PORT_NULL; // Failed to get the master port?
|
nkeynes@709 | 103 | }
|
nkeynes@709 | 104 |
|
nkeynes@709 | 105 | return IORegistryEntryFromPath( master_port, path );
|
nkeynes@709 | 106 | }
|
nkeynes@709 | 107 |
|
nkeynes@709 | 108 | void cdrom_osx_destroy( gdrom_disc_t disc )
|
nkeynes@709 | 109 | {
|
nkeynes@709 | 110 | osx_cdrom_disc_t cdrom = (osx_cdrom_disc_t)disc;
|
nkeynes@709 | 111 |
|
nkeynes@709 | 112 | if( cdrom->scsi != NULL ) {
|
nkeynes@709 | 113 | (*cdrom->scsi)->Release(cdrom->scsi);
|
nkeynes@709 | 114 | cdrom->scsi = NULL;
|
nkeynes@709 | 115 | }
|
nkeynes@709 | 116 | if( cdrom->mmc != NULL ) {
|
nkeynes@709 | 117 | (*cdrom->mmc)->Release(cdrom->mmc);
|
nkeynes@709 | 118 | cdrom->mmc = NULL;
|
nkeynes@709 | 119 | }
|
nkeynes@709 | 120 | if( cdrom->entry != MACH_PORT_NULL ) {
|
nkeynes@709 | 121 | IOObjectRelease( cdrom->entry );
|
nkeynes@709 | 122 | cdrom->entry = MACH_PORT_NULL;
|
nkeynes@709 | 123 | }
|
nkeynes@709 | 124 |
|
nkeynes@709 | 125 | if( disc->name != NULL ) {
|
nkeynes@709 | 126 | g_free( (gpointer)disc->name );
|
nkeynes@709 | 127 | disc->name = NULL;
|
nkeynes@709 | 128 | }
|
nkeynes@709 | 129 | g_free(disc);
|
nkeynes@709 | 130 | }
|
nkeynes@709 | 131 |
|
nkeynes@709 | 132 | gdrom_disc_t cdrom_osx_new( io_object_t obj )
|
nkeynes@709 | 133 | {
|
nkeynes@709 | 134 | osx_cdrom_disc_t cdrom = g_malloc0( sizeof(struct osx_cdrom_disc) );
|
nkeynes@709 | 135 | gdrom_disc_t disc = &cdrom->disc;
|
nkeynes@709 | 136 | IOCFPlugInInterface **pluginInterface = NULL;
|
nkeynes@709 | 137 | HRESULT herr;
|
nkeynes@709 | 138 | SInt32 score = 0;
|
nkeynes@709 | 139 |
|
nkeynes@709 | 140 | cdrom->entry = obj;
|
nkeynes@709 | 141 |
|
nkeynes@709 | 142 | if( IOCreatePlugInInterfaceForService( obj, kIOMMCDeviceUserClientTypeID,
|
nkeynes@709 | 143 | kIOCFPlugInInterfaceID, &pluginInterface, &score ) != KERN_SUCCESS ) {
|
nkeynes@709 | 144 | ERROR( "Failed to create plugin interface" );
|
nkeynes@709 | 145 | cdrom_osx_destroy(disc);
|
nkeynes@709 | 146 | return NULL;
|
nkeynes@709 | 147 | }
|
nkeynes@709 | 148 |
|
nkeynes@709 | 149 | herr = (*pluginInterface)->QueryInterface( pluginInterface,
|
nkeynes@709 | 150 | CFUUIDGetUUIDBytes( kIOMMCDeviceInterfaceID ), (LPVOID *)&cdrom->mmc );
|
nkeynes@709 | 151 | (*pluginInterface)->Release(pluginInterface);
|
nkeynes@709 | 152 | pluginInterface = NULL;
|
nkeynes@709 | 153 | if( herr != S_OK ) {
|
nkeynes@709 | 154 | ERROR( "Failed to create MMC interface" );
|
nkeynes@709 | 155 | cdrom_osx_destroy(disc);
|
nkeynes@709 | 156 | return NULL;
|
nkeynes@709 | 157 | }
|
nkeynes@709 | 158 |
|
nkeynes@709 | 159 | cdrom->scsi = (*cdrom->mmc)->GetSCSITaskDeviceInterface( cdrom->mmc );
|
nkeynes@709 | 160 | if( cdrom->scsi == NULL ) {
|
nkeynes@709 | 161 | ERROR( "Failed to create SCSI interface" );
|
nkeynes@709 | 162 | cdrom_osx_destroy(disc);
|
nkeynes@709 | 163 | return NULL;
|
nkeynes@709 | 164 | }
|
nkeynes@709 | 165 |
|
nkeynes@709 | 166 | char name[sizeof(io_string_t) + 6] = "dvd://";
|
nkeynes@709 | 167 | IORegistryEntryGetPath( cdrom->entry, kIOServicePlane, name+6 );
|
nkeynes@709 | 168 | disc->name = g_strdup(name);
|
nkeynes@709 | 169 |
|
nkeynes@709 | 170 | disc->close = cdrom_osx_destroy;
|
nkeynes@709 | 171 | return disc;
|
nkeynes@709 | 172 | }
|
nkeynes@709 | 173 |
|
nkeynes@709 | 174 | gboolean cdrom_enum_callback( io_object_t object, char *vendor, char *product, void *ptr )
|
nkeynes@709 | 175 | {
|
nkeynes@709 | 176 | GList **list = (GList **)ptr;
|
nkeynes@709 | 177 | char tmp1[sizeof(io_string_t) + 6] = "dvd://";
|
nkeynes@709 | 178 | char tmp2[512];
|
nkeynes@709 | 179 | IORegistryEntryGetPath( object, kIOServicePlane, tmp1+6 );
|
nkeynes@709 | 180 | snprintf( tmp2, sizeof(tmp2), "%s %s", vendor, product );
|
nkeynes@709 | 181 | *list = g_list_append( *list, gdrom_device_new( tmp1, tmp2 ) );
|
nkeynes@709 | 182 | return FALSE;
|
nkeynes@709 | 183 | }
|
nkeynes@709 | 184 |
|
nkeynes@709 | 185 | GList *cdrom_get_native_devices(void)
|
nkeynes@709 | 186 | {
|
nkeynes@709 | 187 | GList *list = NULL;
|
nkeynes@709 | 188 | find_cdrom_device(cdrom_enum_callback, &list);
|
nkeynes@709 | 189 | return list;
|
nkeynes@709 | 190 | }
|
nkeynes@709 | 191 |
|
nkeynes@709 | 192 | gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )
|
nkeynes@709 | 193 | {
|
nkeynes@709 | 194 | io_object_t obj;
|
nkeynes@709 | 195 | gdrom_disc_t result = NULL;
|
nkeynes@709 | 196 |
|
nkeynes@709 | 197 | if( strncasecmp( path, "IOService:", 10 ) == 0 ) {
|
nkeynes@709 | 198 | obj = get_cdrom_by_service_path( path );
|
nkeynes@709 | 199 | }
|
nkeynes@709 | 200 |
|
nkeynes@709 | 201 | if( obj == MACH_PORT_NULL ) {
|
nkeynes@709 | 202 | return NULL;
|
nkeynes@709 | 203 | } else {
|
nkeynes@709 | 204 | return cdrom_osx_new( obj );
|
nkeynes@709 | 205 | }
|
nkeynes@709 | 206 | }
|
nkeynes@709 | 207 |
|
nkeynes@709 | 208 |
|
nkeynes@709 | 209 |
|
nkeynes@709 | 210 | static gboolean osx_image_is_valid( FILE *f )
|
nkeynes@709 | 211 | {
|
nkeynes@709 | 212 | return FALSE;
|
nkeynes@709 | 213 | }
|
nkeynes@709 | 214 |
|
nkeynes@709 | 215 | static gdrom_disc_t osx_open_device( const gchar *filename, FILE *f )
|
nkeynes@709 | 216 | {
|
nkeynes@709 | 217 | return NULL;
|
nkeynes@709 | 218 | }
|